, ,

Configure OpenID Connect for Bitbucket in AWS CDK

/

This guide will explain what is required to create a Bitbucket OpenID Connect (OIDC) provider in AWS CDK and includes a Bitbucket pipeline example on how to authenticate to AWS and access resources.

If you’re looking to configure OpenID Connect for GitHub, then read this article.

What is a Bitbucket OpenID Connect provider (OIDC)?

It’s an identity provider for BitBucket which uses the OpenID Connect protocol and can be set up on an AWS Account to establish trust between the account and your Bitbucket repository.

The advantage is that it allows you to access resources in AWS using an IAM role instead of using long-lived AWS credentials.

How to configure OpenID Connect for Bitbucket in AWS CDK

1. Create the Bitbucket OIDC provider

We’ll start by creating the OpenIdConnectProvider for Bitbucket:

const bitbucketDomain =
  'api.bitbucket.org/2.0/workspaces/<WORKSPACE>/pipelines-config/identity/oidc';

const bitbucketAudience =
  'ari:cloud:bitbucket::workspace/680cb3e455d4-f8b9b8d8f8d9-ddbb-4e19-baf1';

const bitbucketProvider = new iam.OpenIdConnectProvider(
  this,
  'bitbucketProvider',
  {
    url: `https://${bitbucketDomain}`,
    clientIds: [bitbucketAudience],
  }
);

To create the OIDC provider resource for Bitbucket we need to fill the following properties:

  • url: api.bitbucket.org/2.0/workspaces/<WORKSPACE>/pipelines-config/identity/oidc. Here you insert the Provider URL of the OpenID Connect URL used for authentication requests. Note: make sure to replace <WORKSPACE> with your own unique workspace name.
  • clientIds: ari:cloud:bitbucket::workspace/680cb3e455d4-f8b9b8d8f8d9-ddbb-4e19-baf1. This is the audience ID that is issued by the Identity Provider for your app.

You can find both the Provider URL and Audience ID in the OpenID Connect tab of your Bitbucket repository settings. For more details, check the official Bitbucket support page.

2. Create an IAM role with a WebIdentityPrincipal

Now we need to create an IAM role that is needed so we’ll be able to authenticate against the Bitbucket OIDC provider.

new iam.Role(this, 'exampleBitbucketDeployRole', {
  assumedBy: new iam.WebIdentityPrincipal(
    bitbucketProvider.openIdConnectProviderArn,
    conditions
  ),
  managedPolicies: [
    iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'),
  ],
  roleName: 'exampleBitbucketDeployRole',
  description:
    'This role is used via Bitbucket pipelines to deploy with AWS CDK or Terraform on the customers AWS account',
  maxSessionDuration: cdk.Duration.hours(2),
});

To enable the IAM role to authenticate against the OIDC provider, we need to add the property iam.WebIdentityPrincipal and add the bitbucketProvider.openIdConnectProviderArn from the bitbucketProvider we created in the previous step.

The IAM role itself has no permissions by default, so we add a new property managedPolicies, and assign an AWS managed policy. In this example, we apply the managed policy AdministratorAccess but you can limit the role’s privileges by assigning a custom or managed policy that contains fewer privileges.

The property maxSessionDuration sets a limit on how long the AWS STS credentials can be used at a time before expiring. In this case, the duration of the session with the STS credentials is set to 2 hours.

3. Create the condition for the IAM role and assign it to the WebIdentityPrincipal

In the previous part, we created the IAM role and as you can see we added conditions to the assumedBy property:

assumedBy: new iam.WebIdentityPrincipal(bitbucketProvider.openIdConnectProviderArn, conditions),

Now we’ll focus on creating the condition which will be attached to the iam.WebIdentityPrincipal. The condition is important because it allows us to limit the assumed role only to the Bitbucket repositories within the workspace.

We declare the following condition:

const bitbucketAudience =
  'ari:cloud:bitbucket::workspace/680cb3e455d4-f8b9b8d8f8d9-ddbb-4e19-baf1';

// grant only requests coming from a specific Bitbucket workspace.
const conditions: iam.Conditions = {
  StringEquals: {
    [`${bitbucketDomain}:aud`]: bitbucketAudience,
  },
};

The actual policy for the Web Identity will look like this when we synthesize the template in AWS CDK:

"AssumeRolePolicyDocument": {
  "Statement": [
    {
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "api.bitbucket.org/2.0/workspaces/<WORKSPACE>/pipelines-config/identity/oidc:aud": "ari:cloud:bitbucket::workspace/680cb3e455d4-f8b9b8d8f8d9-ddbb-4e19-baf1"
        }
      },
      "Effect": "Allow",
      "Principal": {
        "Federated": {
          "Ref": "bitbucketProviderE25A039A"
        }
      }
    }
  ],
  "Version": "2012-10-17"
},

4. Set up the bitbucket-pipelines.yml file

In order to create a CI/CD pipeline in Bitbucket, all you have to do is create a bitbucket-pipelines.yml at the root of your repository.

For this example, we’ll show how to set up the AWS credentials which we use to authenticate with the Bitbucket OIDC provider we created in AWS CDK at the beginning of this post.

image: node:16.3.0
pipelines:
  branches:
    main:
      - step:
          name: cdk deploy using oidc
          oidc: true
          script:
            - export AWS_REGION=eu-west-1
            - export AWS_ROLE_ARN=arn:aws:iam::012345678901:role/exampleBitbucketDeployRole
            - export AWS_WEB_IDENTITY_TOKEN_FILE=$(pwd)/web-identity-token
            - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token
            - cdk deploy --app "ts-node openid-connect-bitbucket/main.ts" "*bitbucket-oidc" --require-approval never

If you plan on using this example then make sure to change the following values:

  • AWS_ROLE_ARN=arn:aws:iam::012345678901:role/exampleBitbucketDeployRole. Change the AWS account id of the role ARN which matches the account id where you deployed the Bitbucket OIDC provider.
  • AWS_REGION=eu-west-1. Change this to the region where you wish to run your cdk deploy command.
  • cdk deploy --app "ts-node openid-connect-bitbucket/main.ts" "*bitbucket-oidc" --require-approval never. This deploys the AWS CDK stack that is hosted on my aws-cdk-examples GitHub repository. Change this to your own custom AWS CDK stack.

Note: If you need more details I highly suggest reading the official Bitbucket documentation on how to set up the credentials for the pipeline.

Conclusion

You were able to successfully set up a Bitbucket OpenID Connect provider (OIDC) using AWS CDK TypeScript. Additionally, you’ve also managed to test the OIDC connection in bitbucket pipelines by setting up and configuring the bitbucket-pipelines.yml file.

Everything that you’ve just built by following this article can also be found as a fully working example on my GitHub repository.

Danny Steenman

Is a Principal Cloud Consultant with a background in DevOps Engineering and thorough hands-on experience in architecting and building highly scalable distributed systems on AWS Cloud using Infrastructure as Code.

A prominent leader who is passionate about sharing AWS technical expertise by writing technical articles.