Skip to content

ericmolinam/lab-aws-ec2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 

Repository files navigation

AWS EC2 Lab

A Terraform lab that provisions an EC2 instance in AWS (eu-south-2) with a generated SSH key pair, a security group, and a private S3 bucket to store the private key securely.

Authentication to AWS is handled via OIDC dynamic provider credentials configured in Terraform Cloud so no static AWS credentials are stored anywhere.


Architecture:

Terraform Cloud (lab-ec2)
        │
        │  OIDC token (workload identity)
        ▼
  AWS STS → temporary credentials
        │
        ├── IAM Key Pair         ← RSA 4096-bit public key
        ├── Security Group       ← inbound SSH (port 22) from allowed CIDR
        ├── EC2 Instance         ← t3.micro, attached key pair + security group
        └── S3 Bucket            ← private key (.pem), encrypted + versioned

Prerequisites:

  • Terraform CLI >= 1.15
  • Terraform Cloud account with organization emolinam5
  • AWS account with OIDC trust configured (see below)
  • AWS CLI (optional, for downloading the key from S3)

Authentication w/ OIDC dynamic provider credentials:

This project uses Terraform Cloud's native OIDC integration to authenticate to AWS without long-lived credentials. The setup follows the AWS APN blog guide.

1. Create an IAM OIDC Identity Provider in AWS:

Field Value
Provider URL https://app.terraform.io
Audience aws.workload.identity

2. Create an IAM Role with a trust policy:

Attach a trust policy that allows Terraform Cloud to assume the role via the OIDC provider. Scope it to your organization and workspace:

{
  "Effect": "Allow",
  "Principal": {
    "Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/app.terraform.io"
  },
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringEquals": {
      "app.terraform.io:aud": "aws.workload.identity"
    },
    "StringLike": {
      "app.terraform.io:sub": "organization:emolinam5:project:*:workspace:*:run_phase:*"
    }
  }
}

Attach the necessary IAM permissions to this role (EC2, S3, IAM key pair).

3. Configure Terraform Cloud workspace environment variables:

In the lab-ec2 workspace, set the following environment variables (not Terraform variables):

Variable Value Sensitive
TFC_AWS_PROVIDER_AUTH true No
TFC_AWS_RUN_ROLE_ARN arn:aws:iam::<ID>:role/<name> Yes

Terraform Cloud will automatically generate a short-lived OIDC token per run and exchange it for temporary AWS credentials via STS. No AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY is needed.


Project structure:

terraform/
├── backend.tf      # Terraform Cloud workspace + provider requirements
├── keys.tf         # TLS key generation + AWS key pair
├── compute.tf      # Security group + EC2 instance
├── storage.tf      # S3 bucket, encryption, versioning, private key upload
├── variables.tf    # Input variables
└── outputs.tf      # Public DNS + S3 URI

Resources provisioned:

Resource Description
tls_private_key RSA 4096-bit key pair generated by Terraform
aws_key_pair Public key registered in AWS for EC2 access
aws_security_group Allows inbound SSH (port 22) from var.ssh_cidr
aws_instance EC2 instance (t3.micro by default) in eu-south-2
aws_s3_bucket Private bucket to store the .pem key
aws_s3_bucket_public_access_block All public access blocked
aws_s3_bucket_server_side_encryption_configuration SSE-S3 (AES256) encryption at rest
aws_s3_bucket_versioning Versioning enabled to retain previous key versions
aws_s3_object Private key uploaded as private_key.pem

Variables:

Name Description Default
aws_region AWS region to deploy resources eu-south-2
ssh_cidr CIDR block allowed to connect via SSH 185.71.137.32/32
aws_ami AMI ID for the EC2 instance ami-0148251f3f228d827
aws_instance_type EC2 instance type (t3.micro or t3.nano) t3.micro
aws_key_name Name of the AWS Key Pair resource key-pair

Variables can be overridden in the Terraform Cloud workspace under Variables > Terraform Variables.


Outputs:

Name Description
public_ip Public DNS of the EC2 instance
private_key_s3_uri S3 URI of the uploaded private key

CI/CD Workflow:

The repository includes a single GitHub Actions workflow (.github/workflows/terraform.yml) that handles all Terraform operations through Terraform Cloud. It requires one GitHub secret: TF_API_TOKEN.

Triggers and jobs:

Trigger plan job apply job destroy job
Pull request Speculative plan (preview only) Skipped Skipped
Push to main Real plan Requires approval → applies Skipped
Manual → plan Speculative plan (preview only) Skipped Skipped
Manual → apply Real plan Requires approval → applies Skipped
Manual → destroy Real destroy plan Skipped Requires approval → destroys

How it works:

Plan job — always runs first. Uploads the Terraform configuration to TFC and creates a run. For pull requests and manual plan operations the run is speculative (preview only, can never be applied). For apply and destroy operations the run is real and sits waiting for confirmation.

Apply / Destroy jobs — both depend on the plan job and reuse the same TFC run via its run_id. They will not start until a reviewer manually approves the tf-apply environment in GitHub. The reviewer can check the plan summary written to the workflow run's Summary tab before approving.

Approval gate — configured via a GitHub environment named tf-apply. Set it up under Settings → Environments → tf-apply → Required reviewers.

Plan summary:

Every workflow run writes a Terraform plan summary to the GitHub Actions Summary tab showing resources to add, change, and destroy, plus a direct link to the full plan in Terraform Cloud.

Running manually:

Go to Actions → 👷 Terraform Build & Destroy → Run workflow and select the operation:

  • plan — preview changes without applying
  • apply — plan then apply (requires approval)
  • destroy — plan the destruction then destroy (requires approval)

Usage:

Deploy:

Runs are triggered automatically in Terraform Cloud on workspace changes. To run manually via CLI:

cd terraform
terraform login
terraform init
terraform apply

SSH into the instance:

  1. Download the private key from S3:
aws s3 cp $(terraform output -raw private_key_s3_uri) ./private_key.pem
chmod 400 private_key.pem
  1. Connect:
ssh -i private_key.pem ubuntu@$(terraform output -raw public_ip)

Destroy:

terraform destroy

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages