AWS DevOps & Developer Productivity Blog

Ensuring Security of Your Code in a Cross-Region/Cross-Account Deployment Solution

There are multiple ways you can protect your data while it is in transit and at rest. You can protect your data in transit by using SSL or by using client-side encryption. AWS Key Management Service (AWS KMS) is a managed service that makes it easy for you to create, control, rotate, and use your encryption keys. AWS KMS allows you to create custom keys. You can then share these keys with AWS Identity and Access Management (IAM) users and roles in your AWS account or in an AWS account owned by someone else.

In my previous post, I described a solution for building a cross-region/cross-account code deployment solution on AWS. In this post, I describe a few options for protecting your source code as it travels between regions and between AWS accounts.

To recap, you deployed the infrastructure as shown in the following diagram.

  • You had your development environment running in Region A in AWS Account A.
  • You had your QA environment running in Region B in AWS Account B.
  • You had a staging or production environment running in Region C in AWS Account C.

An update to the source code in Region A triggered validation and deployment of source code changes in the pipeline in Region A. A successful processing of source code in all of its AWS CodePipeline states invoked a Lambda function, which copied the source code into an S3 bucket in Region B. After the source code was copied into this bucket, it triggered a similar chain of processes into the different AWS CodePipeline stages in Region B.

 

Ensuring Security for Your Source Code

You might choose to encrypt the source code .zip file before uploading to the S3 bucket that is in Account A, Region A, using Amazon S3 server-side encryption:

1. Using the Amazon S3 service master key

Refer back to the Lambda function created for you by the CloudFormation stack in the previous post. Go to the AWS Lambda console and your function name should be <stackname>-CopytoDest-XXXXXXX.

 

 

Use the following parameter for the copyObject function – ServerSideEncryption: ‘AES256’

Note: The set-up already uses this option by default.

The copyObject function decrypts the .zip file and copies the object into account B.

 

2. Using an AWS KMS master key

Since the KMS keys are constrained in a region, copying the object (source code .zip file) into a different account across the region requires cross-account access to the KMS key. This must occur before Amazon S3 can use that key for encryption and decryption.

Use the following parameter for the copyObject function – ServerSideEncryption: ‘aws:kms’ and provide an SSEKMSKeyId: ‘<keyeid>’

To enable cross-account access for the KMS key and use it in Lambda function

a. Create a KMS key in the source account (Account A), region B – for example, XRDepTestKey

Note: This key must be created in region B. This is because the source code will be copied in an S3 bucket that exists in region B and the KMS key must be accessible in this region.

b. To enable the Lambda function to be able to use this KMS key, add lambdaS3CopyRole as a user for this key. The Lambda function and associated role and policies are defined in the CloudFormation template.

c. Note the ARN of the key that you generated.

d. Provide the external account (Account B) permission to use this key. For more information, see Sharing custom encryption keys securely between accounts.

arn:aws:iam::<Account B ID>:root

e. In Account B, delegate the permission to use this key to the role that AWS CodePipeline is using. In the CloudFormation template, you can see that CodePipelineTrustRole is used. Attach the following policy to the role. Ensure that you update the region and Account ID accordingly.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowUseOfTheKey",
            "Effect": "Allow",
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": [
                "arn:aws:kms:<regionB>:<AccountA ID>:key/<KMS Key in Region B ID>"
            ]
        },
        {
            "Sid": "AllowAttachmentOfPersistentResources",
            "Effect": "Allow",
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": [
                "arn:aws:kms:<regionB>:<AccountA ID>:key/<KMS Key in Region B ID>"
            ],
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": true
                }
          }
        }
    ]
}

f. Update the Lambda function, CopytoDest, to use the following in the parameter definition.

 

ServerSideEncryption: 'aws:kms',\n",
SSEKMSKeyId: '< keyeid >'  
//ServerSideEncryption: 'AES256'\n",

And there you go! You have enabled secure delivery of your source code into your cross-region/cross-account deployment solution.

About the Author


BK Chaurasiya is a Solutions Architect with Amazon Web Services. He provides technical guidance, design advice and thought leadership to some of the largest and successful AWS customers and partners.