🚀 AWS EKS Infrastructure Automation

Production-Grade Kubernetes Cluster Deployment with IaC & CI/CD

AWS EKS Terraform GitHub Actions Kubernetes Docker Helm Monitoring
View on GitHub

📋 Project Overview

This project demonstrates a complete DevOps pipeline for deploying and managing a production-ready AWS EKS cluster using Infrastructure as Code (Terraform) and automated CI/CD workflows (GitHub Actions). The solution includes cluster provisioning, application deployment, monitoring setup, and automated testing.

🏗️

Infrastructure as Code

Complete EKS cluster defined in Terraform with modular, reusable components

🔄

CI/CD Pipeline

Automated deployment workflows with GitHub Actions for infrastructure and applications

🔒

Security Best Practices

IAM roles, RBAC, network policies, and secrets management

📊

Observability

Prometheus, Grafana, and CloudWatch integration for comprehensive monitoring

🏛️ Architecture

Developer
Push Code
GitHub
Trigger Actions
Terraform
Apply Infrastructure
AWS EKS
Deploy Applications

🛠️ Implementation Steps

1

Prerequisites & Initial Setup

  • AWS Account with appropriate permissions
  • AWS CLI configured with credentials
  • Terraform installed (v1.5+)
  • kubectl installed
  • GitHub repository created
Note: Configure AWS credentials as GitHub Secrets for the CI/CD pipeline.
# Install required tools
brew install terraform kubectl aws-cli helm

# Configure AWS CLI
aws configure

# Verify installations
terraform version
kubectl version --client
aws sts get-caller-identity
2

Terraform Configuration Structure

Create a modular Terraform configuration for the EKS cluster:

eks-terraform-pipeline/
├── terraform/
│   ├── environments/
│   │   ├── dev/
│   │   │   ├── main.tf
│   │   │   ├── variables.tf
│   │   │   └── terraform.tfvars
│   │   └── prod/
│   │       ├── main.tf
│   │       ├── variables.tf
│   │       └── terraform.tfvars
│   ├── modules/
│   │   ├── vpc/
│   │   │   ├── main.tf
│   │   │   ├── variables.tf
│   │   │   └── outputs.tf
│   │   ├── eks/
│   │   │   ├── main.tf
│   │   │   ├── variables.tf
│   │   │   ├── outputs.tf
│   │   │   └── irsa.tf
│   │   └── node-groups/
│   │       ├── main.tf
│   │       ├── variables.tf
│   │       └── outputs.tf
│   └── backend.tf
├── .github/
│   └── workflows/
│       ├── terraform-plan.yml
│       ├── terraform-apply.yml
│       └── app-deploy.yml
├── k8s/
│   ├── namespaces/
│   ├── deployments/
│   └── services/
└── monitoring/
    ├── prometheus/
    └── grafana/

Key Terraform Files:

backend.tf - Remote State Configuration:

terraform {
  backend "s3" {
    bucket         = "your-terraform-state-bucket"
    key            = "eks/terraform.tfstate"
    region         = "us-west-2"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}

modules/eks/main.tf - EKS Module:

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 19.0"

  cluster_name    = var.cluster_name
  cluster_version = var.cluster_version

  vpc_id     = var.vpc_id
  subnet_ids = var.private_subnets

  eks_managed_node_groups = {
    general = {
      desired_size = 2
      min_size     = 1
      max_size     = 4

      instance_types = ["t3.medium"]
      
      labels = {
        role = "general"
      }
    }
  }

  manage_aws_auth_configmap = true
  
  cluster_addons = {
    coredns = {
      most_recent = true
    }
    kube-proxy = {
      most_recent = true
    }
    vpc-cni = {
      most_recent = true
    }
  }
}
3

GitHub Actions Workflows

.github/workflows/terraform-plan.yml - PR Validation:

name: Terraform Plan

on:
  pull_request:
    paths:
      - 'terraform/**'

env:
  TF_VERSION: '1.5.0'
  AWS_REGION: 'us-west-2'

jobs:
  terraform-plan:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: Terraform Init
        run: |
          cd terraform/environments/dev
          terraform init

      - name: Terraform Format Check
        run: terraform fmt -check -recursive

      - name: Terraform Validate
        run: |
          cd terraform/environments/dev
          terraform validate

      - name: Terraform Plan
        run: |
          cd terraform/environments/dev
          terraform plan -out=tfplan

      - name: Comment PR
        uses: actions/github-script@v6
        with:
          script: |
            const fs = require('fs');
            const plan = fs.readFileSync('terraform/environments/dev/tfplan', 'utf8');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '### Terraform Plan Results\n\n' + plan
            });

.github/workflows/terraform-apply.yml - Infrastructure Deployment:

name: Terraform Apply

on:
  push:
    branches:
      - main
    paths:
      - 'terraform/**'

jobs:
  terraform-apply:
    runs-on: ubuntu-latest
    environment: production
    
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-west-2

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2

      - name: Terraform Init
        run: |
          cd terraform/environments/prod
          terraform init

      - name: Terraform Apply
        run: |
          cd terraform/environments/prod
          terraform apply -auto-approve

      - name: Update kubeconfig
        run: |
          aws eks update-kubeconfig --region us-west-2 --name production-eks-cluster

      - name: Deploy Monitoring Stack
        run: |
          helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
          helm repo add grafana https://grafana.github.io/helm-charts
          helm repo update
          
          kubectl create namespace monitoring || true
          
          helm upgrade --install prometheus prometheus-community/kube-prometheus-stack \
            --namespace monitoring \
            --set grafana.adminPassword=${{ secrets.GRAFANA_PASSWORD }}
4

Application Deployment Workflow

.github/workflows/app-deploy.yml - Deploy Sample Application:

name: Deploy Application

on:
  push:
    branches:
      - main
    paths:
      - 'app/**'
      - 'k8s/**'

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-west-2

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Build, tag, and push image to Amazon ECR
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: sample-app
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG ./app
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

      - name: Update kubeconfig
        run: |
          aws eks update-kubeconfig --region us-west-2 --name production-eks-cluster

      - name: Deploy to EKS
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          kubectl set image deployment/sample-app \
            sample-app=$ECR_REGISTRY/sample-app:$IMAGE_TAG \
            -n default
          
          kubectl rollout status deployment/sample-app -n default
5

Security & Best Practices Implementation

  • IRSA (IAM Roles for Service Accounts): Configure pod-level AWS permissions
  • Network Policies: Implement Calico or AWS Security Groups for Pods
  • Secrets Management: Use AWS Secrets Manager with External Secrets Operator
  • RBAC: Define Kubernetes roles and role bindings
  • Pod Security Standards: Enforce security policies

Example RBAC Configuration:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: ServiceAccount
  name: pod-reader
  namespace: default
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
6

Testing & Validation

Success Criteria:
  • EKS cluster successfully provisioned via GitHub Actions
  • Worker nodes registered and ready
  • Sample application deployed and accessible
  • Monitoring stack operational (Prometheus/Grafana)
  • Automated rollback on deployment failure

Validation Commands:

# Check cluster status
kubectl get nodes
kubectl get pods --all-namespaces

# Verify application deployment
kubectl get deployments
kubectl get services

# Check monitoring
kubectl get pods -n monitoring

# Test application endpoint
kubectl port-forward svc/sample-app 8080:80
curl http://localhost:8080

# View Grafana dashboard
kubectl port-forward -n monitoring svc/prometheus-grafana 3000:80

🎯 Key Achievements

📚 Repository Structure

The complete project repository includes:

💡 Skills Demonstrated

This project showcases proficiency in: