Cloud 16 min read

AWS CLI First #17: Zero-Secret CI/CD: Automating AWS Deployments with GitHub Actions & OIDC

Eliminate long-lived access keys in CI/CD: configure AWS IAM OpenID Connect (OIDC) identity provider, craft least-privilege trust policies for GitHub Actions, build an automated deployment pipeline, validate templates with cfn-lint, and invalidate CloudFront CDN caches from the terminal.

Mohammad Rizky Prawira portrait
Mohammad Rizky Prawira
terminal Series Guide • Part 17 of 17

AWS with CLI: The Terminal-First Mastery Path

Part of the CLI-first comprehensive learning path from foundational setup to production cloud architectures.

Welcome to the grand finale of AWS with CLI: The Terminal-First Mastery Path.

Across the first 16 parts of this series, we designed, provisioned, hardened, and orchestrated production-grade AWS infrastructure without ever opening the AWS Management Console. We conquered VPC networking, multi-tier compute fleets, auto-scaling, distributed storage, managed databases, containers, serverless microservices, and declarative CloudFormation stacks.

However, in modern cloud engineering, running deployment commands manually from an engineer’s personal terminal workstation—even via scripted CLI—creates a production bottleneck. Production deployments must happen reliably, repeatably, and automatically through a Continuous Integration and Continuous Deployment (CI/CD) pipeline.

Yet, traditional CI/CD pipelines introduce one of the most critical security liabilities in cloud security: storing long-lived IAM Access Keys (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) as static GitHub repository secrets.

If a repository secret is compromised, leaked through a malicious pull request, or printed to build logs, attackers gain persistent, unrestricted access to your AWS infrastructure.

The modern cloud-native solution is OpenID Connect (OIDC) Federated Identity. With OIDC, your GitHub Actions runner exchanges a cryptographically signed, short-lived JSON Web Token (JWT) directly with AWS Security Token Service (STS) via sts:AssumeRoleWithWebIdentity. Zero static credentials are stored anywhere.

In this capstone guide, we will:

  1. Register GitHub as an IAM OIDC Identity Provider purely from the AWS CLI.
  2. Craft a mathematically locked-down IAM Role Trust Policy scoped exclusively to your GitHub organization, repository, and branch.
  3. Attach least-privilege deployment policies for CloudFormation, S3, and CloudFront.
  4. Construct a production GitHub Actions workflow (.github/workflows/deploy.yml) that authenticates via OIDC, runs cfn-lint, executes CloudFormation deployments, and invalidates CloudFront CDN caches.
  5. Provide an automated teardown script and review the entire 17-part architect journey.

💰 Estimated Lab Cost & Security Architecture

1. Cost Breakdown for this Lab

All services configured in this capstone lab run within the AWS and GitHub Free Tiers:

ResourceQuantityUnit Cost (Hourly)Estimated Lab Cost (1 Hour)
AWS IAM OIDC Identity Provider1 ProviderFree AWS Service$0.000
AWS STS Token ExchangeAPI CallsFree AWS Feature$0.000
IAM Roles & Trust Policies1 RoleFree AWS Feature$0.000
GitHub Actions Runner (Linux)~5 Build MinsGitHub Free Tier (2,000 min/mo)$0.000
CloudFront Invalidation1 InvalidationFirst 1,000 paths/mo free$0.000
Total Estimated Lab Cost~$0.000 USD (100% Free)

2. Zero-Secret OIDC Architecture Diagram

+----------------------------------------------------------------+
|           GitHub Actions OIDC Authentication & Deploy           |
+-------------------------------+--------------------------------+
                                |
                                v
+----------------------------------------------------------------+
| GitHub Actions Runner (Workflow Job)                           |
|  1. Requests signed OIDC JSON Web Token (JWT) from GitHub OIDC |
|  2. Token contains claims: sub (repo:org/app:ref:refs/heads/..)|
+-------------------------------+--------------------------------+
                                |
                                | [1] Send JWT (sts:AssumeRoleWithWebIdentity)
                                v
