Perplexity ‐ Packer and HashiCorp Vault - sathishkpr/ptactions GitHub Wiki

Automating AWS Infrastructure with HashiCorp Packer, GitHub Actions, and Vault for Secure Auto-Scaling

This report provides a technical blueprint for implementing a secure infrastructure automation pipeline that combines HashiCorp Packer for machine image creation, GitHub Actions for workflow orchestration, HashiCorp Vault for credential management, and AWS Auto Scaling for dynamic resource provisioning. The solution addresses the challenge of securely deploying auto-scaled EC2 instances while maintaining strict control over sensitive credentials. Key innovations include the integration of Vault-managed AWS keys into GitHub Actions workflows and the automated propagation of Packer-generated AMIs to Terraform-managed auto-scaling groups.


Architecture Overview

GitHub Actions as the Orchestration Engine

GitHub Actions serves as the central workflow controller, coordinating the image-building process with Packer, credential retrieval from Vault, and infrastructure updates via Terraform. The hashicorp/setup-packer Action ensures proper CLI versioning and execution environment configuration[1]. Workflows are triggered by code changes to Packer templates or infrastructure definitions, enabling continuous integration of both application and infrastructure components.

The pipeline structure follows a phased approach:

  1. Image Construction: Packer executes provisioning scripts against a base AWS AMI
  2. Secret Injection: Vault provides temporary AWS credentials via authenticated API calls
  3. Validation & Publishing: Built images undergo automated testing before registration in AWS
  4. Infrastructure Synchronization: Terraform applies updated launch templates referencing new AMIs

Secure Credential Management with Vault

Vault-GitHub Actions Integration

The hashicorp/vault-action enables secure retrieval of AWS credentials without persistent secrets in GitHub repositories[8]. A dedicated Vault authentication path for GitHub workflows uses JWT tokens from GitHub's OIDC provider to generate short-lived AWS credentials:

- name: Retrieve AWS Credentials
  uses: hashicorp/vault-action@v2
  with:
    url: https://vault.prod.example.com
    method: jwt
    role: github-actions-packer
    secrets: |
      aws/creds/packer-role access_key | AWS_ACCESS_KEY_ID 
      aws/creds/packer-role secret_key | AWS_SECRET_ACCESS_KEY

This configuration maps Vault-generated AWS credentials to environment variables used by subsequent workflow steps. The AWS credentials are automatically revoked after 15 minutes, complying with zero-trust security principles[9].


Packer Image Build Automation

Template Configuration with Dynamic Credentials

Packer templates consume AWS credentials from environment variables set by the GitHub Actions workflow:

source "amazon-ebs" "web-server" {
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
  region     = "us-west-2"
  
  ami_name = "web-server-${local.timestamp}"
  instance_type = "t3.micro"
}

build {
  sources = ["source.amazon-ebs.web-server"]
  
  provisioner "shell" {
    script = "scripts/configure-nginx.sh"
  }
}

The workflow securely injects credentials using Vault-derived environment variables:

- name: Build AMI
  run: packer build -var aws_access_key=${{ env.AWS_ACCESS_KEY_ID }} -var aws_secret_key=${{ env.AWS_SECRET_ACCESS_KEY }} web-server.pkr.hcl

Critical security practices include:

  1. Ephemeral Credentials: AWS keys are valid only for the workflow duration
  2. Least Privilege: Vault role restricts Packer to specific EC2 and AMI operations
  3. Audit Trail: Vault logs all credential issuance events

Auto-Scaling Integration

Terraform Infrastructure as Code

The Terraform configuration manages auto-scaling groups and launch templates referencing Packer-built AMIs:

data "aws_ami" "web_server" {
  most_recent = true
  owners      = ["self"]

  filter {
    name   = "name"
    values = ["web-server-*"]
  }
}

resource "aws_launch_template" "web" {
  name_prefix   = "web-"
  image_id      = data.aws_ami.web_server.id
  instance_type = "t3.micro"
}

