Skip to content
This repository has been archived by the owner on Oct 23, 2023. It is now read-only.

Commit

Permalink
Make AWS access keys optional and document OIDC (#11)
Browse files Browse the repository at this point in the history
* Make AWS access keys optional

For OIDC (AssumeRoleWithWebIdentity)

* Update action.yml

* Update README.md

* Update README.md

* Update README.md

* Update action.yml

* Update action.yml

* Update README.md

* Update README.md

* Update action.yml

* Update action.yml

* Update README.md

* Update README.md

* Update README.md

* Update README.md
  • Loading branch information
jpalomaki authored Dec 2, 2021
1 parent 10fd826 commit b26f0df
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 41 deletions.
127 changes: 96 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,97 @@
# ec2-actions-runner

⚠️ This is a new project and is very experimental
⚠️ This is a new project and as such, backwards-incompatible changes may occur between releases

Composite actions for managing an on-demand, self-hosted GitHub actions _repository_ runner (Linux on EC2).

Inspired by <https://github.com/machulav/ec2-github-runner>

## Requirements

- AWS account and VPC network
- A default VPC works fine, too
- AWS credentials with EC2 permissions
- You can use either a plain IAM user, or assume a role
- VPC subnet with Internet access
- Public subnet (public IP) **OR**
- Private subnet and NAT gateway
- Linux runner AMI (amd64 or arm64), with the following things pre-configured:
- Non-root user to run actions-runner service as
- [Actions-runner](https://github.com/actions/runner) v2.283.1+ and required [dependencies](https://github.com/actions/runner/blob/main/docs/start/envlinux.md)
- `git`, `docker`, `curl` and optionally `at` (if using the `auto-shutdown-at` feature)
- See e.g. <https://github.com/superblk/ec2-actions-runner-ami-linux-arm64> for an example AMI build
- EC2 launch template (AMI, instance type, VPC subnet, security groups, spot options etc)
- See example [Cloudformation template](https://gist.github.com/jpalomaki/003c4d173a856cf64c6d35f8869a2de8) that sets up a launch template
- GitHub personal access token (PAT) with `repo` scope

See [start/action.yml](start/action.yml) and [stop/action.yml](stop/action.yml) for all available input parameters.
Inspired by <https://github.com/machulav/ec2-github-runner> ❤️

## Pre-requisites

- AWS account
- Permissions to provision IAM, EC2 and VPC resources (to set up the runner scaffolding)
- VPC network
- Subnet with Internet access (required because self-hosted runners communicate with github.com)

## Limitations

- GitHub Enterprise Server (GHES) is not currently supported

## Setup

1. AWS: Configure GitHub OIDC identity provider (GitHub [documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services))
- Use of OIDC is recommended, so that static AWS access keys need not be stored in GitHub secrets
- NOTE: if you cannot configure OIDC roles, it is possible to utilize an IAM user with static access keys
2. AWS: Configure the IAM role that is assumed by the workflow, for starting/stopping runner EC2 instances
- Example OIDC assume role (trust) policy, that defines who can assume the role (see related [docs](<https://github.com/aws-actions/configure-aws-credentials#sample-iam-role-cloudformation-template>))

```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account>:oidc-provider/token.actions.githubusercontent.com"
},
"Action": [
"sts:AssumeRoleWithWebIdentity",
"sts:TagSession"
],
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:<owner>/<repository>:*"
}
}
}
]
}
```
- Example role policy (inline or customer-managed), that defines the _minimum_ permissions needed for starting/stopping runner EC2 instances

```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:RunInstances",
"ec2:TerminateInstances"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:CreateTags"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:CreateAction": "RunInstances"
}
}
}
]
}
```
4. AWS: Linux runner AMI (amd64 or arm64), with the following things pre-configured:
- Non-root user to run the actions-runner service as
- [Actions-runner](https://github.com/actions/runner) v2.283.1+ and required [dependencies](https://github.com/actions/runner/blob/main/docs/start/envlinux.md)
- `git`, `docker`, `curl` and optionally `at` (if using the `auto-shutdown-at` feature)
- See e.g. <https://github.com/superblk/ec2-actions-runner-ami-ubuntu-18.04-arm64> for an example AMI build
5. AWS: EC2 runner launch template (defines AMI, instance type, VPC subnet, security groups, spot options etc)
- See example [Cloudformation template](https://gist.github.com/jpalomaki/003c4d173a856cf64c6d35f8869a2de8) that sets up a launch template
6. GitHub: personal access token (PAT) with `repo` scope, required for registering self-hosted repository runners

## Example workflows

💡 EC2 instance ID is automatically assigned as a unique, self-hosted runner label

⚠️ Do not simply copy these examples verbatim, but adjust action version, AWS region, launch template name etc to match your config
⚠️ Do not simply copy these examples verbatim, but adjust action version, AWS region, launch template name etc to match your configuration

See [start/action.yml](start/action.yml) and [stop/action.yml](stop/action.yml) for all available input parameters

### Simple

Expand All @@ -39,15 +100,16 @@ Simple default. Leverages ephemeral runners that are automatically deregistered
```yaml
jobs:
start-runner:
permissions:
id-token: write
runs-on: ubuntu-20.04
steps:
- id: runner
name: Start runner
uses: superblk/ec2-actions-runner/start@<release>
with:
aws-region: eu-north-1
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-role-to-assume: arn:aws:iam::<account>:role/<role>
aws-launch-template: LaunchTemplateName=my-special-runner
github-token: ${{ secrets.GH_PAT }}
outputs:
Expand All @@ -61,15 +123,16 @@ jobs:

stop-runner:
if: always()
permissions:
id-token: write
needs: [start-runner, main]
runs-on: ubuntu-20.04
steps:
- name: Stop runner
uses: superblk/ec2-actions-runner/stop@<release>
with:
aws-region: eu-north-1
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-role-to-assume: arn:aws:iam::<account>:role/<role>
instance-id: ${{ needs.start-runner.outputs.instance-id }}
```

Expand All @@ -84,15 +147,16 @@ A more fail-safe alternative. Deregisters GitHub runner explicitly (not relying
```yaml
jobs:
start-runner:
permissions:
id-token: write
runs-on: ubuntu-20.04
steps:
- id: runner
name: Start runner
uses: superblk/ec2-actions-runner/start@<release>
with:
aws-region: eu-north-1
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-role-to-assume: arn:aws:iam::<account>:role/<role>
aws-launch-template: LaunchTemplateName=my-special-runner
runner-labels: ubuntu-18.04-arm64-${{ github.run_id }}
github-token: ${{ secrets.GH_PAT }}
Expand All @@ -114,15 +178,16 @@ jobs:

stop-runner:
if: always()
permissions:
id-token: write
needs: [start-runner, main]
runs-on: ubuntu-20.04
steps:
- name: Stop runner
uses: superblk/ec2-actions-runner/stop@<release>
with:
aws-region: eu-north-1
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-role-to-assume: arn:aws:iam::<account>:role/<role>
instance-id: ${{ needs.start-runner.outputs.instance-id }}
runner-id: ${{ needs.start-runner.outputs.runner-id }}
github-token: ${{ secrets.GH_PAT }}
Expand Down
10 changes: 5 additions & 5 deletions start/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ inputs:
description: AWS region, e.g. eu-west-1
required: true
aws-access-key-id:
description: AWS access key ID (pass via GitHub secret)
required: true
description: AWS access key ID (pass via GitHub secret). Required only if **not** using OIDC
required: false
aws-secret-access-key:
description: AWS secret access key (pass via GitHub secret)
required: true
description: AWS secret access key (pass via GitHub secret). Required only if **not** using OIDC
required: false
aws-role-to-assume:
description: AWS IAM role (ARN) to assume (optional)
description: AWS IAM role (ARN) to assume. Required if using OIDC (AssumeRoleWithWebIdentity)
required: false
aws-launch-template:
description: AWS EC2 launch template (AWS CLI format, e.g. LaunchTemplateId=lt-0abcd290751193123)
Expand Down
10 changes: 5 additions & 5 deletions stop/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ inputs:
description: AWS region, e.g. eu-west-1
required: true
aws-access-key-id:
description: AWS access key ID (pass via GitHub secret)
required: true
description: AWS access key ID (pass via GitHub secret). Required only if **not** using OIDC
required: false
aws-secret-access-key:
description: AWS secret access key (pass via GitHub secret)
required: true
description: AWS secret access key (pass via GitHub secret). Required only if **not** using OIDC
required: false
aws-role-to-assume:
description: AWS IAM role to assume (optional)
description: AWS IAM role (ARN) to assume. Required if using OIDC (AssumeRoleWithWebIdentity)
required: false
github-token:
description: GitHub auth token (PAT with repo scope, pass via GitHub secret). Optional if using ephemeral runners
Expand Down

0 comments on commit b26f0df

Please sign in to comment.