+----------------------------------------------------------------+
| AWS Security Token Service (STS)                               |
|  - Validates GitHub OIDC CA Thumbprint                         |
|  - Evaluates IAM Role Trust Policy (Audience & Subject Match)  |
|  - Issues Ephemeral Credentials (AWS_SESSION_TOKEN, 1 hour max)|
+-------------------------------+--------------------------------+
                                |
                                | [2] Return Temporary STS Credentials
                                v
+----------------------------------------------------------------+
| GitHub Actions Runner with Temporary AWS Credentials           |
|  3. aws cloudformation deploy (Declarative Stack Rollout)      |
|  4. aws s3 sync dist/ s3://bucket (Static Asset Upload)        |
|  5. aws cloudfront create-invalidation (Global Edge Refresh)   |
+----------------------------------------------------------------+

🛡️ Why Static Access Keys in CI/CD Are an Anti-Pattern

Before writing code, let’s examine why every major security benchmark (including CIS AWS Foundations and AWS Well-Architected Framework) strongly condemns storing static access keys in CI/CD:

VectorStatic Access Keys (AKIA...)OIDC Federated Identity
Credential LifetimePermanent (until manually rotated)Ephemeral (typically 15–60 minutes)
Storage LocationPlaintext secret in GitHub repository settingsNever stored anywhere; minted in memory
Rotation MechanismManual, error-prone, frequently ignoredAutomatic per workflow run by AWS STS
Fork/PR ExploitationIf compromised, attacker has full off-site accessScoped to specific repo, branch, or environment
Audit TrailCloudTrail shows fixed IAM user activityCloudTrail logs exact GitHub run ID, commit, and repo

🔧 Step 1: Discovering & Registering the GitHub OIDC Provider via CLI

GitHub exposes its OpenID Connect discovery document at https://token.actions.githubusercontent.com/.well-known/openid-configuration.

AWS IAM requires:

  1. The Provider URL: https://token.actions.githubusercontent.com
  2. The Client ID / Audience: sts.amazonaws.com
  3. The Server Certificate Thumbprint: The SHA-1 hash of the OIDC identity provider’s root/intermediate CA certificate.

1. Extract the CA Thumbprint via OpenSSL and CLI

AWS accepts GitHub’s official intermediate root certificate thumbprints. You can calculate it directly in your terminal using openssl:

# Retrieve GitHub's OIDC certificate thumbprint
THUMBPRINT=$(echo | openssl s_client -servername token.actions.githubusercontent.com \
  -showcerts -connect token.actions.githubusercontent.com:443 2>/dev/null \
  | awk '/-----BEGIN CERTIFICATE-----/{cert=""} {cert=cert $0 "\n"} /-----END CERTIFICATE-----/{last=cert} END{printf "%s", last}' \
  | openssl x509 -fingerprint -noout -sha1 \
  | tr -d ':' | tr '[:upper:]' '[:lower:]' | cut -d'=' -f2)

echo "GitHub Actions OIDC Thumbprint: ${THUMBPRINT}"

[!TIP] GitHub Actions OIDC utilizes two canonical thumbprints verified by AWS: 6938fd4d98bab03faadb97b34396831e3780aea1 and 1c58a3a8518e8759bf075b76b750d4f2df264fcd. AWS IAM now automatically validates GitHub’s certificates, but supplying the thumbprint remains mandatory in the CLI API.

2. Create the OpenID Connect Provider

Let’s check if the provider already exists in your AWS account to maintain idempotency:

EXISTING_PROVIDER_ARN=$(aws iam list-open-id-connect-providers \
  --query "OpenIDConnectProviderList[?contains(Arn, 'token.actions.githubusercontent.com')].Arn" \
  --output text)

if [ -z "$EXISTING_PROVIDER_ARN" ]; then
  echo "Creating GitHub Actions OIDC Provider..."
  PROVIDER_ARN=$(aws iam create-open-id-connect-provider \
    --url "https://token.actions.githubusercontent.com" \
    --client-id-list "sts.amazonaws.com" \
    --thumbprint-list "6938fd4d98bab03faadb97b34396831e3780aea1" "1c58a3a8518e8759bf075b76b750d4f2df264fcd" \
    --query "OpenIDConnectProviderArn" \
    --output text)
  echo "OIDC Provider Created: ${PROVIDER_ARN}"
