diff --git a/API.md b/API.md
index 9304fd52..10bb6f69 100644
--- a/API.md
+++ b/API.md
@@ -68,6 +68,7 @@ new CodeBuildImageBuilder(scope: Construct, id: string, props: CodeBuildImageBui
| **Name** | **Description** |
| --- | --- |
| toString
| Returns a string representation of this construct. |
+| addExtraCertificates
| Add extra trusted certificates. This helps deal with self-signed certificates for GitHub Enterprise Server. |
| addFiles
| Uploads a folder to the build server at a given folder name. |
| addPolicyStatement
| Add a policy statement to the builder to access resources required to the image build. |
| addPostBuildCommand
| Adds a command that runs after `docker build` and `docker push`. |
@@ -85,6 +86,24 @@ public toString(): string
Returns a string representation of this construct.
+##### `addExtraCertificates`
+
+```typescript
+public addExtraCertificates(path: string): void
+```
+
+Add extra trusted certificates. This helps deal with self-signed certificates for GitHub Enterprise Server.
+
+All first party Dockerfiles support this. Others may not.
+
+###### `path`Required
+
+- *Type:* string
+
+path to directory containing a file called certs.pem containing all the required certificates.
+
+---
+
##### `addFiles`
```typescript
@@ -814,20 +833,20 @@ It creates a webhook, secrets, and a step function to orchestrate all runs. Secr
By default, this will create a runner provider of each available type with the defaults. This is good enough for the initial setup stage when you just want to get GitHub integration working.
```typescript
-new GitHubRunners(stack, 'runners', {});
+new GitHubRunners(this, 'runners');
```
Usually you'd want to configure the runner providers so the runners can run in a certain VPC or have certain permissions.
```typescript
-const vpc = ec2.Vpc.fromLookup(stack, 'vpc', { vpcId: 'vpc-1234567' });
-const runnerSg = new ec2.SecurityGroup(stack, 'runner security group', { vpc: vpc });
-const dbSg = ec2.SecurityGroup.fromSecurityGroupId(stack, 'database security group', 'sg-1234567');
-const bucket = new s3.Bucket(stack, 'runner bucket');
+const vpc = ec2.Vpc.fromLookup(this, 'vpc', { vpcId: 'vpc-1234567' });
+const runnerSg = new ec2.SecurityGroup(this, 'runner security group', { vpc: vpc });
+const dbSg = ec2.SecurityGroup.fromSecurityGroupId(this, 'database security group', 'sg-1234567');
+const bucket = new s3.Bucket(this, 'runner bucket');
// create a custom CodeBuild provider
const myProvider = new CodeBuildRunner(
- stack, 'codebuild runner',
+ this, 'codebuild runner',
{
label: 'my-codebuild',
vpc: vpc,
@@ -840,7 +859,7 @@ dbSg.connections.allowFrom(runnerSg, ec2.Port.tcp(3306), 'allow runners to conne
// create the runner infrastructure
new GitHubRunners(
- stack,
+ this,
'runners',
{
providers: [myProvider],
@@ -1962,7 +1981,61 @@ const gitHubRunnersProps: GitHubRunnersProps = { ... }
| **Name** | **Type** | **Description** |
| --- | --- | --- |
+| allowPublicSubnet
| boolean
| Allow management functions to run in public subnets. |
+| extraCertificates
| string
| Path to a directory containing a file named certs.pem containing any additional certificates required to trust GitHub Enterprise Server. Use this when GitHub Enterprise Server certificates are self-signed. |
| providers
| IRunnerProvider[]
| List of runner providers to use. |
+| securityGroup
| aws-cdk-lib.aws_ec2.ISecurityGroup
| Security group attached to all management functions. |
+| vpc
| aws-cdk-lib.aws_ec2.IVpc
| VPC used for all management functions. |
+| vpcSubnets
| aws-cdk-lib.aws_ec2.SubnetSelection
| VPC subnets used for all management functions. |
+
+---
+
+##### `allowPublicSubnet`Optional
+
+```typescript
+public readonly allowPublicSubnet: boolean;
+```
+
+- *Type:* boolean
+- *Default:* false
+
+Allow management functions to run in public subnets.
+
+Lambda Functions in a public subnet can NOT access the internet.
+
+---
+
+##### `extraCertificates`Optional
+
+```typescript
+public readonly extraCertificates: string;
+```
+
+- *Type:* string
+
+Path to a directory containing a file named certs.pem containing any additional certificates required to trust GitHub Enterprise Server. Use this when GitHub Enterprise Server certificates are self-signed.
+
+You may also want to use custom images for your runner providers that contain the same certificates. See {@link CodeBuildImageBuilder.addCertificates}.
+
+```typescript
+const imageBuilder = new CodeBuildImageBuilder(this, 'Image Builder with Certs', {
+ dockerfilePath: CodeBuildRunner.LINUX_X64_DOCKERFILE_PATH,
+});
+imageBuilder.addExtraCertificates('path-to-my-extra-certs-folder');
+
+const provider = new CodeBuildRunner(this, 'CodeBuild', {
+ imageBuilder: imageBuilder,
+});
+
+new GitHubRunners(
+ this,
+ 'runners',
+ {
+ providers: [provider],
+ extraCertificates: 'path-to-my-extra-certs-folder',
+ }
+);
+```
---
@@ -1981,6 +2054,48 @@ At least one provider is required. Provider will be selected when its label matc
---
+##### `securityGroup`Optional
+
+```typescript
+public readonly securityGroup: ISecurityGroup;
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.ISecurityGroup
+
+Security group attached to all management functions.
+
+Use this with to provide access to GitHub Enterprise Server hosted inside a VPC.
+
+---
+
+##### `vpc`Optional
+
+```typescript
+public readonly vpc: IVpc;
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.IVpc
+
+VPC used for all management functions.
+
+Use this with GitHub Enterprise Server hosted that's inaccessible from outside the VPC.
+
+---
+
+##### `vpcSubnets`Optional
+
+```typescript
+public readonly vpcSubnets: SubnetSelection;
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.SubnetSelection
+
+VPC subnets used for all management functions.
+
+Use this with GitHub Enterprise Server hosted that's inaccessible from outside the VPC.
+
+---
+
### LambdaRunnerProps
#### Initializer
diff --git a/src/providers/docker-images/codebuild/linux-arm64/Dockerfile b/src/providers/docker-images/codebuild/linux-arm64/Dockerfile
index f9325d1d..9bb23480 100644
--- a/src/providers/docker-images/codebuild/linux-arm64/Dockerfile
+++ b/src/providers/docker-images/codebuild/linux-arm64/Dockerfile
@@ -6,10 +6,14 @@ RUN addgroup runner && adduser --system --disabled-password --home /home/runner
# add dependencies and sudo
ARG EXTRA_PACKAGES=""
-RUN apt-get update && apt-get upgrade -y && apt-get install -y curl sudo jq bash zip unzip iptables software-properties-common $EXTRA_PACKAGES && \
+RUN apt-get update && apt-get upgrade -y && apt-get install -y curl sudo jq bash zip unzip iptables software-properties-common ca-certificates $EXTRA_PACKAGES && \
usermod -aG sudo runner && \
echo "%sudo ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/runner
+# install extra certificates
+COPY extra_certs/. /tmp/certs/
+RUN if [ -f /tmp/certs/certs.pem ]; then cp /tmp/certs/certs.pem /usr/local/share/ca-certificates/github-enterprise-server.crt; update-ca-certificates; else echo no self-signed certificates; fi
+
# add latest git
RUN add-apt-repository ppa:git-core/ppa && apt update && apt-get install -y git
diff --git a/src/providers/docker-images/codebuild/linux-x64/Dockerfile b/src/providers/docker-images/codebuild/linux-x64/Dockerfile
index 96c799bb..166495fc 100644
--- a/src/providers/docker-images/codebuild/linux-x64/Dockerfile
+++ b/src/providers/docker-images/codebuild/linux-x64/Dockerfile
@@ -6,10 +6,14 @@ RUN addgroup runner && adduser --system --disabled-password --home /home/runner
# add dependencies and sudo
ARG EXTRA_PACKAGES=""
-RUN apt-get update && apt-get upgrade -y && apt-get install -y curl sudo jq bash zip unzip iptables software-properties-common $EXTRA_PACKAGES && \
+RUN apt-get update && apt-get upgrade -y && apt-get install -y curl sudo jq bash zip unzip iptables software-properties-common ca-certificates $EXTRA_PACKAGES && \
usermod -aG sudo runner && \
echo "%sudo ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/runner
+# install extra certificates
+COPY extra_certs/. /tmp/certs/
+RUN if [ -f /tmp/certs/certs.pem ]; then cp /tmp/certs/certs.pem /usr/local/share/ca-certificates/github-enterprise-server.crt; update-ca-certificates; else echo no self-signed certificates; fi
+
# add latest git
RUN add-apt-repository ppa:git-core/ppa && apt update && apt-get install -y git
diff --git a/src/providers/docker-images/fargate/linux-arm64/Dockerfile b/src/providers/docker-images/fargate/linux-arm64/Dockerfile
index 56f06651..65d4e232 100644
--- a/src/providers/docker-images/fargate/linux-arm64/Dockerfile
+++ b/src/providers/docker-images/fargate/linux-arm64/Dockerfile
@@ -6,10 +6,14 @@ RUN addgroup runner && adduser --system --disabled-password --home /home/runner
# add dependencies and sudo
ARG EXTRA_PACKAGES=""
-RUN apt-get update && apt-get upgrade -y && apt-get install -y curl sudo jq bash zip unzip software-properties-common $EXTRA_PACKAGES && \
+RUN apt-get update && apt-get upgrade -y && apt-get install -y curl sudo jq bash zip unzip software-properties-common ca-certificates $EXTRA_PACKAGES && \
usermod -aG sudo runner && \
echo "%sudo ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/runner
+# install extra certificates
+COPY extra_certs/. /tmp/certs/
+RUN if [ -f /tmp/certs/certs.pem ]; then cp /tmp/certs/certs.pem /usr/local/share/ca-certificates/github-enterprise-server.crt; update-ca-certificates; else echo no self-signed certificates; fi
+
# add latest git
RUN add-apt-repository ppa:git-core/ppa && apt update && apt-get install -y git
diff --git a/src/providers/docker-images/fargate/linux-x64/Dockerfile b/src/providers/docker-images/fargate/linux-x64/Dockerfile
index 6db7d73c..afc5c41d 100644
--- a/src/providers/docker-images/fargate/linux-x64/Dockerfile
+++ b/src/providers/docker-images/fargate/linux-x64/Dockerfile
@@ -6,10 +6,14 @@ RUN addgroup runner && adduser --system --disabled-password --home /home/runner
# add dependencies and sudo
ARG EXTRA_PACKAGES=""
-RUN apt-get update && apt-get upgrade -y && apt-get install -y curl sudo jq bash zip unzip software-properties-common $EXTRA_PACKAGES && \
+RUN apt-get update && apt-get upgrade -y && apt-get install -y curl sudo jq bash zip unzip software-properties-common ca-certificates $EXTRA_PACKAGES && \
usermod -aG sudo runner && \
echo "%sudo ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/runner
+# install extra certificates
+COPY extra_certs/. /tmp/certs/
+RUN if [ -f /tmp/certs/certs.pem ]; then cp /tmp/certs/certs.pem /usr/local/share/ca-certificates/github-enterprise-server.crt; update-ca-certificates; else echo no self-signed certificates; fi
+
# add latest git
RUN add-apt-repository ppa:git-core/ppa && apt update && apt-get install -y git
diff --git a/src/providers/docker-images/lambda/linux-arm64/Dockerfile b/src/providers/docker-images/lambda/linux-arm64/Dockerfile
index f729031c..bd1f48d7 100644
--- a/src/providers/docker-images/lambda/linux-arm64/Dockerfile
+++ b/src/providers/docker-images/lambda/linux-arm64/Dockerfile
@@ -5,6 +5,10 @@ FROM $BASE_IMAGE
WORKDIR /runner
+# install extra certificates
+COPY extra_certs/. /tmp/certs/
+RUN if [ -f /tmp/certs/certs.pem ]; then cp /tmp/certs/certs.pem /etc/pki/ca-trust/source/anchors/ghe.crt; update-ca-trust; else echo no self-signed certificates; fi
+
# add dependencies
ARG EXTRA_PACKAGES=""
RUN yum update -y && yum install -y jq tar gzip bzip2 which binutils git zip unzip $EXTRA_PACKAGES
diff --git a/src/providers/docker-images/lambda/linux-x64/Dockerfile b/src/providers/docker-images/lambda/linux-x64/Dockerfile
index bc02dc59..8afdedb9 100644
--- a/src/providers/docker-images/lambda/linux-x64/Dockerfile
+++ b/src/providers/docker-images/lambda/linux-x64/Dockerfile
@@ -5,6 +5,10 @@ FROM $BASE_IMAGE
WORKDIR /runner
+# install extra certificates
+COPY extra_certs/. /tmp/certs/
+RUN if [ -f /tmp/certs/certs.pem ]; then cp /tmp/certs/certs.pem /etc/pki/ca-trust/source/anchors/ghe.crt; update-ca-trust; else echo no self-signed certificates; fi
+
# add dependencies
ARG EXTRA_PACKAGES=""
RUN yum update -y && yum install -y jq tar gzip bzip2 which binutils git zip unzip $EXTRA_PACKAGES
diff --git a/src/providers/image-builders/codebuild.ts b/src/providers/image-builders/codebuild.ts
index 85fa5b84..e88964ca 100644
--- a/src/providers/image-builders/codebuild.ts
+++ b/src/providers/image-builders/codebuild.ts
@@ -209,7 +209,7 @@ export class CodeBuildImageBuilder extends Construct implements IImageBuilder {
const asset = new s3_assets.Asset(this, destName, { path: sourcePath });
this.secondaryAssets.set(destName, asset);
- this.preBuild.push(`ln -s "$CODEBUILD_SRC_DIR_${destName}" "${destName}"`);
+ this.preBuild.push(`rm -rf "${destName}" && cp -r "$CODEBUILD_SRC_DIR_${destName}" "${destName}"`); // symlinks don't work with docker
}
/**
@@ -261,6 +261,20 @@ export class CodeBuildImageBuilder extends Construct implements IImageBuilder {
this.policyStatements.push(statement);
}
+ /**
+ * Add extra trusted certificates. This helps deal with self-signed certificates for GitHub Enterprise Server.
+ *
+ * All first party Dockerfiles support this. Others may not.
+ *
+ * @param path path to directory containing a file called certs.pem containing all the required certificates
+ */
+ public addExtraCertificates(path: string) {
+ if (this.boundImage) {
+ throw new Error('Image is already bound. Use this method before passing the builder to a runner provider.');
+ }
+ this.addFiles(path, 'extra_certs');
+ }
+
/**
* Called by IRunnerProvider to finalize settings and create the image builder.
*/
@@ -378,6 +392,7 @@ export class CodeBuildImageBuilder extends Construct implements IImageBuilder {
phases: {
pre_build: {
commands: this.preBuild.concat([
+ 'mkdir -p extra_certs',
'$(aws ecr get-login --no-include-email --region "$AWS_DEFAULT_REGION")',
]),
},
diff --git a/src/runner.ts b/src/runner.ts
index 0c94a7d7..6c0e5e93 100644
--- a/src/runner.ts
+++ b/src/runner.ts
@@ -1,5 +1,11 @@
import * as cdk from 'aws-cdk-lib';
-import { aws_ec2 as ec2, aws_iam as iam, aws_stepfunctions as stepfunctions, aws_stepfunctions_tasks as stepfunctions_tasks } from 'aws-cdk-lib';
+import {
+ aws_ec2 as ec2,
+ aws_iam as iam,
+ aws_lambda as lambda,
+ aws_stepfunctions as stepfunctions,
+ aws_stepfunctions_tasks as stepfunctions_tasks,
+} from 'aws-cdk-lib';
import { FunctionUrlAuthType } from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
import { CodeBuildRunner } from './providers/codebuild';
@@ -42,6 +48,33 @@ export interface GitHubRunnersProps {
* Security group attached to all management functions. Use this with to provide access to GitHub Enterprise Server hosted inside a VPC.
*/
readonly securityGroup?: ec2.ISecurityGroup;
+
+ /**
+ * Path to a directory containing a file named certs.pem containing any additional certificates required to trust GitHub Enterprise Server. Use this when GitHub Enterprise Server certificates are self-signed.
+ *
+ * You may also want to use custom images for your runner providers that contain the same certificates. See {@link CodeBuildImageBuilder.addCertificates}.
+ *
+ * ```typescript
+ * const imageBuilder = new CodeBuildImageBuilder(this, 'Image Builder with Certs', {
+ * dockerfilePath: CodeBuildRunner.LINUX_X64_DOCKERFILE_PATH,
+ * });
+ * imageBuilder.addExtraCertificates('path-to-my-extra-certs-folder');
+ *
+ * const provider = new CodeBuildRunner(this, 'CodeBuild', {
+ * imageBuilder: imageBuilder,
+ * });
+ *
+ * new GitHubRunners(
+ * this,
+ * 'runners',
+ * {
+ * providers: [provider],
+ * extraCertificates: 'path-to-my-extra-certs-folder',
+ * }
+ * );
+ * ```
+ */
+ readonly extraCertificates?: string;
}
/**
@@ -50,20 +83,20 @@ export interface GitHubRunnersProps {
* By default, this will create a runner provider of each available type with the defaults. This is good enough for the initial setup stage when you just want to get GitHub integration working.
*
* ```typescript
- * new GitHubRunners(stack, 'runners', {});
+ * new GitHubRunners(this, 'runners');
* ```
*
* Usually you'd want to configure the runner providers so the runners can run in a certain VPC or have certain permissions.
*
* ```typescript
- * const vpc = ec2.Vpc.fromLookup(stack, 'vpc', { vpcId: 'vpc-1234567' });
- * const runnerSg = new ec2.SecurityGroup(stack, 'runner security group', { vpc: vpc });
- * const dbSg = ec2.SecurityGroup.fromSecurityGroupId(stack, 'database security group', 'sg-1234567');
- * const bucket = new s3.Bucket(stack, 'runner bucket');
+ * const vpc = ec2.Vpc.fromLookup(this, 'vpc', { vpcId: 'vpc-1234567' });
+ * const runnerSg = new ec2.SecurityGroup(this, 'runner security group', { vpc: vpc });
+ * const dbSg = ec2.SecurityGroup.fromSecurityGroupId(this, 'database security group', 'sg-1234567');
+ * const bucket = new s3.Bucket(this, 'runner bucket');
*
* // create a custom CodeBuild provider
* const myProvider = new CodeBuildRunner(
- * stack, 'codebuild runner',
+ * this, 'codebuild runner',
* {
* label: 'my-codebuild',
* vpc: vpc,
@@ -76,7 +109,7 @@ export interface GitHubRunnersProps {
*
* // create the runner infrastructure
* new GitHubRunners(
- * stack,
+ * this,
* 'runners',
* {
* providers: [myProvider],
@@ -101,12 +134,27 @@ export class GitHubRunners extends Construct {
private readonly webhook: GithubWebhookHandler;
private readonly orchestrator: stepfunctions.StateMachine;
private readonly setupUrl: string;
+ private readonly extraLambdaEnv: {[p: string]: string} = {};
+ private readonly extraLambdaProps: lambda.FunctionOptions;
constructor(scope: Construct, id: string, props?: GitHubRunnersProps) {
super(scope, id);
this.props = props ?? {};
this.secrets = new Secrets(this, 'Secrets');
+ this.extraLambdaProps = {
+ vpc: this.props.vpc,
+ vpcSubnets: this.props.vpcSubnets,
+ allowPublicSubnet: this.props.allowPublicSubnet,
+ securityGroups: this.props.securityGroup ? [this.props.securityGroup] : undefined,
+ layers: this.props.extraCertificates ? [new lambda.LayerVersion(scope, 'Certificate Layer', {
+ description: 'Layer containing GitHub Enterprise Server certificate for cdk-github-runners',
+ code: lambda.Code.fromAsset(this.props.extraCertificates),
+ })] : undefined,
+ };
+ if (this.props.extraCertificates) {
+ this.extraLambdaEnv.NODE_EXTRA_CA_CERTS = '/opt/certs.pem';
+ }
if (this.props.providers) {
this.providers = this.props.providers;
@@ -209,12 +257,10 @@ export class GitHubRunners extends Construct {
environment: {
GITHUB_SECRET_ARN: this.secrets.github.secretArn,
GITHUB_PRIVATE_KEY_SECRET_ARN: this.secrets.githubPrivateKey.secretArn,
+ ...this.extraLambdaEnv,
},
timeout: cdk.Duration.seconds(30),
- vpc: this.props.vpc,
- vpcSubnets: this.props.vpcSubnets,
- allowPublicSubnet: this.props.allowPublicSubnet,
- securityGroups: this.props.securityGroup ? [this.props.securityGroup] : undefined,
+ ...this.extraLambdaProps,
},
);
@@ -233,12 +279,10 @@ export class GitHubRunners extends Construct {
environment: {
GITHUB_SECRET_ARN: this.secrets.github.secretArn,
GITHUB_PRIVATE_KEY_SECRET_ARN: this.secrets.githubPrivateKey.secretArn,
+ ...this.extraLambdaEnv,
},
timeout: cdk.Duration.seconds(30),
- vpc: this.props.vpc,
- vpcSubnets: this.props.vpcSubnets,
- allowPublicSubnet: this.props.allowPublicSubnet,
- securityGroups: this.props.securityGroup ? [this.props.securityGroup] : undefined,
+ ...this.extraLambdaProps,
},
);
@@ -274,12 +318,10 @@ export class GitHubRunners extends Construct {
WEBHOOK_HANDLER_ARN: this.webhook.handler.latestVersion.functionArn,
STEP_FUNCTION_ARN: this.orchestrator.stateMachineArn,
SETUP_FUNCTION_URL: this.setupUrl,
+ ...this.extraLambdaEnv,
},
timeout: cdk.Duration.minutes(3),
- vpc: this.props.vpc,
- vpcSubnets: this.props.vpcSubnets,
- allowPublicSubnet: this.props.allowPublicSubnet,
- securityGroups: this.props.securityGroup ? [this.props.securityGroup] : undefined,
+ ...this.extraLambdaProps,
},
);
@@ -310,12 +352,10 @@ export class GitHubRunners extends Construct {
GITHUB_SECRET_ARN: this.secrets.github.secretArn,
GITHUB_PRIVATE_KEY_SECRET_ARN: this.secrets.githubPrivateKey.secretArn,
WEBHOOK_URL: this.webhook.url,
+ ...this.extraLambdaEnv,
},
timeout: cdk.Duration.minutes(3),
- vpc: this.props.vpc,
- vpcSubnets: this.props.vpcSubnets,
- allowPublicSubnet: this.props.allowPublicSubnet,
- securityGroups: this.props.securityGroup ? [this.props.securityGroup] : undefined,
+ ...this.extraLambdaProps,
},
);