Terraform-Based Zero Trust Implementation on AWS

Create IAM User, Scoped Access, and Enforce MFA

In the previous blog, we discussed how to implement the Zero Trust Framework manually in AWS by creating an IAM user, assigning least privilege access, and enabling Multi-Factor Authentication (MFA).

Now let’s go a step further — we’ll automate the entire setup using Terraform. This helps you implement Zero Trust at scale in a reproducible and secure way.


What We’ll Achieve Using Terraform

Create an IAM user (demo-user)
Create an S3 bucket
Assign scoped (least-privilege) access to that bucket
Attach a policy that denies write access unless MFA is used
Note: MFA setup must still be done manually via AWS Console (Terraform can’t manage MFA devices)


Project Structure

zero-trust-aws/
├── main.tf├── variables.tf├── outputs.tf

You can create a new folder and paste the files below.


variables.tf

variable "user_name" {
  default = "demo-user"
}

variable "bucket_name" {
  default = "zero-trust-demo-bucket"
}

variable "region" {
  default = "us-east-1"
}

main.tf

provider "aws" {
  region = var.region
}

# Create S3 Bucket
resource "aws_s3_bucket" "demo_bucket" {
  bucket = var.bucket_name
}

# Create IAM User
resource "aws_iam_user" "demo_user" {
  name = var.user_name
}

# Create Access Keys for the User
resource "aws_iam_access_key" "demo_user_key" {
  user = aws_iam_user.demo_user.name
}

# Attach S3 Read Policy
resource "aws_iam_user_policy" "read_policy" {
  name = "s3-read-only"
  user = aws_iam_user.demo_user.name

  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Sid: "AllowListBucket",
        Effect = "Allow",
        Action = "s3:ListBucket",
        Resource = "arn:aws:s3:::${var.bucket_name}"
      },
      {
        Sid: "AllowGetObject",
        Effect = "Allow",
        Action = "s3:GetObject",
        Resource = "arn:aws:s3:::${var.bucket_name}/*"
      }
    ]
  })
}

# Attach MFA Enforcement Policy
resource "aws_iam_user_policy" "mfa_enforce_policy" {
  name = "require-mfa-for-put"
  user = aws_iam_user.demo_user.name

  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Sid: "DenyPutObjectWithoutMFA",
        Effect = "Deny",
        Action = "s3:PutObject",
        Resource = "arn:aws:s3:::${var.bucket_name}/*",
        Condition = {
          BoolIfExists = {
            "aws:MultiFactorAuthPresent" = "false"
          }
        }
      }
    ]
  })
}

outputs.tf

output "iam_user_name" {
  value = aws_iam_user.demo_user.name
}

output "access_key_id" {
  value = aws_iam_access_key.demo_user_key.id
}

output "secret_access_key" {
  value = aws_iam_access_key.demo_user_key.secret
  sensitive = true
}

Deploy the Setup

1. Initialize Terraform

terraform init

2. Apply the Configuration

terraform apply

Confirm when prompted. After a few seconds, Terraform will output:

  • The IAM user name
  • Their access key and secret

You can now test this user’s access using the AWS CLI.


Manual Step: Enable MFA

  1. Go to AWS Console → IAM → Users → demo-user
  2. Under Security credentials, click Assign MFA device
  3. Use a virtual device like Google Authenticator
  4. Complete the OTP process

Now your user is protected with MFA.


Test the Zero Trust Flow

  • List or read objects from the S3 bucket → Should work
  • Upload to the bucket without MFA → Should fail
  • Use sts get-session-token with MFA → Upload succeeds

This proves that Zero Trust is working — identity is verified, access is minimal, and privileged actions require strong authentication.


Final Thoughts

With just a few lines of Terraform, we’ve automated:

  • IAM user creation
  • Least privilege policy enforcement
  • MFA-based conditional access

This aligns perfectly with the Zero Trust principles of:

  • Never trust by default
  • Verify explicitly
  • Enforce least privilege
  • Assume breach

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top