else
  echo "GitHub OIDC Provider already exists: ${EXISTING_PROVIDER_ARN}"
  PROVIDER_ARN="${EXISTING_PROVIDER_ARN}"
fi

3. Verify the OIDC Provider Configuration

aws iam get-open-id-connect-provider \
  --open-id-connect-provider-arn "${PROVIDER_ARN}" \
  --output json

Terminal Output:

{
    "Url": "token.actions.githubusercontent.com",
    "ClientIDList": [
        "sts.amazonaws.com"
    ],
    "ThumbprintList": [
        "6938fd4d98bab03faadb97b34396831e3780aea1",
        "1c58a3a8518e8759bf075b76b750d4f2df264fcd"
    ],
    "CreateDate": "2026-09-13T01:15:22.000Z"
}

🔐 Step 2: Crafting the Cryptographically Scoped IAM Trust Policy

The security of OIDC rests entirely on the IAM Role Trust Policy. If you write a permissive trust policy without filtering claims, any developer with a GitHub account could assume your AWS IAM role.

1. Understanding GitHub OIDC JWT Claims

When a GitHub Actions runner executes, its OIDC token includes standard claims:

  • aud: Audience, always sts.amazonaws.com.
  • iss: Issuer, https://token.actions.githubusercontent.com.
  • sub: Subject identifier in the format repo:<org>/<repo>:ref:refs/heads/<branch> or repo:<org>/<repo>:environment:<env>.

2. Define Trust Policy Variables

Replace YOUR_GITHUB_ORG and YOUR_GITHUB_REPO with your actual GitHub username/organization and repository name:

GITHUB_ORG="rizkyprawira"
GITHUB_REPO="production-cloud-app"
DEPLOY_BRANCH="main"
ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
ROLE_NAME="GitHubActionsDeployerRole"

3. Generate the Secure Trust Policy JSON

We enforce two conditions:

  1. StringEquals: The audience must strictly match sts.amazonaws.com.
  2. StringLike: The subject must originate only from the main branch of rizkyprawira/production-cloud-app.
cat <<EOF > trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:${GITHUB_ORG}/${GITHUB_REPO}:ref:refs/heads/${DEPLOY_BRANCH}"
        }
      }
    }
  ]
}
EOF

[!WARNING] Never use "token.actions.githubusercontent.com:sub": "*" in production! Wildcarding the subject claim permits any repository hosted on GitHub to assume this IAM role and seize control of your AWS account.

4. Create the Deployment IAM Role

aws iam create-role \
  --role-name "${ROLE_NAME}" \
  --assume-role-policy-document file://trust-policy.json \
  --description "Federated role for GitHub Actions CI/CD deployments via OIDC" \
  --query "Role.[RoleName, Arn]" \
  --output table

Terminal Output:

---------------------------------------------------------------------------------------------------------
|                                              CreateRole                                               |
+--------------------------+----------------------------------------------------------------------------+
|  GitHubActionsDeployerRole| arn:aws:iam::123456789012:role/GitHubActionsDeployerRole                   |
+--------------------------+----------------------------------------------------------------------------+

📜 Step 3: Attaching Least-Privilege Deployment Policies

Our CI/CD pipeline needs permission to:

  1. Validate and deploy CloudFormation stacks (cloudformation:*).
  2. Sync compiled frontend bundles to S3 (s3:PutObject, s3:ListBucket).
  3. Invalidate CloudFront edge distribution caches (cloudfront:CreateInvalidation).

Let’s craft a scoped inline policy:

cat <<EOF > cicd-permissions-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CloudFormationDeployment",
      "Effect": "Allow",
      "Action": [
        "cloudformation:CreateStack",
        "cloudformation:UpdateStack",
        "cloudformation:DescribeStacks",
        "cloudformation:DescribeStackEvents",
        "cloudformation:CreateChangeSet",
        "cloudformation:DescribeChangeSet",
        "cloudformation:ExecuteChangeSet",
        "cloudformation:GetTemplateSummary"
      ],
      "Resource": "arn:aws:cloudformation:*:${ACCOUNT_ID}:stack/production-*/*"
    },
    {
      "Sid": "S3AssetSync",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::production-web-assets-*",
        "arn:aws:s3:::production-web-assets-*/*"
      ]
    },
    {
      "Sid": "CloudFrontCacheInvalidation",
      "Effect": "Allow",
      "Action": [
        "cloudfront:CreateInvalidation",
        "cloudfront:GetInvalidation"
      ],
      "Resource": "*"
    }
  ]
}
EOF

