Secrets Unleashed: Elevate Your Builds Across All Environments with AWS Secret Manager Integration ๐Ÿš€โœจ

Secrets Unleashed: Elevate Your Builds Across All Environments with AWS Secret Manager Integration ๐Ÿš€โœจ

ยท

4 min read

Navigating the complex landscape of deploying applications to AWS demands a strategic approach, especially when it comes to ensuring security across diverse environments. Fear not, as this guide is your compass through the integration of AWS CodeBuild, CodePipeline, and AWS Secret Manager. Manage all your secrets using a single environment variable declared in the pipeline

The beauty of this process lies in its versatility. Whether your applications run on Node.js, Python, or any other runtime, the principles explored here can seamlessly extend to meet the specific needs of your chosen environment. Let's embark on a journey that promises not just security but also adaptability and efficiency in your deployment pipeline. Are you ready to transform your deployment experience? Let's dive in! ๐Ÿš€โœจ

Setting the Stage: AWS CloudFront, S3, and CodePipeline

We're orchestrating a seamless deployment of a React app to an S3 bucket, utilizing AWS CloudFront as a robust CDN. CodePipeline takes center stage, automating the CI/CD process. But what's the secret sauce behind securing this setup and dynamically managing secrets? Let's dive in!

๐Ÿคซ Create a Secret in AWS Secret Manager

๐ŸŒŸ Step 1: Building the Foundation with AWS CodeBuild

AWS CodeBuild, our trusty builder, requires a buildspec file to map out the entire build process. This file specifies runtime environments, commands, and scripts needed for a successful build. For instance, you can customize your Node.js version, ensuring your app is built with the right tools. Discover the supported runtimes here. Also mention the required environment variable in the aws codebuild for this pipeline

๐ŸŽญ Step 2: Decoding the CodeBuild Events

CodeBuild events are the backbone of our build process. In each stage - install, pre_build, build, and post_build - we orchestrate specific tasks. In the install stage, we set up the runtime and versions. The pre_build stage is where the magic begins: we fetch environment variables dynamically, securing our secrets for the respective environment.

Make sure your codebuild has the required permissions to access s3, invalidate cloudfront distribution and also access secret manager.

You should have an iam role that can be assumed by codebuild service with the proper permissions and this role should then be attached in the aws codebuild.

using the jq library we fetch the secret name according to the environment available, here the "environment" is set in the aws codebuild codepipeline.

after getting the secret name we fetch all the secrets key value pairs in a .env file in the root directory and then proceed to the build step.

๐Ÿ•ต๏ธโ€โ™‚๏ธ Step 3: The Dynamic Duo: CodeBuild and AWS Secret Manager

AWS Secret Manager shines in the pre_build stage. Leveraging its power, we fetch environment variables securely, ensuring our secrets are seamlessly integrated into the build process. This dynamic approach allows for flexibility across different environments.

In the build step we install the required libraries using npm install and then build using npm run build.

๐Ÿ—๏ธ Step 4: Building, Deploying, and Invalidating

As we move into the build stage, we specify the actual build steps required for our React app. In the post_build stage, the /out directory โ€“ containing static files generated by Next.js โ€“ is synced with the S3 bucket designated for the specific environment. But the magic doesn't end there; we dynamically fetch and invalidate the CloudFront distribution, ensuring our CDN is always up to date with the latest content.

this postbuild script dynamically fetches the bucket name and pushes the code to it and also fetches the distribution id dynamically and invalidates it too.

๐Ÿš€ Conclusion: Elevate Your CI/CD Experience

By combining the forces of AWS CodeBuild, CodePipeline, and Secret Manager, you're not just deploying an app โ€“ you're fortifying your CI/CD pipeline with security and dynamism. Feel free to extend this solution to your preferred CI/CD tools; the principles remain the same.

Embark on the journey of secure, dynamic, and efficient deployment with #aws_codebuild, #aws_codepipeline, #aws_secret_manager, and the power of AWS CloudFront. Your React app deserves nothing less than a seamless, secure, and engaging user experience! #aws_s3 #bash๐ŸŒŸ

Final Buildspec File:

version: 0.2
phases:
  install:
    runtime-versions:
      nodejs: 20
  pre_build: 
    commands:
      - echo "Setting ENV VARS for $environment environment"
      - sh scripts/pre_build.sh
  build:
    commands:
      - echo Installing Yarn
      - npm install yarn -g
      - yarn install 
      - echo "Building Frontend-$environment"
      - build_var="$(environment)"
      - yarn run build:$build_var
  post_build:
    commands:
      - echo "Sync to S3 Bucket & Cloudfront Invalidation"
      - sh scripts/post_build.sh

artifacts:
  files:
    - '**/*'
env:
  variables:
    AWS_DEFAULT_REGION: "us-east-2"
cache:
  paths:
    - 'node_modules/**/*'

pre_build.sh

#!/bin/bash
sudo apt install jq -y
secret_name="${environment}-frontend"
secret_json=$(aws secretsmanager get-secret-value --secret-id "$secret_name" --output text --query SecretString)
secret_dict=$(echo $secret_json | jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]')
echo "$secret_dict" > .env

post_build.sh

#!/bin/bash
bucket_name="${environment}.yourdomain.com"
aws s3 sync ./dist "s3://$bucket_name"
distribution_id=$(aws cloudfront list-distributions | jq -r '.DistributionList.Items[] | select(.Origins.Items[].Id == "'${bucket_name}'") | .Id')
aws cloudfront create-invalidation --distribution-id $distribution_id --paths "/*"

TL/DR

Use a single environment variable set in AWS Codepipeline-Codebuild to fetch secrets from AWS Secret Manager , build your application, push it to S3 and also invalidate the distribution dynamically using Codebuild itself.

ย