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
- Go to AWS Console → IAM → Users →
demo-user - Under Security credentials, click Assign MFA device
- Use a virtual device like Google Authenticator
- 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-tokenwith 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
