Deploy GitHub Action runners in your AWS Account using serverless AWS CodeBuild.
This Terraform module simplifies deployment of self-hosted GitHub Action runners using AWS CodeBuild. Unlike traditional approaches that require managing EC2 instances, this solution is serverless.
- Simple - Quick setup with minimal configuration (see examples)
- Serverless - No EC2 instances to maintain; CodeBuild spins up ephemeral runners on-demand
- Cost-effective - Pay only for build minutes when workflows run; zero cost when idle
- Scalable - Automatically scales within AWS CodeBuild quotas
- Secure - No public inbound traffic required
This module is best for projects with infrequent CI/CD runs or long idle periods. For many projects, CI/CD runs sporadically, making the pay-per-minute model of CodeBuild more economical than continuously running EC2 instances.
When a GitHub Action is triggered in your repository:
- A webhook notifies the AWS CodeBuild project
- CodeBuild spins up an ephemeral runner environment (optionally, within your VPC)
- The runner self-configures and connects to GitHub
- Your workflow jobs execute in the CodeBuild environment
- The runner terminates after job completion
- AWS Account with appropriate permissions
- GitHub repository with appropriate permissions
- Terraform >= 0.13.0
Configure authentication between AWS and GitHub to enable secure communication.
Follow the detailed setup guide: GitHub Authentication Setup
Configure and deploy this module using Terraform. Check the examples directory for quick-start templates.
module "github_runner" {
source = "cloudandthings/github-runners/aws"
# Your configuration here
}Modify your GitHub workflow file to use the CodeBuild runner:
jobs:
my-job:
# The runner label below will trigger CodeBuild to run this job
runs-on: codebuild-${{ RUNNER_NAME }}-${{ github.run_id }}-${{ github.run_attempt }}
steps:
- uses: actions/checkout@v3
- name: Run your commands
run: echo "Running on CodeBuild!"Replace RUNNER_NAME with the name you configured for your runner.
The runner label is also added as a description on the CodeBuild project.
The module automatically selects an appropriate default Docker image:
- Default:
aws/codebuild/amazonlinux2-x86_64-standard:5.0(when not using ECR) - ECR: Assumes an image tagged
latestexists in your ECR repository
Specify a custom Docker image via the environment_image variable:
CodeBuild images:
environment_image = "aws/codebuild/amazonlinux2-x86_64-standard:4.0"Docker Hub images:
environment_image = "hashicorp/terraform:latest"Amazon ECR images:
environment_image = "137112412989.dkr.ecr.us-west-2.amazonaws.com/amazonlinux:latest"To use Amazon ECR:
- Provide an existing ECR repository name, or let the module create one
- Ensure an image with the
latesttag exists, or specify a different tag inenvironment_image - The final image URI is available as an output variable for verification
Note: If using a custom ECR image, you may need additional configuration in your Dockerfile since some GitHub uses actions may not work by default.
When using custom ECR images, some GitHub uses actions may not work out of the box. Additional installation and configuration steps may be needed in your Dockerfile to ensure compatibility with GitHub Actions.
CodeBuild charges per build minute. While this module is highly cost-effective for projects with infrequent builds, it may not be economical for repositories with:
- Frequent commits and builds
- Very long-running workflows
- Numerous parallel jobs
Use the AWS Pricing Calculator to estimate costs for your specific use case.
This module previously used EC2 spot instances with configurable AutoScaling. If you wish to continue using the EC2-based approach, the code has been moved to a separate repository:
terraform-aws-github-runners-ec2
Having issues? Check out our Troubleshooting Guide for common problems and solutions.
Found an issue or want to contribute? See CONTRIBUTING.md for guidelines.
Please note that this project has a Code of Conduct. By participating, you are expected to uphold this code.
For security concerns, please review our Security Policy. To report a vulnerability, please use GitHub Security Advisories.
- GitHub Authentication Setup Guide
- Troubleshooting Guide
- AWS CodeBuild Documentation
- GitHub Actions Documentation
License: View License
module "github_runner" {
source = "../../"
# Required parameters
############################
# Naming for all created resources
name = "github-runner-codebuild-test"
source_location = "https://github.com/my-org/my-repo.git"
# Environment image is not specified so it will default to:
# "aws/codebuild/amazonlinux2-x86_64-standard:5.0"
# Optional parameters
############################
description = "Created by my-org/my-runner-repo.git"
# testing purposes only
github_personal_access_token = "example"
vpc_id = "vpc-0ffaabbcc1122"
subnet_ids = ["subnet-0123", "subnet-0456"]
}locals {
naming_prefix = "test-github-runner"
vpc_id = "vpc-0ffaabbcc1122"
vpc_cidr = "10.0.0.0/16"
}
# Create a custom security-group to allow SSH to all EC2 instances
resource "aws_security_group" "this" {
name = "${local.naming_prefix}-sg"
description = "GitHub runner ${local.naming_prefix}-sg"
# tfsec:ignore:aws-ec2-no-public-egress-sgr
egress {
description = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
vpc_id = local.vpc_id
#checkov:skip=CKV2_AWS_5:The SG is attached by the module.
#checkov:skip=CKV_AWS_382:Egress to GitHub Actions is required for the runner to work.
}
# Create a baseline CodeBuild credential that all GitHub projects will use by default
resource "aws_codebuild_source_credential" "github" {
auth_type = "SECRETS_MANAGER"
server_type = "GITHUB"
token = "arn:aws:secretsmanager:region:account-id:secret:name"
}
module "github_runner" {
source = "../../"
# Required parameters
############################
source_location = "https://github.com/my-org/my-repo.git"
# Naming for all created resources
name = "github-runner-codebuild-test"
# Environment image is not specified so it will default to:
# "${local.aws_account_id}.dkr.ecr.${local.aws_region}.amazonaws.com/${local.ecr_repository_name}:latest"
# Because an ECR repo is used
vpc_id = "vpc-0ffaabbcc1122"
subnet_ids = ["subnet-0123", "subnet-0456"]
# Optional parameters
################################
description = "Created by my-org/my-runner-repo.git"
create_ecr_repository = true
# Override the baseline CodeBuild credential
source_auth = {
type = "SECRETS_MANAGER"
resource = "arn:aws:secretsmanager:af-south-1:123456789012:secret:my-github-oauth-token-secret-nwYBWW"
}
security_group_ids = [aws_security_group.this.id]
cloudwatch_logs_group_name = "/some/log/group"
}
# Example: Using the default security group with custom ingress rules for Packer
module "github_runner_with_packer" {
source = "../../"
# Required parameters
source_location = "https://github.com/my-org/my-repo.git"
name = "github-runner-packer"
# VPC configuration
vpc_id = local.vpc_id
subnet_ids = ["subnet-0123", "subnet-0456"]
# Custom ingress rules added to the default security group
# This is useful when running Packer which requires ephemeral ports for WinRM/SSH
ingress_with_cidr_blocks = [
{
from_port = 1024
to_port = 65535
protocol = "tcp"
description = "Ephemeral ports required for Packer WinRM/SSH communication"
cidr_blocks = [local.vpc_cidr]
},
{
from_port = 5985
to_port = 5986
protocol = "tcp"
description = "WinRM ports for Packer"
cidr_blocks = [local.vpc_cidr]
}
]
}| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| build_timeout | Number of minutes, from 5 to 2160 (36 hours), for AWS CodeBuild to wait until timing out any related build that does not get marked as completed. | number |
5 |
no |
| cloudwatch_log_group_retention_in_days | Number of days to retain log events | number |
14 |
no |
| cloudwatch_logs_group_name | Name of the log group used by the CodeBuild project. If not specified then a default is used. | string |
null |
no |
| cloudwatch_logs_stream_name | Name of the log stream used by the CodeBuild project. If not specified then a default is used. | string |
null |
no |
| create_cloudwatch_log_group | Determines whether a log group is created by this module. If not, AWS will automatically create one if logging is enabled | bool |
true |
no |
| create_ecr_repository | If set to true then an ECR repository will be created, and an image needs to be pushed to it before running the build project | string |
false |
no |
| description | Short description of the project. | string |
null |
no |
| ecr_repository_name | Name of the ECR repository to create or use. If not specified and create_ecr_repository is true, then a default is used. |
string |
null |
no |
| environment_compute_type | Information about the compute resources the build project will use. Valid values: BUILD_GENERAL1_SMALL, BUILD_GENERAL1_MEDIUM, BUILD_GENERAL1_LARGE, BUILD_GENERAL1_2XLARGE, BUILD_LAMBDA_1GB, BUILD_LAMBDA_2GB, BUILD_LAMBDA_4GB, BUILD_LAMBDA_8GB, BUILD_LAMBDA_10GB. BUILD_GENERAL1_SMALL is only valid if type is set to LINUX_CONTAINER. When type is set to LINUX_GPU_CONTAINER, compute_type must be BUILD_GENERAL1_LARGE. When type is set to LINUX_LAMBDA_CONTAINER or ARM_LAMBDA_CONTAINER, compute_type must be BUILD_LAMBDA_XGB |
string |
"BUILD_GENERAL1_SMALL" |
no |
| environment_image | Docker image to use for this build project. Valid values include Docker images provided by CodeBuild (e.g aws/codebuild/amazonlinux2-x86_64-standard:4.0), Docker Hub images (e.g., hashicorp/terraform:latest) and full Docker repository URIs such as those for ECR (e.g., 137112412989.dkr.ecr.us-west-2.amazonaws.com/amazonlinux:latest). If not specified and not using ECR, then a default CodeBuild image is used, or if using ECR then an ECR image with a latest tag is used. |
string |
null |
no |
| environment_type | Type of build environment to use for related builds. Valid values: LINUX_CONTAINER, LINUX_GPU_CONTAINER, WINDOWS_CONTAINER (deprecated), WINDOWS_SERVER_2019_CONTAINER, ARM_CONTAINER, LINUX_LAMBDA_CONTAINER, ARM_LAMBDA_CONTAINER |
string |
"LINUX_CONTAINER" |
no |
| github_codeconnection_arn | ARN of an active GitHub app CodeConnection to use for the region-wide CodeBuild Source Credential. See docs/GITHUB-AUTH-SETUP.md for more information. |
string |
null |
no |
| github_personal_access_token | The GitHub personal access token for the region-wide CodeBuild Source Credential. See docs/GITHUB-AUTH-SETUP.md for more information. |
string |
null |
no |
| github_personal_access_token_ssm_parameter | SSM parameter containing the GitHub personal access token to use for the region-wide CodeBuild Source Credential. See docs/GITHUB-AUTH-SETUP.md for more information. |
string |
null |
no |
| github_secretsmanager_secret_arn | The Secret ARN containing the credentials to use for the region-wide CodeBuild Source Credential. See docs/GITHUB-AUTH-SETUP.md for more information. |
string |
null |
no |
| iam_role_assume_role_policy | The IAM role assume role policy document to use. If not specified then a default is used. | string |
null |
no |
| iam_role_name | Name of the IAM role to be used. If not specified then a role will be created | string |
null |
no |
| iam_role_permissions_boundary | ARN of the policy that is used to set the permissions boundary for the IAM service role | string |
null |
no |
| iam_role_policies | Map of IAM role policy ARNs to attach to the IAM role | map(string) |
{} |
no |
| ingress_with_cidr_blocks | List of ingress rules to add to the default security group with CIDR blocks | list(object({ |
[] |
no |
| ingress_with_source_security_group_id | List of ingress rules to add to the default security group with source security group IDs | list(object({ |
[] |
no |
| kms_key_id | The AWS KMS key to be used | string |
null |
no |
| name | Created resources will be named with this. | string |
n/a | yes |
| s3_logs_bucket_name | Name of the S3 bucket to store logs in. If not specified then logging to S3 will be disabled. | string |
null |
no |
| s3_logs_bucket_prefix | Prefix to use for the logs in the S3 bucket | string |
"" |
no |
| security_group_ids | The list of Security Group IDs for AWS CodeBuild to launch ephemeral EC2 instances in. | list(string) |
[] |
no |
| security_group_name | Name to use on created Security Group. Defaults to name |
string |
null |
no |
| source_auth | Override the default CodeBuild source credential for this project. This allows using project-specific authentication instead of the account/region baseline credential. See docs/GITHUB-AUTH-SETUP.md for usage details. | object({ |
null |
no |
| source_location | Your source code repo location, for example https://github.com/my/repo.git | string |
n/a | yes |
| subnet_ids | The list of Subnet IDs for AWS CodeBuild to launch ephemeral EC2 instances in. | list(string) |
[] |
no |
| tags | A map of tags to assign to the resources created by this module. If configured with a provider default_tags configuration block present, tags with matching keys will overwrite those defined at the provider-level. |
map(string) |
{} |
no |
| vpc_id | The VPC ID for AWS CodeBuild to launch ephemeral instances in. | string |
null |
no |
No modules.
| Name | Description |
|---|---|
| aws_security_group_id | ID of the security group created for the CodeBuild project |
| codebuild_project_arn | ARN of the CodeBuild project, to be used when running GitHub Actions |
| codebuild_project_name | Name of the CodeBuild project, to be used when running GitHub Actions |
| codebuild_role_name | Name of the CodeBuild role, to be used when running GitHub Actions |
| ecr_repository_name | Name of the ECR repository, to be used when to push custom docker images for the CodeBuild project |
| environment_image | Docker image used for this CodeBuild project |
| Name | Version |
|---|---|
| aws | >= 5, < 7 |
| Name | Version |
|---|---|
| terraform | >= 0.14.0 |
| aws | >= 5, < 7 |
| http | ~> 3.0 |
| null | ~> 3.2 |
<!-- END_TF_DOCS -->