-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add 2 CodeBuild projects for GitHub runners
- One for Lambda - One for standard Linux
- Loading branch information
Showing
17 changed files
with
2,901 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
name: Build | ||
|
||
on: | ||
push: | ||
branches: | ||
- "*" | ||
|
||
jobs: | ||
build: | ||
runs-on: | ||
- codebuild-gha-runners-lambda-${{ github.run_id }}-${{ github.run_attempt }} | ||
- instance-size:10GB | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
- run: npm ci | ||
- run: npm run lint | ||
name: Lint | ||
- name: Build TypeScript | ||
run: npm run build | ||
- name: CDK Synth | ||
run: npx cdk synth --context githuborg=test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
name: Manual Lambda | ||
|
||
on: workflow_dispatch | ||
|
||
jobs: | ||
build: | ||
runs-on: | ||
- codebuild-gha-runners-lambda-${{ github.run_id }}-${{ github.run_attempt }} | ||
|
||
steps: | ||
- name: sleep | ||
run: sleep 60 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
name: Manual Standard | ||
|
||
on: workflow_dispatch | ||
|
||
jobs: | ||
build: | ||
runs-on: | ||
- codebuild-gha-runners-${{ github.run_id }}-${{ github.run_attempt }} | ||
|
||
steps: | ||
- name: sleep | ||
run: sleep 60 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
*.js | ||
!jest.config.js | ||
*.d.ts | ||
node_modules | ||
|
||
# CDK asset staging directory | ||
.cdk.staging | ||
cdk.out | ||
|
||
*.sw? | ||
import-source-credentials.json | ||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
*.ts | ||
!*.d.ts | ||
|
||
# CDK asset staging directory | ||
.cdk.staging | ||
cdk.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
# codebuild-gha-runners | ||
CodeBuild Runners for GitHub Actions | ||
# GitHub Actions Runners with CodeBuild ⚡️ 👷♀️ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#!/usr/bin/env node | ||
import 'source-map-support/register' | ||
import * as cdk from 'aws-cdk-lib' | ||
import { CodeConnectionStack } from '../lib/connconnection-stack' | ||
import { GhaRunnersStack } from '../lib/gha-runners-stack' | ||
|
||
const app = new cdk.App() | ||
const connectionStack = new CodeConnectionStack(app, 'ConnectionStack', {}) | ||
const ghaRunnersStack = new GhaRunnersStack(app, 'GhaRunnersStack', {}) | ||
ghaRunnersStack.addDependency(connectionStack, 'Connection must be created first and be approved in AWS Console') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"$schema": "https://biomejs.dev/schemas/1.9.2/schema.json", | ||
"vcs": { | ||
"enabled": true, | ||
"clientKind": "git", | ||
"useIgnoreFile": true | ||
}, | ||
"files": { | ||
"ignoreUnknown": false, | ||
"ignore": [] | ||
}, | ||
"formatter": { | ||
"enabled": true, | ||
"indentStyle": "space", | ||
"indentWidth": 2, | ||
"lineWidth": 120 | ||
}, | ||
"organizeImports": { | ||
"enabled": true | ||
}, | ||
"linter": { | ||
"enabled": true, | ||
"rules": { | ||
"recommended": true, | ||
"suspicious": { | ||
"noExplicitAny": "off" | ||
} | ||
} | ||
}, | ||
"javascript": { | ||
"formatter": { | ||
"quoteStyle": "single", | ||
"semicolons": "asNeeded", | ||
"trailingCommas": "none" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
{ | ||
"app": "npx ts-node --prefer-ts-exts bin/gha-runners.ts", | ||
"watch": { | ||
"include": ["**"], | ||
"exclude": [ | ||
"README.md", | ||
"cdk*.json", | ||
"**/*.d.ts", | ||
"**/*.js", | ||
"tsconfig.json", | ||
"package*.json", | ||
"yarn.lock", | ||
"node_modules", | ||
"test" | ||
] | ||
}, | ||
"context": { | ||
"@aws-cdk/aws-lambda:recognizeLayerVersion": true, | ||
"@aws-cdk/core:checkSecretUsage": true, | ||
"@aws-cdk/core:target-partitions": ["aws", "aws-cn"], | ||
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, | ||
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, | ||
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, | ||
"@aws-cdk/aws-iam:minimizePolicies": true, | ||
"@aws-cdk/core:validateSnapshotRemovalPolicy": true, | ||
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, | ||
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, | ||
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, | ||
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true, | ||
"@aws-cdk/core:enablePartitionLiterals": true, | ||
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, | ||
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, | ||
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, | ||
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, | ||
"@aws-cdk/aws-route53-patters:useCertificate": true, | ||
"@aws-cdk/customresources:installLatestAwsSdkDefault": false, | ||
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, | ||
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, | ||
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, | ||
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, | ||
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, | ||
"@aws-cdk/aws-redshift:columnId": true, | ||
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, | ||
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, | ||
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, | ||
"@aws-cdk/aws-kms:aliasNameRef": true, | ||
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, | ||
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true, | ||
"@aws-cdk/aws-efs:denyAnonymousAccess": true, | ||
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, | ||
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, | ||
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, | ||
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, | ||
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, | ||
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, | ||
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, | ||
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, | ||
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, | ||
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, | ||
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, | ||
"@aws-cdk/aws-eks:nodegroupNameAttribute": true, | ||
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, | ||
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, | ||
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, | ||
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module.exports = { | ||
testEnvironment: 'node', | ||
roots: ['<rootDir>/test'], | ||
testMatch: ['**/*.test.ts'], | ||
transform: { | ||
'^.+\\.tsx?$': 'ts-jest' | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import * as cdk from 'aws-cdk-lib' | ||
import * as codeconn from 'aws-cdk-lib/aws-codeconnections' | ||
import * as iam from 'aws-cdk-lib/aws-iam' | ||
import * as ssm from 'aws-cdk-lib/aws-ssm' | ||
import type { Construct } from 'constructs' | ||
import { CODEBUILD_POLICY_ARN_PARAM_NAME, GITHUB_CODECONNECTION_ARN_PARAM_NAME } from './constants' | ||
|
||
/** | ||
* This stack provides a CodeConnection connection, allowing services like CodeBuild to connect | ||
* to GitHub. After creation, the connection must be manually finalised | ||
* in the management console before it is used. That's why we keep it in a separate stack. | ||
*/ | ||
export class CodeConnectionStack extends cdk.Stack { | ||
constructor(scope: Construct, id: string, props?: cdk.StackProps) { | ||
super(scope, id, props) | ||
|
||
// Adding this policy to the same stack as the CodeBuild project | ||
// resulted in IAM eventual consistency problems, causing | ||
// the CodeConnection to be inaccessible | ||
// ("User is not authorized to access connection") | ||
// Providing it as a managed policy in a separate stack mitigates this. | ||
const codebuildConnectionPolicy = new iam.ManagedPolicy(this, 'CodeBuildPolicy', { | ||
managedPolicyName: `${cdk.Stack.of(this).stackName}CodeBuildPolicy`, | ||
document: new iam.PolicyDocument({ | ||
statements: [ | ||
new iam.PolicyStatement({ | ||
effect: iam.Effect.ALLOW, | ||
actions: ['codeconnections:Get*', 'codeconnections:List*', 'codeconnections:Pass*', 'codeconnections:Use*'], | ||
resources: ['*'] | ||
}), | ||
new iam.PolicyStatement({ | ||
effect: iam.Effect.ALLOW, | ||
actions: [ | ||
'codebuild:ListConnectedOAuthAccounts', | ||
'codebuild:ListRepositories', | ||
'codebuild:PersistOAuthToken', | ||
'codebuild:ImportSourceCredentials' | ||
], | ||
resources: ['*'] | ||
}), | ||
new iam.PolicyStatement({ | ||
effect: iam.Effect.ALLOW, | ||
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'], | ||
resources: ['*'] | ||
}) | ||
] | ||
}) | ||
}) | ||
|
||
const conn = new codeconn.CfnConnection(this, 'Conn', { | ||
connectionName: 'GitHubFt', | ||
providerType: 'GitHub' | ||
}) | ||
|
||
new ssm.StringParameter(this, 'CodeBuildPolicyArnParam', { | ||
parameterName: CODEBUILD_POLICY_ARN_PARAM_NAME, | ||
stringValue: codebuildConnectionPolicy.managedPolicyArn, | ||
description: 'Managed policy for CodeBuild allowing CodeConnection usage' | ||
}) | ||
new ssm.StringParameter(this, 'ConnectionArnParam', { | ||
parameterName: GITHUB_CODECONNECTION_ARN_PARAM_NAME, | ||
stringValue: conn.attrConnectionArn, | ||
description: 'CodeConnection connection ARN for access to GitHub from' | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export const GITHUB_CODECONNECTION_ARN_PARAM_NAME = '/github/codeconnection-arn' | ||
export const CODEBUILD_POLICY_ARN_PARAM_NAME = '/codebuild-connection-policy-arn' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import * as cdk from 'aws-cdk-lib' | ||
import * as codebuild from 'aws-cdk-lib/aws-codebuild' | ||
import * as iam from 'aws-cdk-lib/aws-iam' | ||
import * as ssm from 'aws-cdk-lib/aws-ssm' | ||
import type { Construct } from 'constructs' | ||
import { CODEBUILD_POLICY_ARN_PARAM_NAME, GITHUB_CODECONNECTION_ARN_PARAM_NAME } from './constants' | ||
|
||
/** | ||
* This stack sets up CodeBuild projects to run GitHub Actions runners. | ||
*/ | ||
export class GhaRunnersStack extends cdk.Stack { | ||
constructor(scope: Construct, id: string, props?: cdk.StackProps) { | ||
super(scope, id, props) | ||
|
||
const githubOrganisation = scope.node.tryGetContext('githuborg') | ||
if (!githubOrganisation) { | ||
throw new Error("Context variable 'githuborg' is required. This should be the name of your GitHub organisation") | ||
} | ||
|
||
const connectionArn = ssm.StringParameter.fromStringParameterName( | ||
this, | ||
'ConnectionArnParam', | ||
GITHUB_CODECONNECTION_ARN_PARAM_NAME | ||
).stringValue | ||
const codeBuildPolicyArnParam = ssm.StringParameter.fromStringParameterName( | ||
this, | ||
'CodeBuildPolicyArnParam', | ||
CODEBUILD_POLICY_ARN_PARAM_NAME | ||
).stringValue | ||
const projectServiceRole = new iam.Role(this, 'CodeBuildServiceRole', { | ||
assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), | ||
path: '/service-role/' | ||
}) | ||
projectServiceRole.addManagedPolicy( | ||
iam.ManagedPolicy.fromManagedPolicyArn(this, 'CodeBuildManagedPolicy', codeBuildPolicyArnParam) | ||
) | ||
|
||
const environmentsBySuffix: Record<string, codebuild.CfnProject.EnvironmentProperty> = { | ||
'': { | ||
computeType: 'BUILD_GENERAL1_SMALL', | ||
image: 'aws/codebuild/standard:5.0', | ||
type: 'LINUX_CONTAINER' | ||
}, | ||
'-lambda': { | ||
computeType: 'BUILD_LAMBDA_10GB', | ||
image: 'aws/codebuild/amazonlinux-x86_64-lambda-standard:nodejs20', | ||
type: 'LINUX_LAMBDA_CONTAINER' | ||
} | ||
} | ||
|
||
const commonCodeBuildProjectProps: Omit<codebuild.CfnProjectProps, 'name' | 'environment'> = { | ||
source: { | ||
gitCloneDepth: 1, | ||
type: 'GITHUB', | ||
location: 'CODEBUILD_DEFAULT_WEBHOOK_SOURCE_LOCATION', | ||
auth: { | ||
// Change type to 'OAUTH' if you want to use a GitHub PAT that has already been | ||
// loaded into your AWS account+region with `import-source-credentials`. | ||
type: 'CODECONNECTIONS', | ||
resource: connectionArn | ||
} | ||
}, | ||
triggers: { | ||
webhook: true, | ||
scopeConfiguration: { | ||
name: githubOrganisation | ||
}, | ||
filterGroups: [ | ||
[ | ||
{ | ||
type: 'EVENT', | ||
pattern: 'WORKFLOW_JOB_QUEUED' | ||
} | ||
] | ||
] | ||
}, | ||
artifacts: { | ||
type: 'NO_ARTIFACTS' | ||
}, | ||
concurrentBuildLimit: 60, | ||
serviceRole: projectServiceRole.roleArn | ||
} | ||
|
||
for (const [suffix, environment] of Object.entries(environmentsBySuffix)) { | ||
new codebuild.CfnProject(this, `RunnerProject${suffix}`, { | ||
...commonCodeBuildProjectProps, | ||
environment: environment, | ||
name: `gha-runners${suffix}` | ||
}) | ||
} | ||
} | ||
} |
Oops, something went wrong.