resource "aws_autoscaling_group" "web" {
  availability_zones = ["us-west-2a"]
  desired_capacity   = 2
  max_size           = 5
  min_size           = 1

  launch_template {
    id      = aws_launch_template.web.id
    version = "$Latest"
  }
}

End-to-End Workflow Implementation

Phase 1: Image Build Pipeline

name: Packer Build
on:
  push:
    paths:
      - 'packer/*.pkr.hcl'
      - 'scripts/**'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Packer
        uses: hashicorp/setup-packer@main
        
      - name: Get AWS Credentials
        uses: hashicorp/vault-action@v2
        id: vault
        with:
          url: https://vault.example.com
          method: jwt
          role: packer-builder
          exportEnv: true
          secrets: |
            aws/creds/packer access_key | AWS_ACCESS_KEY_ID
            aws/creds/packer secret_key | AWS_SECRET_ACCESS_KEY
            
      - name: Build Image
        run: packer build web-server.pkr.hcl
        
      - name: Output AMI ID
        id: ami
        run: echo "AMI_ID=$(jq -r '.builds[-1].artifact_id' manifest.json | cut -d':' -f2)" >> $GITHUB_OUTPUT

Phase 2: Infrastructure Update

name: Terraform Deploy
on:
  workflow_run:
    workflows: ["Packer Build"]
    types:
      - completed

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2
        
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v3
        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: Terraform Apply
        run: terraform apply -auto-approve

Security Architecture

Credential Lifecycle Management

  1. Vault Authentication: GitHub Actions authenticates via OIDC JWT tokens
  2. Dynamic Secrets: AWS credentials generated per-run with 15-minute TTL
  3. Automatic Rotation: Vault's AWS secrets engine rotates underlying IAM keys
  4. Network Security: Vault communication over TLS with IP whitelisting
# Vault AWS Secrets Engine Configuration
resource "vault_aws_secret_backend" "aws" {
  access_key = var.vault_aws_access_key
  secret_key = var.vault_aws_secret_key
}

resource "vault_aws_secret_backend_role" "packer" {
  backend = vault_aws_secret_backend.aws.path
  name    = "packer"
  
  credential_type = "iam_user"
  policy_document = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect   = "Allow"
      Action   = ["ec2:*", "iam:*"]
      Resource = "*"
    }]
  })
}

Auto-Scaling Pattern Implementation

Dynamic Instance Configuration

New auto-scaled instances retrieve runtime configuration from Vault using IAM instance profiles:

#!/bin/bash
VAULT_ADDR="https://vault.example.com"

# Retrieve instance identity document
PKCS7=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/pkcs7 | tr -d '\n')

# Get Vault token using AWS auth method
VAULT_TOKEN=$(curl -s -X POST $VAULT_ADDR/v1/auth/aws/login \
  -d "{\"role\":\"web-server\", \"pkcs7\":\"$PKCS7\"}" | jq -r .auth.client_token)

# Retrieve application secrets
APP_CONFIG=$(curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
  $VAULT_ADDR/v1/secret/data/web/config | jq -r .data.data)

This pattern enables:

  1. Zero Hardcoded Secrets: Credentials never persist on disk
  2. Automatic Secret Rotation: Vault manages credential lifecycle
  3. Instance-Specific Permissions: IAM roles restrict Vault access per ASG

Operational Monitoring

Cross-Tool Observability

  1. Vault Audit Logs: Track all credential access attempts
  2. AWS CloudTrail: Monitor API calls from Packer and Terraform
  3. GitHub Actions Logging: Centralized workflow execution history
  4. Prometheus Metrics:
    • Packer build durations
    • AMI deployment velocity
    • Auto-scaling group fluctuation rates
resource "aws_cloudtrail" "packer" {
  name           = "packer-ami-creation"
  s3_bucket_name = aws_s3_bucket.audit_logs.id
  event_selector {
    read_write_type           = "WriteOnly"
    include_management_events = true

    data_resource {
      type   = "AWS::EC2::Image"
      values = ["arn:aws:ec2:::image/*"]
    }
  }
}

