Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/allamand/preview-bot


https://github.com/allamand/preview-bot

Last synced: 21 days ago
JSON representation

Awesome Lists containing this project

README

        

## preview-bot

[![CI + CD](https://github.com/allamand/preview-bot/actions/workflows/cicd.yml/badge.svg)](https://github.com/allamand/preview-bot/actions/workflows/cicd.yml)

![](https://github.com/allamand/preview-bot/raw/master/assets/robot.png)

The preview-bot application polls for GitHub notifications like @preview-bot mentions and performs actions.

For example, whitelisted GitHub users (namely, @allamand) can mention @preview-bot with a command "preview this" in a pull request to provision a preview environment.

```
@preview-bot preview this
```

Preview-bot is built with GitHub APIs, AWS Elastic Container Service, AWS Fargate, AWS CodeBuild, Amazon ECR, and AWS CloudFormation

### How does preview-bot work?

The preview-bot container constantly polls the [GitHub Notifications APIs](https://developer.github.com/v3/activity/notifications/) for any mentions of the @preview-bot username on GitHub pull requests. If the mentioner is whitelisted, preview-bot attempts to set up a preview environment in the same AWS account. The preview-bot provisioning behavior is hard-coded to look for a `buildspec.yml` file in order to complete a CodeBuild build.

The goal of the build is to create a CloudFormation `template.yaml` file as an artifact. This can be created by updating an existing CloudFormation template, or generating from a Cloud Development Kit (CDK) application.

The CodeBuild will be given some environment variables to configure the build depending of the context:
- DOMAIN_NAME = `${owner}-${repo}-pr-${prNumber}` = prefix of the custom domain to uses for exposing your app.
- ECR_REPOSITORY = preview-bot-preview-images
- IMAGE_TAG = `${owner}-${repo}-pr-${prNumber}`

Once the build is ok, then the preview-bot will call CloudFormation to create the stack from the `template.yaml` file generated by CodeBuild.

### Set up your own bot

0. Configure the environment where to deploy the Bot

```bash
BOT_NAME=
AWS_REGION=
CLUSTER_NAME=
WHITELIST_USER=
#Tag name of the VPC where to deploy or "default" to deploy in default VPC
VPC_TAG_NAME=JenkinsKanikoStack/jenkins-vpc
```

Create an ssm parameter with the value of your domain certificat

This is the certificat which will be use to expose our services from the bot example:

```bash
aws ssm put-parameter --region $AWS_REGION --tags Key=project,Value=trivia --name CertificateArn-ecs.demo3.allamand.com --type String --value arn:aws:acm:...
```

1. Create a GitHub user for your bot, like @preview-bot.

2. Update the user's [notification settings](https://github.com/settings/notifications) to select:

- **Automatically watch repositories**
- Participating **Web and Mobile**
- Watching **Web and Mobile**

3. Create a [personal access token](https://github.com/settings/tokens) for the bot user with the following scopes:

- `repo` (Full control of private repositories)
- `notifications` (Access notifications)

Store the token in AWS Systems Manager Parameter Store:

```bash
aws ssm put-parameter --region $AWS_REGION --name ${BOT_NAME}-github-token --type SecureString --value
```

4. Invite the bot as a collaborator of your GitHub Repository.

5. Deploy the Bot

You can deploy in default VPC or in the VPC of your choice by configuring the **VPC_TAG_NAME** env var, cf `./scripts/0.pre-requisite.sh` file

Once the file is configured, you can source it

```bash
source ./scripts/0.pre-requisite.sh
```

Provision the stack in CloudFormation with the bot disabled:

```bash
make deploy-without-activation
```

> TODO: change permissions on cloudformation stack to least privilege

Then, build and push the bot docker image to ECR.

```bash
make build
```

Once the bot is build and pushed, you can enable it.

```bash
make deploy-activate
```

### Test Locally

```
GITHUB_TOKEN=`aws ssm get-parameter --name ${BOT_NAME}-github-token --with-decryption --query 'Parameter.Value' --output text`
docker run --rm -v $HOME/.aws:/root/.aws:ro -e AWS_REGION=$AWS_REGION -e githubToken=$GITHUB_TOKEN $BOT_NAME
```

### Deploy the bot using Github Actions

We can also automate the deployment of this bot using github-actions

For doing that we need to provide aws credentials to the github actions so that they will be able to connect to the AWS APIs needed for our deployment.

Github introduce a new way to integrates with AWS STS in order to retrieve temporary, short-lived credentials that can be used during the execution of the workflow. After that, the credentials will expire and no one will ever be able to use them again, preventing futur attacks in case of credentials leak at github action level.

#### Create an OpenID Connect Identity provider

The first step is to create an OpenId Connect (OIDC) identity provider in your AWS Account. This will aloow Githug to identify itself.

- Go to the IAM console / Identity providers
- Click Add new provider and select OpenID Connect
- Provider Url: https://token.actions.githubusercontent.com (Don't forget to click Get Thumbprint)
- Audience: sts.amazonaws.com

> You need to do this step only once per AWS account.

#### Create a role for Github Action

Now we need to create a role that Github will be able to assume in order to access the resources it need to control.

- Go back to IAM and select Roles
- Create a new role
- Chose Web Identity, select the Identity provider we created previously (tokens.actions.guthubusercontent.com), and its audience (sts.amazonaws.com)

Then we need to fill policies: Keep in mind that you should always stick to the principle of least privileges.

The GithubAction we are using needs some permissions:
- https://github.com/aws-actions/amazon-ecr-login#permissions

our script is also using some commands that needs additional permissions
- aws ec2 describe-vpcs
- aws ec2 describe-subnets
- aws cloudformation deploy

There is now an additional step to do. You need to edit the trust policy of the role to reduce its scope to your repository only. Make sure you don't skip this part, it is very important. Without that, any repository on GitHub will be able to assume your role and access your resources. (Unfortunately, there does not seem to be a way to do that at creation time).

Under condition, add the following segment:
```json
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:[your-org]/[your-repo]:*"
}
```

> You can also reduce the scope by using git reference, to a branch or tag, for example: `:ref:refs/heads/master`

Final result look like:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::1234567890:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:[your-org]/[your-repo]:*"
}
}
}
]
}
```

# Crédit

This works if derived from awsome work from Clare Liguory

https://github.com/clareliguori/clare-bot