# Attach the policy to our deployment role
aws iam put-role-policy \
  --role-name "${ROLE_NAME}" \
  --policy-name "GitHubActionsDeploymentPolicy" \
  --policy-document file://cicd-permissions-policy.json

Verify that the policy is attached:

aws iam list-role-policies \
  --role-name "${ROLE_NAME}" \
  --output text

🚀 Step 4: Crafting the Production GitHub Actions Workflow

Now let’s build the complete, production-ready GitHub Actions workflow file: .github/workflows/deploy.yml.

1. Key Workflow Directives

  1. permissions: id-token: write: This is mandatory. Without this permission, the GitHub runner cannot request an OIDC token from GitHub’s token endpoint.
  2. aws-actions/configure-aws-credentials@v4: Official AWS action that handles the OIDC handshake, sends the JWT to STS, and exports standard AWS environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) into the runner environment.

2. Workflow Definition (.github/workflows/deploy.yml)

name: Production Deployment Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

# Grant minimal permissions required for OIDC token exchange and git checkout
permissions:
  id-token: write
  contents: read

env:
  AWS_REGION: ap-southeast-1
  ROLE_ARN: arn:aws:iam::123456789012:role/GitHubActionsDeployerRole
  STACK_NAME: production-vpc-infra

jobs:
  # ============================================================
  # Stage 1: Quality Gate & CloudFormation Linting
  # ============================================================
  validate-and-test:
    name: Lint & Validate Infrastructure
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Source Code
        uses: actions/checkout@v4

      - name: Set up Python for cfn-lint
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install CloudFormation Linter
        run: |
          pip install cfn-lint awscli

      - name: Run cfn-lint on CloudFormation Templates
        run: |
          echo "=== Linting CloudFormation Templates ==="
          cfn-lint infrastructure/**/*.yaml

      - name: Validate CloudFormation Syntax via AWS CLI
        run: |
          echo "=== Validating Template Structure ==="
          aws cloudformation validate-template \
            --template-body file://infrastructure/vpc-infrastructure.yaml \
            --region ${{ env.AWS_REGION }}

  # ============================================================
  # Stage 2: Zero-Secret AWS Deployment via OIDC
  # ============================================================
  deploy-production:
    name: Deploy to Production via OIDC
    needs: validate-and-test
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Source Code
        uses: actions/checkout@v4

      - name: Authenticate to AWS via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ env.ROLE_ARN }}
          aws-region: ${{ env.AWS_REGION }}
          audience: sts.amazonaws.com
          role-session-name: GitHubActions-${{ github.run_id }}

      - name: Verify STS Identity (Audit Verification)
        run: |
          echo "=== Verifying Ephemeral STS Identity ==="
          aws sts get-caller-identity --output table

      - name: Deploy CloudFormation Stack
        run: |
          echo "=== Deploying CloudFormation Stack ==="
          aws cloudformation deploy \
            --template-file infrastructure/vpc-infrastructure.yaml \
            --stack-name ${{ env.STACK_NAME }} \
            --parameter-overrides Environment=Production VPCCIDR=10.0.0.0/16 \
            --no-fail-on-empty-changeset \
            --region ${{ env.AWS_REGION }}

      - name: Invalidate CloudFront CDN Cache
        run: |
          DISTRIBUTION_ID=$(aws cloudformation describe-stacks \
            --stack-name ${{ env.STACK_NAME }} \
            --query "Stacks[0].Outputs[?OutputKey=='CloudFrontDistributionId'].OutputValue" \
            --output text 2>/dev/null || echo "")

          if [ -n "$DISTRIBUTION_ID" ] && [ "$DISTRIBUTION_ID" != "None" ]; then
            echo "=== Triggering CloudFront Cache Invalidation for ${DISTRIBUTION_ID} ==="
            INVALIDATION_ID=$(aws cloudfront create-invalidation \
              --distribution-id "${DISTRIBUTION_ID}" \
              --paths "/*" \
              --query "Invalidation.Id" \
              --output text)
            echo "Cache Invalidation Triggered: ${INVALIDATION_ID}"
          else
            echo "No CloudFront distribution output found; skipping invalidation."
          fi

