Skip to main content

GitHub Workflows support for CDK Pipelines

Project description

CDK Pipelines for GitHub Workflows

Experimental

A construct library for painless Continuous Delivery of CDK applications, deployed via GitHub Workflows.

The CDK already has a CI/CD solution, CDK Pipelines, which creates an AWS CodePipeline that deploys CDK applications. This module serves the same surface area, except that it is implemented with GitHub Workflows.

Table of Contents

Usage

Assuming you have a Stage called MyStage that includes CDK stacks for your app and you want to deploy it to two AWS environments (BETA_ENV and PROD_ENV):

import { App } from 'aws-cdk-lib';
import { ShellStep } from 'aws-cdk-lib/pipelines';
import { GitHubWorkflow } from 'cdk-pipelines-github';

const app = new App();

const pipeline = new GitHubWorkflow(app, 'Pipeline', {
  synth: new ShellStep('Build', {
    commands: [
      'yarn install',
      'yarn build',
    ],
  }),
  gitHubActionRoleArn: 'arn:aws:iam::<account-id>:role/GitHubActionRole',
});

pipeline.addStage(new MyStage(this, 'Beta', { env: BETA_ENV }));
pipeline.addStage(new MyStage(this, 'Prod', { env: PROD_ENV }));

app.synth();

When you run cdk synth, a deploy.yml workflow will be created under .github/workflows in your repo. This workflow will deploy your application based on the definition of the pipeline. In this case, it will the two stages in sequence, and within each stage, it will deploy all the stacks according to their dependency order and maximum parallelism. If you app uses assets, assets will be published to the relevant destination environment.

The Pipeline class from cdk-pipelines-github is derived from the base CDK Pipelines class, so most features should be supported out of the box. See the CDK Pipelines documentation for more details.

NOTES:

AWS Credentials

There are two ways to supply AWS credentials to the workflow:

  • GitHub Action IAM Role (recommended).
  • Long-lived AWS Credentials stored in GitHub Secrets.

The GitHub Action IAM Role authenticates via the GitHub OpenID Connect provider and is recommended, but it requires preparing your AWS account beforehand. This approach allows your Workflow to exchange short-lived tokens directly from AWS. With OIDC, benefits include:

  • No cloud secrets.
  • Authentication and authorization management.
  • Rotating credentials.

You can read more here.

GitHub Action Role

Authenticating via OpenId Connect means you do not need to store long-lived credentials as GitHub Secrets. With OIDC, you provide a pre-provisioned IAM role to your GitHub Workflow via the gitHubActionRoleArn property.

import { App } from 'aws-cdk-lib';
import { ShellStep } from 'aws-cdk-lib/pipelines';
import { GitHubWorkflow } from 'cdk-pipelines-github';

const app = new App();

const pipeline = new GitHubWorkflow(app, 'Pipeline', {
  synth: new ShellStep('Build', {
    commands: [
      'yarn install',
      'yarn build',
    ],
  }),
  gitHubActionRoleArn: 'arn:aws:iam::<account-id>:role/GitHubActionRole',
});

There are two ways to create this IAM role:

  • Use the GitHubActionRole construct (recommended and described below).
  • Manually set up the role (Guide).

GitHubActionRole Construct

Because this construct involves creating an IAM role in your account, it must be created separate to your GitHub Workflow and deployed via a normal cdk deploy with your local AWS credentials. Upon successful deployment, the arn of your newly created IAM role will be exposed as a CfnOutput.

To utilize this construct, create a separate CDK stack with the following code and cdk deploy:

import { GitHubActionRole } from 'cdk-pipelines-github';
import { App, Construct, Stack, StackProps } from 'aws-cdk-lib';

class MyGitHubActionRole extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const provider = new GitHubActionRole(this, 'github-action-role', {
      repoString: 'myUser/myRepo',
    };
  }
}

const app = new App();
new MyGitHubActionRole(app, 'MyGitHubActionRole');
app.synth();

Note: If you have previously created the GitHub identity provider with url https://token.actions.githubusercontent.com, the above example will fail because you can only have one such provider defined per account. In this case, you must provide the already created provider into your GithubActionRole construct via the provider property.

Make sure the audience for the provider is sts.amazonaws.com in this case.

class MyGitHubActionRole extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const provider = new GitHubActionRole(this, 'github-action-role', {
      repos: ['myUser/myRepo'],
      provider: GitHubActionRole.existingGitHubActionsProvider(this),
    });
  }
}

