@cloudsnorkel/cdk-github-runners
Version:
CDK construct to create GitHub Actions self-hosted runners. Creates ephemeral runners on demand. Easy to deploy and highly customizable.
272 lines (271 loc) • 12.2 kB
TypeScript
import * as cdk from 'aws-cdk-lib';
import { aws_cloudwatch as cloudwatch, aws_ec2 as ec2, aws_logs as logs, aws_stepfunctions as stepfunctions } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { LambdaAccess } from './access';
import { IRunnerProvider, ProviderRetryOptions } from './providers';
import { Secrets } from './secrets';
/**
* Properties for GitHubRunners
*/
export interface GitHubRunnersProps {
/**
* List of runner providers to use. At least one provider is required. Provider will be selected when its label matches the labels requested by the workflow job.
*
* @default CodeBuild, Lambda and Fargate runners with all the defaults (no VPC or default account VPC)
*/
readonly providers?: IRunnerProvider[];
/**
* Whether to require the `self-hosted` label. If `true`, the runner will only start if the workflow job explicitly requests the `self-hosted` label.
*
* Be careful when setting this to `false`. Avoid setting up providers with generic label requirements like `linux` as they may match workflows that are not meant to run on self-hosted runners.
*
* @default true
*/
readonly requireSelfHostedLabel?: boolean;
/**
* VPC used for all management functions. Use this with GitHub Enterprise Server hosted that's inaccessible from outside the VPC.
*
* Make sure the selected VPC and subnets have access to the following with either NAT Gateway or VPC Endpoints:
* * GitHub Enterprise Server
* * Secrets Manager
* * SQS
* * Step Functions
* * CloudFormation (status function only)
* * EC2 (status function only)
* * ECR (status function only)
*/
readonly vpc?: ec2.IVpc;
/**
* VPC subnets used for all management functions. Use this with GitHub Enterprise Server hosted that's inaccessible from outside the VPC.
*/
readonly vpcSubnets?: ec2.SubnetSelection;
/**
* Allow management functions to run in public subnets. Lambda Functions in a public subnet can NOT access the internet.
*
* @default false
*/
readonly allowPublicSubnet?: boolean;
/**
* Security group attached to all management functions. Use this with to provide access to GitHub Enterprise Server hosted inside a VPC.
*
* @deprecated use {@link securityGroups} instead
*/
readonly securityGroup?: ec2.ISecurityGroup;
/**
* Security groups attached to all management functions. Use this with to provide access to GitHub Enterprise Server hosted inside a VPC.
*/
readonly securityGroups?: 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 = CodeBuildRunnerProvider.imageBuilder(this, 'Image Builder with Certs');
* imageBuilder.addComponent(RunnerImageComponent.extraCertificates('path-to-my-extra-certs-folder/certs.pem', 'private-ca');
*
* const provider = new CodeBuildRunnerProvider(this, 'CodeBuild', {
* imageBuilder: imageBuilder,
* });
*
* new GitHubRunners(
* this,
* 'runners',
* {
* providers: [provider],
* extraCertificates: 'path-to-my-extra-certs-folder',
* }
* );
* ```
*/
readonly extraCertificates?: string;
/**
* Time to wait before stopping a runner that remains idle. If the user cancelled the job, or if another runner stole it, this stops the runner to avoid wasting resources.
*
* @default 5 minutes
*/
readonly idleTimeout?: cdk.Duration;
/**
* Logging options for the state machine that manages the runners.
*
* @default no logs
*/
readonly logOptions?: LogOptions;
/**
* Access configuration for the setup function. Once you finish the setup process, you can set this to `LambdaAccess.noAccess()` to remove access to the setup function. You can also use `LambdaAccess.apiGateway({ allowedIps: ['my-ip/0']})` to limit access to your IP only.
*
* @default LambdaAccess.lambdaUrl()
*/
readonly setupAccess?: LambdaAccess;
/**
* Access configuration for the webhook function. This function is called by GitHub when a new workflow job is scheduled. For an extra layer of security, you can set this to `LambdaAccess.apiGateway({ allowedIps: LambdaAccess.githubWebhookIps() })`.
*
* You can also set this to `LambdaAccess.apiGateway({allowedVpc: vpc, allowedIps: ['GHES.IP.ADDRESS/32']})` if your GitHub Enterprise Server is hosted in a VPC. This will create an API Gateway endpoint that's only accessible from within the VPC.
*
* *WARNING*: changing access type may change the URL. When the URL changes, you must update GitHub as well.
*
* @default LambdaAccess.lambdaUrl()
*/
readonly webhookAccess?: LambdaAccess;
/**
* Access configuration for the status function. This function returns a lot of sensitive information about the runner, so you should only allow access to it from trusted IPs, if at all.
*
* @default LambdaAccess.noAccess()
*/
readonly statusAccess?: LambdaAccess;
/**
* Options to retry operation in case of failure like missing capacity, or API quota issues.
*
* GitHub jobs time out after not being able to get a runner for 24 hours. You should not retry for more than 24 hours.
*
* Total time spent waiting can be calculated with interval * (backoffRate ^ maxAttempts) / (backoffRate - 1).
*
* @default retry 23 times up to about 24 hours
*/
readonly retryOptions?: ProviderRetryOptions;
}
/**
* Defines what execution history events are logged and where they are logged.
*/
export interface LogOptions {
/**
* The log group where the execution history events will be logged.
*/
readonly logGroupName?: string;
/**
* Determines whether execution data is included in your log.
*
* @default false
*/
readonly includeExecutionData?: boolean;
/**
* Defines which category of execution history events are logged.
*
* @default ERROR
*/
readonly level?: stepfunctions.LogLevel;
/**
* The number of days log events are kept in CloudWatch Logs. When updating
* this property, unsetting it doesn't remove the log retention policy. To
* remove the retention policy, set the value to `INFINITE`.
*
* @default logs.RetentionDays.ONE_MONTH
*/
readonly logRetention?: logs.RetentionDays;
}
/**
* Create all the required infrastructure to provide self-hosted GitHub runners. It creates a webhook, secrets, and a step function to orchestrate all runs. Secrets are not automatically filled. See README.md for instructions on how to setup GitHub integration.
*
* 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(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(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 CodeBuildRunnerProvider(
* this, 'codebuild runner',
* {
* labels: ['my-codebuild'],
* vpc: vpc,
* securityGroups: [runnerSg],
* },
* );
* // grant some permissions to the provider
* bucket.grantReadWrite(myProvider);
* dbSg.connections.allowFrom(runnerSg, ec2.Port.tcp(3306), 'allow runners to connect to MySQL database');
*
* // create the runner infrastructure
* new GitHubRunners(
* this,
* 'runners',
* {
* providers: [myProvider],
* }
* );
* ```
*/
export declare class GitHubRunners extends Construct implements ec2.IConnectable {
readonly props?: GitHubRunnersProps | undefined;
/**
* Configured runner providers.
*/
readonly providers: IRunnerProvider[];
/**
* Secrets for GitHub communication including webhook secret and runner authentication.
*/
readonly secrets: Secrets;
/**
* Manage the connections of all management functions. Use this to enable connections to your GitHub Enterprise Server in a VPC.
*
* This cannot be used to manage connections of the runners. Use the `connections` property of each runner provider to manage runner connections.
*/
readonly connections: ec2.Connections;
private readonly webhook;
private readonly redeliverer;
private readonly orchestrator;
private readonly setupUrl;
private readonly extraLambdaEnv;
private readonly extraLambdaProps;
private stateMachineLogGroup?;
private jobsCompletedMetricFilters?;
constructor(scope: Construct, id: string, props?: GitHubRunnersProps | undefined);
private stateMachine;
private tokenRetriever;
private deleteFailedRunner;
private statusFunction;
private setupFunction;
private checkIntersectingLabels;
private idleReaper;
private idleReaperQueue;
private lambdaSecurityGroups;
/**
* Metric for the number of GitHub Actions jobs completed. It has `ProviderLabels` and `Status` dimensions. The status can be one of "Succeeded", "SucceededWithIssues", "Failed", "Canceled", "Skipped", or "Abandoned".
*
* **WARNING:** this method creates a metric filter for each provider. Each metric has a status dimension with six possible values. These resources may incur cost.
*/
metricJobCompleted(props?: cloudwatch.MetricProps): cloudwatch.Metric;
/**
* Metric for successful executions.
*
* A successful execution doesn't always mean a runner was started. It can be successful even without any label matches.
*
* A successful runner doesn't mean the job it executed was successful. For that, see {@link metricJobCompleted}.
*/
metricSucceeded(props?: cloudwatch.MetricProps): cloudwatch.Metric;
/**
* Metric for failed runner executions.
*
* A failed runner usually means the runner failed to start and so a job was never executed. It doesn't necessarily mean the job was executed and failed. For that, see {@link metricJobCompleted}.
*/
metricFailed(props?: cloudwatch.MetricProps): cloudwatch.Metric;
/**
* Metric for the interval, in milliseconds, between the time the execution starts and the time it closes. This time may be longer than the time the runner took.
*/
metricTime(props?: cloudwatch.MetricProps): cloudwatch.Metric;
/**
* Creates a topic for notifications when a runner image build fails.
*
* Runner images are rebuilt every week by default. This provides the latest GitHub Runner version and software updates.
*
* If you want to be sure you are using the latest runner version, you can use this topic to be notified when a build fails.
*/
failedImageBuildsTopic(): cdk.aws_sns.Topic;
/**
* Creates CloudWatch Logs Insights saved queries that can be used to debug issues with the runners.
*
* * "Webhook errors" helps diagnose configuration issues with GitHub integration
* * "Ignored webhook" helps understand why runners aren't started
* * "Ignored jobs based on labels" helps debug label matching issues
* * "Webhook started runners" helps understand which runners were started
*/
createLogsInsightsQueries(): void;
}