Conclusion

This implementation establishes a secure, automated pipeline for AWS infrastructure management that addresses key cloud security challenges. By integrating Vault's dynamic credential management with GitHub Actions' workflow automation and Packer's image-building capabilities, organizations achieve:

  1. Auditable Secret Lifecycle: All AWS credential usage tracked in Vault logs
  2. Immutable Infrastructure: Packer-built AMIs enable consistent deployments
  3. Elastic Scaling: Terraform-managed ASGs automatically adjust to load
  4. Developer Velocity: Full CI/CD pipeline for infrastructure changes

Future enhancements could incorporate HashiCorp Consul for service mesh integration and Nomad for workload orchestration, creating a complete HashiStack solution. The architecture demonstrates how modern DevOps tools combine to create secure, self-healing cloud infrastructure.

Citations: [1] https://github.com/hashicorp/setup-packer [2] https://serverfault.com/questions/1085387/run-github-actions-workflow-ec2-auto-scaled-servers [3] https://github.com/hashicorp-modules/hashistack-aws [4] https://developer.hashicorp.com/packer/tutorials/cloud-production/github-actions [5] https://www.ingeniumcode.io/cicd-github-actions-separate-workflows/ [6] https://www.ivobeerens.nl/blog/2024/06/pass-github-variable-to-packer-powershell-provisioner/ [7] https://github.com/hashicorp/terraform-aws-vault [8] https://developer.hashicorp.com/vault/tutorials/app-integration/github-actions [9] https://austincloud.guru/2021/03/01/secrets-in-aws-user_data-via-hashicorp's-vault/ [10] https://dev.to/aws-builders/using-github-actions-to-build-packer-ami-on-aws-3p12 [11] https://github.com/aws-samples/ec2-auto-scaling-instance-refresh-sample [12] https://www.infralovers.com/blog/2024-10-17-hashicorp-packer-github-actions/ [13] https://repost.aws/questions/QUIPP5MKaNRpmpQNhiAFFh5g/create-new-ami-only-on-updates [14] https://developer.hashicorp.com/vault/docs/platform/github-actions [15] https://github.com/hashicorp/vault-action [16] https://www.reddit.com/r/hashicorp/comments/1hzz3r4/access_secrets_from_hashicorp_vault_in_github/ [17] https://codemyworld.hashnode.dev/packer-to-create-ami-golden-image-in-aws [18] https://www.reddit.com/r/hashicorp/comments/17s5auo/vaultaction_in_github_actions/ [19] https://www.youtube.com/watch?v=Vl5dO3EzNJ0 [20] https://github.com/hashicorp/packer/blob/master/website/content/docs/templates/hcl_templates/functions/contextual/vault.mdx [21] https://github.com/daveshepherd/packer-vault [22] https://github.com/giuliocalzolari/terraform-aws-vault-raft [23] https://www.youtube.com/watch?v=eN8QQCLrpyE [24] https://registry.terraform.io/modules/giuliocalzolari/vault-raft/aws/latest [25] https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/automatically-rotate-iam-user-access-keys-at-scale-with-aws-organizations-and-aws-secrets-manager.html [26] https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/create-a-pipeline-and-ami-using-codepipeline-and-hashicorp-packer.html [27] https://faun.pub/serverless-packer-ami-build-ci-cd-and-asg-instance-refresh-9851c211310e [28] https://aws.amazon.com/blogs/devops/best-practices-working-with-self-hosted-github-action-runners-at-scale-on-aws/ [29] https://github.com/hashicorp-modules/vault-aws [30] https://github.com/hashicorp/terraform-aws-vault/blob/master/modules/vault-cluster/README.md [31] https://stackoverflow.com/questions/61455092/terraform-autoscaling-listen-for-new-ami-and-deploy-automatically [32] https://www.reddit.com/r/aws/comments/zukahi/ec2_auto_scaling_deployment_options/ [33] https://github.com/jonico/auto-scaling-github-runners-ec2-issueops/blob/master/README.md