🧪 Step 5: What Happens Under the Hood: The STS Handshake

To appreciate what aws-actions/configure-aws-credentials does, consider how AWS STS executes this exchange natively via the CLI.

When the GitHub runner starts:

  1. GitHub generates a signed JSON Web Token (JWT) using its private key:
    {
      "iss": "https://token.actions.githubusercontent.com",
      "aud": "sts.amazonaws.com",
      "sub": "repo:rizkyprawira/production-cloud-app:ref:refs/heads/main",
      "exp": 1726190400
    }
  2. The runner invokes the AWS STS endpoint:
    aws sts assume-role-with-web-identity \
      --role-arn "arn:aws:iam::123456789012:role/GitHubActionsDeployerRole" \
      --role-session-name "GitHubCI-Session" \
      --web-identity-token "$OIDC_JWT_TOKEN" \
      --duration-seconds 3600
  3. STS verifies GitHub’s public RSA signature against the registered OIDC provider thumbprints.
  4. STS checks if sub matches repo:rizkyprawira/production-cloud-app:ref:refs/heads/main.
  5. STS returns temporary AWS credentials:
    {
        "Credentials": {
            "AccessKeyId": "ASIAIOSFODNN7EXAMPLE",
            "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
            "SessionToken": "IQoJb3JpZ2luX2VjEOD...",
            "Expiration": "2026-09-13T02:15:22+00:00"
        },
        "SubjectFromWebIdentityToken": "repo:rizkyprawira/production-cloud-app:ref:refs/heads/main"
    }
  6. After 60 minutes, these credentials automatically expire into oblivion.

⚡ Step 6: Verifying Deployment Invalidation from the CLI

Once your pipeline deploys a new frontend build, you can inspect CloudFront invalidation status directly from your local terminal:

# List recent invalidations on your CloudFront distribution
aws cloudfront list-invalidations \
  --distribution-id "E2EXAMPLE12345" \
  --query "InvalidationList.Items[*].[Id, Status, CreateTime]" \
  --output table

Terminal Output:

--------------------------------------------------------------------------
|                            ListInvalidations                           |
+-----------------------+------------+-----------------------------------+
|  I1BEXAMPLE4567       |  Completed |  2026-09-13T01:32:10.512000+00:00 |
|  I2CEXAMPLE8901       |  InProgress|  2026-09-13T01:45:00.128000+00:00 |
+-----------------------+------------+-----------------------------------+

You can wait for completion using the CLI waiter:

aws cloudfront wait invalidation-completed \
  --distribution-id "E2EXAMPLE12345" \
  --id "I2CEXAMPLE8901"

echo "CloudFront global edge caches successfully invalidated!"

🧹 Step 7: Clean Teardown Script

To clean up all IAM roles, inline policies, and the OIDC identity provider created during this lab, save and run this script:

cat <<'EOF' > teardown-oidc.sh
#!/usr/bin/env bash
set -euo pipefail

ROLE_NAME="GitHubActionsDeployerRole"

echo "=== 1. Deleting Inline Role Policies ==="
POLICIES=$(aws iam list-role-policies --role-name "${ROLE_NAME}" --query "PolicyNames[]" --output text 2>/dev/null || echo "")
for policy in $POLICIES; do
  echo "Deleting policy: ${policy}..."
  aws iam delete-role-policy --role-name "${ROLE_NAME}" --policy-name "${policy}"
done

echo "=== 2. Deleting IAM Deployment Role ==="
if aws iam get-role --role-name "${ROLE_NAME}" >/dev/null 2>&1; then
  aws iam delete-role --role-name "${ROLE_NAME}"
  echo "Deleted role: ${ROLE_NAME}"
fi

echo "=== 3. Deleting GitHub OIDC Identity Provider ==="
PROVIDER_ARN=$(aws iam list-open-id-connect-providers \
  --query "OpenIDConnectProviderList[?contains(Arn, 'token.actions.githubusercontent.com')].Arn" \
  --output text 2>/dev/null || echo "")

