Switch the config repository for the AWS Landing Zone Accelerator to S3
Photo generated by chatGPT

Introduction

The Landing Zone Accelerator (LZA) introduced the support of other repositories, such as S3 or CodeConnection, e.g., for GitHub, GitLab in v1.10.0 and explained in the official docs. However, as I installed the LZA before, I started off with CodeCommit, which is deprecated by AWS.

NOTE: if you want to switch from CodeCommit to GitHub / GitLab etc. refer to this official blog post

So for me, it was time to switch and the impulse came from the release of aws-luminarlz-cli, which needs S3 as source of the config files. I will elaborate on this CLI in a later blog post, but for now, first things first, let’s switch from CodeCommit to S3.

Should be a piece of 🍰, right 😃 So let’s go!

Challenge

As said, after reading the docs, I thought that this would be an easy switch. So, I additionally did some research if someone had already tried it and found 2 things

  1. the following issue#735 on GitHub which also mentioned
  2. the official blog post from AWS: Moving from AWS CodeCommit or Amazon S3 to external configuration repositories for Landing Zone Accelerator on AWS

The blog post from AWS, however, only mentioned migrating from CodeCommit to another VCS. That’s not what I needed for my use case.

Then let’s change it in a naive way from CodeCommit to S3 in the Cloudformation Stack, which also needs to be adapted for each update.

So from CodeCommit 1-config-codecommit

to S3 and leave all the other settings unchanged: 2-config-s3

Also, the ChangeSet tells me the same.

3-changeset

However, I was still wondering where the new S3 🪣 with the config will be created. As it, of course, did not exist yet:

4-no-config-bucket

Let’s give it a try and see what happens, as I ultimately still need to approve within the pipeline. The docs warned with the hint:

Select ‘Yes’ to deploy the solution with an existing configuration repository. Leave the default value if you’re using the solution-deployed repository. NOTE: Updating this value after initial installation may cause adverse effects such as unexpected failures and resource replacements.

❌ And the update failed ❌

5-failure-installer-validate

and the logs told me

ConfigRepositoryLocation parameter set to s3, but existing deployment using CodeCommit was detected. This value cannot be changed for existing deployments. Please set ConfigRepositoryLocation to CodeCommit and try again.

5-failure-installer-log

which I verified with the code snippet from lib/lambdas/validate/index.js, which was introduced in v1.10.0 as well:

const response = require('cfn-response');
const { CodePipelineClient, GetPipelineCommand } = require('@aws-sdk/client-codepipeline');
exports.handler = async function (event, context) {
  console.log(JSON.stringify(event, null, 4));

  const configRepositoryLocation = event.ResourceProperties.configRepositoryLocation;

  if (event.RequestType === 'Delete') {
    await response.send(event, context, response.SUCCESS, {}, event.PhysicalResourceId);
    return;
 }

  if (configRepositoryLocation === 's3') {
    try {
      const pipelineName = event.ResourceProperties.acceleratorPipelineName;
      const client = new CodePipelineClient();
      const input = { name: pipelineName };
      const command = new GetPipelineCommand(input);
      const pipelineResponse = await client.send(command);
      const sourceStage = pipelineResponse.pipeline.stages.find(stage => stage.name === 'Source');
      const configAction = sourceStage?.actions.find(action => action.name === 'Configuration');
      // 👇🏽 we we cannot switch from CodeCommit to S3 ... as the validation fails
      if (configAction.actionTypeId.provider === 'CodeCommit') {
        await response.send(
          event,
          context,
          response.FAILED,
 {
            FailureReason:
              'ConfigRepositoryLocation parameter set to s3, but existing deployment using CodeCommit was detected. This value cannot be changed for existing deployments. Please set ConfigRepositoryLocation to CodeCommit and try again.',
 },
          event.PhysicalResourceId,
 );
        return;
 }
 } catch (err) {
      console.log('Encountered error finding existing pipeline, continuing');
      console.log(err);
      await response.send(event, context, response.SUCCESS, {}, event.PhysicalResourceId);
      return;
 }
 }

  // End of Validation
  await response.send(event, context, response.SUCCESS, {}, event.PhysicalResourceId);
  return;
};

So I was wondering if this change is even possible if the code prevents it 🤔 So I digged more and found the comment-2702283688 from one of the contributors of the LZA saying

I’ve completed the migration for a customers from Codecommit to S3, high level steps:

  1. Update the InstallerStack with the necessary changes to leverage S3
  2. Allow the Installer pipeline to finish (will create a S3 bucket for source code)
  3. When the primary pipeline begins to run automatically, stop it
  4. Zip the contents of the Codecommit repository and push it to s3 (bucket name: aws-accelerator-config-$AWS_ACCOUNT_ID-$AWS_HOME_REGION/aws-accelerator-config.zip)

However, someone else had the same error, and no solutions were provided, so I decided to try to fix it myself. Here’s how I did it, step-by-step!

Step

As we know, the installer pipeline will create the config S3 bucket; however, we cannot pass the validation stage. To work around this, we

  1. create empty tmp bucket named: aws-accelerator-tmp-<AWS_ACCOUNT_ID>-<AWS_REGION>
  2. edit the AWSAccelerator-Pipeline Source step from 6-pipeline-source-edit

to the tmp S3 bucket: 8-tmp-config-bucket

save the pipeline, and the Configuration shows the change Source configuration: 9-tmp-config-bucket-changed

  1. Trigger the LZA installer pipeline via Release change and see the corresponding CodeBuild Project with env CONFIG_REPOSITORY_LOCATION s3 run again. 10-installer-pipeline-success

  2. You’d see the pipeline stack being updated 11-pipeline-stack-success

  3. Now you need to stop your AWSAccelerator-Pipeline as quickly as possible (best in the Build step) 12-pipeline-stop

  4. The installer pipeline has now created a aws-accelerator-config-<AWS_ACCOUNT_ID>-<AWS_REGION> S3 bucket with all the correct policies for us 🎉 and also adapted the Source in the AWSAccelerator-Pipeline. That’s what we wanted ✅

  5. You can now safely delete the empty tmp bucket aws-accelerator-tmp-<AWS_ACCOUNT_ID>-<AWS_REGION>, we needed before

  6. Now you take the existing aws-accelerator-config from the CodeCommit repository, zip it with all yaml file in the root and upload it to the aws-accelerator-config-<AWS_ACCOUNT_ID>-<AWS_REGION> at zipped/aws-accelerator-config.zip

cd aws-accelerator-config
zip -r aws-accelerator-config.zip .
  1. Feel now free to trigger the AWSAccelerator-Pipeline manually via Release Change and watch the LZA use the config files from the S3 🪣 source 🎉

13-pipeline-new-release

Conclusion

It was more complex than expected; however, I now understand why the validation stage first tried to prevent it and favors CodeConnection. Let me know if there is a better solution 😃

Like what you read? You can hire me 💻, book a meeting 📆 or drop me a message to see which services may help you 👇