Architecting Automated Deployment: CI/CD Pipelines with GitHub Actions and AWS

The acceleration of software delivery cycles has moved from a competitive advantage to an operational necessity. Modern development teams no longer manually compile, test, and deploy code; they engineer automated pipelines that bridge the gap between version control and production environments. This process, known as a Continuous Integration and Continuous Delivery (CI/CD) pipeline, addresses a fundamental engineering question: how can features be shipped to production faster without sacrificing quality? By automating the build, test, and deployment stages, organizations achieve repeatable builds and rapid feature delivery. This article details the architectural implementation of a CI/CD pipeline using GitHub Actions for orchestration and Amazon Web Services (AWS) for infrastructure hosting, covering both serverless platform options like Elastic Beanstalk and infrastructure-as-a-service options like EC2.

Foundations of CI/CD and GitHub Actions

To engineer an effective pipeline, one must first demystify the terminology. A CI/CD pipeline is a development practice designed to hasten the feature release process. Without automation, each step in the delivery cycle—coding, building, testing, and deploying—is performed manually, introducing latency and human error. Continuous Integration (CI) focuses on automatically running builds and tests to catch bugs early. Continuous Delivery (CD) ensures that validated code is automatically deployed to the target environment.

GitHub Actions serves as the orchestration engine for this workflow. It provides a platform where every push to a repository can trigger a sequence of automated jobs. AWS, specifically services like Elastic Beanstalk and EC2, provides the destination infrastructure. The integration allows developers to commit code, which triggers GitHub Actions to build the application and push it to the cloud.

Configuring AWS Infrastructure for Deployment

Before establishing the pipeline, the target infrastructure must be provisioned. Two primary architectural patterns emerge from the reference materials: using AWS Elastic Beanstalk for platform-as-a-service deployment, or using Amazon EC2 for infrastructure-as-a-service deployment.

Provisioning an EC2 Instance

For direct infrastructure control, an Amazon EC2 instance is launched via the AWS Console. The configuration requires specific parameters to ensure security and functionality:

  • Name: MyStaticSite
  • AMI: Amazon Linux 2 (recommended for AWS native compatibility)
  • Instance Type: t2.micro (eligible for the AWS Free Tier)
  • Key Pair: Create or use an existing .pem file for SSH access
  • Security Group: Must allow inbound traffic on Port 22 (SSH) and Port 80 (HTTP)

After launching the instance, the private key file must be secured on the local machine.

bash mv ~/Downloads/your-key.pem ~/.ssh/ chmod 400 ~/.ssh/your-key.pem

To connect to the instance, use SSH with the private key. For Amazon Linux 2, the default user is ec2-user. For Ubuntu-based AMIs, the default user is ubuntu.

bash ssh -i ~/.ssh/your-key.pem ec2-user@your-ec2-public-ip

Configuring the Web Server

Once connected, the web server must be installed and configured to serve static content. The package manager commands differ based on the operating system.

For Amazon Linux 2:
bash sudo yum update -y sudo yum install -y httpd sudo systemctl start httpd sudo systemctl enable httpd sudo chown ec2-user /var/www/html

For Ubuntu:
bash sudo apt update sudo apt install -y apache2 sudo systemctl start apache2 sudo systemctl enable apache2 sudo chown ubuntu /var/www/html

Verification is performed by opening the EC2 instance's public IP in a web browser. The default Apache test page confirms the server is running correctly.

Establishing the GitHub Actions Workflow

With the infrastructure ready, the CI/CD automation is defined within a YAML workflow file located at .github/workflows/deploy.yml. This file instructs GitHub Actions how to build and deploy the code.

The workflow is triggered on pushes to the default branch (typically main or master). The job runs on an ubuntu-latest runner and utilizes the appleboy/scp-action to securely transfer files to the EC2 instance via SCP.

yaml name: Deploy to EC2 on: push: branches: - main # or 'master', based on your repo’s default branch jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 - name: Copy files via SCP uses: appleboy/[email protected] with: host: ${{ secrets.EC2_HOST }} username: ${{ secrets.EC2_USER }} key: ${{ secrets.EC2_KEY }} source: "index.html" target: "/var/www/html"

Managing Secrets and Security

Security is paramount in CI/CD pipelines. Sensitive credentials, such as the EC2 host IP, username, and private key content, must not be hardcoded in the YAML file. Instead, they are stored as encrypted repository secrets in GitHub.

Navigate to the repository settings and add the following secrets:
- EC2_HOST: The public IP or DNS of the EC2 instance.
- EC2_USER: The SSH username (ec2-user for Amazon Linux, ubuntu for Ubuntu).
- EC2_KEY: The content of the private .pem key file.

For production environments, AWS recommends using IAM roles or session-based credentials instead of static keys, as GitHub Secrets, while encrypted, represent a single point of failure if compromised.

Advanced Pipeline Automation with AWS CDK

For teams requiring more sophisticated pipeline definitions, AWS provides the aws-codepipeline-cicd sample repository. This pattern uses AWS Cloud Development Kit (CDK) v2 to define the infrastructure and pipeline as code. This approach ensures that the deployment process adheres to DevOps best practices, including automated security validation of third-party libraries.

Implementing the CDK Pipeline

To utilize this pattern, clone the sample repository and prepare it for deployment.

bash git clone --depth 1 https://github.com/aws-samples/aws-codepipeline-cicd.git cd ./aws-codepipeline-cicd rm -rf ./.git

The rm -rf ./.git command removes the original git history because the pipeline will utilize an AWS CodeCommit repository as the new remote origin.

Bootstrapping and Deployment

Before deploying, the environment must be bootstrapped. This process sets up the necessary AWS resources for CDK deployments.

```bash
AWSREGION="eu-west-1"
ACCOUNT
NUMBER=$(aws sts get-caller-identity --query Account --output text)
echo "${ACCOUNT_NUMBER}"

npm install
npm run build
npm run cdk bootstrap "aws://${ACCOUNTNUMBER}/${AWSREGION}"
```

A successful bootstrap outputs a confirmation message. Next, synthesize the CDK application to generate the CloudFormation template.

bash npm run cdk synth

Finally, deploy the CodePipeline stack. This action creates the automated pipeline that handles testing, building, and releasing code changes to the desired environment. This method accelerates the use of CI/CD pipelines while ensuring that deployed resources adhere to strict security and operational standards.

Conclusion

The integration of GitHub Actions with AWS infrastructure represents a maturation of development workflows. By automating the transition from code commit to production deployment, teams eliminate manual bottlenecks and reduce the risk of human error. Whether deploying a simple static site to EC2 via SCP or utilizing AWS CDK for fully automated CodePipeline structures, the core objective remains consistent: rapid, reliable, and secure feature delivery. As organizations scale, the shift from manual processes to automated CI/CD pipelines is not merely an efficiency gain but a structural requirement for modern software engineering.

Sources

  1. How to setup a CI/CD pipeline with GitHub Actions and AWS
  2. CI/CD for Beginners: Deploy a Static HTML Site to AWS EC2 with GitHub Actions
  3. AWS CodePipeline CI/CD Sample

Related Posts