if [ -n "$PROVIDER_ARN" ]; then
  aws iam delete-open-id-connect-provider --open-id-connect-provider-arn "${PROVIDER_ARN}"
  echo "Deleted OIDC Provider: ${PROVIDER_ARN}"
fi

# Clean up local JSON files
rm -f trust-policy.json cicd-permissions-policy.json

echo "=== Teardown Complete! Zero lingering IAM objects or charges. ==="
EOF

chmod +x teardown-oidc.sh
./teardown-oidc.sh

🎓 Capstone Retrospective: The 17-Part Mastery Path

Congratulations! You have officially completed AWS with CLI: The Terminal-First Mastery Path.

Take a moment to reflect on the immense architectural journey you have completed across all 17 parts:

+--------------------------------------------------------------+
|            THE 17-PART AWS CLI MASTERY CURRICULUM            |
+--------------------------------------------------------------+
|                                                              |
| MODULE 1: FOUNDATIONS & IAM SECURITY                         |
|  #01: CLI Installation, Root Bootstrap & Admin IAM Setup     |
|  #02: Multi-Account Profiles & Ephemeral STS AssumeRole      |
|  #03: Granular IAM Policies, Boundaries & Policy Simulator   |
|                                                              |
| MODULE 2: GLOBAL INFRASTRUCTURE & VPC NETWORKING             |
|  #04: Global Regions, Availability Zones & Physical AZ IDs   |
|  #05: Production Multi-AZ VPC, Subnets & Route Tables        |
|  #06: Advanced VPC: S3 Endpoints, Flow Logs & Reachability   |
|                                                              |
| MODULE 3: COMPUTE FLEETS & HIGH AVAILABILITY                 |
|  #07: EC2 Instances, Stateful SG vs NACLs & IMDSv2           |
|  #08: EBS Block Storage, KMS Encryption & Golden AMIs        |
|  #09: Zero-Trust SSM Session Manager & Fleet Run Command     |
|  #10: Layer 7 Traffic Routing: ALB, Target Groups & SSL      |
|  #11: Elastic Fleets: Auto Scaling, Spot & Rolling Refresh   |
|                                                              |
| MODULE 4: STORAGE, DATABASES & DATA LIFECYCLE                |
|  #12: S3 Mastery: Bucket Policies, KMS, Lifecycles & EFS     |
|  #13: RDS PostgreSQL Multi-AZ & DynamoDB NoSQL with CLI      |
|                                                              |
| MODULE 5: SERVERLESS, CONTAINERS & APIS                      |
|  #14: Container Workflows: Docker ECR Push & ECS Fargate     |
|  #15: Serverless Microservices: Lambda & HTTP API Gateways   |
|                                                              |
| MODULE 6: INFRASTRUCTURE AS CODE & CI/CD                     |
|  #16: Multi-Tier Stacks with CloudFormation & SAM CLI        |
|  #17: Zero-Secret CI/CD: GitHub Actions OIDC & CloudFront    |
|                                                              |
+--------------------------------------------------------------+

The 5 Golden Rules of the Terminal-First Cloud Architect

  1. Eliminate ClickOps Everywhere: Never create a production resource in the web console that isn’t reproducible, scriptable, or version-controlled.
  2. Enforce Least Privilege by Default: Grant permissions only to the exact actions, resources, and conditions required. Reject Action: "*" and Resource: "*".
  3. Embrace Ephemeral Credentials: Never hardcode long-lived access keys in configuration files, build scripts, or CI secrets. Use IAM Roles, STS AssumeRole, and OIDC.
  4. Architect for Failure Across Multi-AZ: Assume individual instances, disks, and availability zones will fail. Rely on stateless compute, ASG self-healing, and load-balanced target groups.
  5. Declare Desired State: Move from imperative CLI commands for exploration to declarative CloudFormation / SAM templates for enterprise production.

You now possess the hands-on engineering muscle to architect, troubleshoot, deploy, and automate enterprise cloud infrastructure directly from the command line.

Keep your terminal open, your credentials ephemeral, and happy building on AWS!

Related & Recommended Guides

Continue exploring related systems architectures and engineering field notes.