GitHub Secrets

Authenticating via this approach means that you will be manually creating AWS credentials and duplicating them in GitHub secrets. The workflow expects the GitHub repository to include secrets with AWS credentials under AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. You can override these defaults by supplying the awsCredentials property to the workflow:

import { App } from 'aws-cdk-lib';
import { ShellStep } from 'aws-cdk-lib/pipelines';
import { GitHubWorkflow } from 'cdk-pipelines-github';

const app = new App();

const pipeline = new GitHubWorkflow(app, 'Pipeline', {
  synth: new ShellStep('Build', {
    commands: [
      'yarn install',
      'yarn build',
    ],
  }),
  awsCredentials: {
    accessKeyId: 'MY_ID',
    secretAccessKey: 'MY_KEY',
  },
});

Using Docker in the Pipeline

You can use Docker in GitHub Workflows in a similar fashion to CDK Pipelines. For a full discussion on how to use Docker in CDK Pipelines, see Using Docker in the Pipeline.

Just like CDK Pipelines, you may need to authenticate to Docker registries to avoid being throttled.

Authenticating to Docker registries

You can specify credentials to use for authenticating to Docker registries as part of the Workflow definition. This can be useful if any Docker image assets — in the pipeline or any of the application stages — require authentication, either due to being in a different environment (e.g., ECR repo) or to avoid throttling (e.g., DockerHub).

import { App } from 'aws-cdk-lib';
import { ShellStep } from 'aws-cdk-lib/pipelines';
import { GitHubWorkflow } from 'cdk-pipelines-github';

const app = new App();

const pipeline = new GitHubWorkflow(app, 'Pipeline', {
  synth: new ShellStep('Build', {
    commands: [
      'yarn install',
      'yarn build',
    ],
  }),
  dockerCredentials: [
    // Authenticate to ECR
    DockerCredential.ecr('<account-id>.dkr.ecr.<aws-region>.amazonaws.com'),

    // Authenticate to DockerHub
    DockerCredential.dockerHub({
      // These properties are defaults; feel free to omit
      usernameKey: 'DOCKERHUB_USERNAME',
      personalAccessTokenKey: 'DOCKERHUB_TOKEN',
    }),

    // Authenticate to Custom Registries
    DockerCredential.customRegistry('custom-registry', {
      usernameKey: 'CUSTOM_USERNAME',
      passwordKey: 'CUSTOM_PASSWORD',
    }),
  ],
});

Tutorial

You can find an example usage in test/example-app.ts which includes a simple CDK app and a pipeline.

You can find a repository that uses this example here: eladb/test-app-cdkpipeline.

To run the example, clone this repository and install dependencies:

cd ~/projects # or some other playground space
git clone https://github.com/cdklabs/cdk-pipelines-github
cd cdk-pipelines-github
yarn

Now, create a new GitHub repository and clone it as well:

cd ~/projects
git clone https://github.com/myaccount/my-test-repository

You'll need to set up AWS credentials in your environment:

export AWS_ACCESS_KEY_ID=xxxx
export AWS_SECRET_ACCESS_KEY=xxxxx

Bootstrap your environments:

export CDK_NEW_BOOTSTRAP=1
npx cdk bootstrap aws://ACCOUNTID/us-east-1
npx cdk bootstrap aws://ACCOUNTID/eu-west-2

Now, run the manual-test.sh script when your working directory is the new repository:

cd ~/projects/my-test-repository
~/projects/cdk-piplines/github/test/manual-test.sh

This will produce a cdk.out directory and a .github/workflows/deploy.yml file.

Commit and push these files to your repo and you should see the deployment workflow in action. Make sure your GitHub repository has AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY secrets that can access the same account that you synthesized against.

Not supported yet

This is work in progress. The following features are still not supported:

  • Anti-tamper check for CI runs (synth should fail if CI=1 and the workflow has changed)

Contributing

See CONTRIBUTING for more information.

License

This project is licensed under the Apache-2.0 License.

Project details


Release history Release notifications | RSS feed

This version

0.2.1

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cdk-pipelines-github-0.2.1.tar.gz (224.4 kB view hashes)

Uploaded Source

Built Distribution

cdk_pipelines_github-0.2.1-py3-none-any.whl (223.0 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page