Core Implementation — EC2 Instance Role

Designing the EC2 Processing Role

An EC2 instance that writes to S3 should never do so using an IAM user’s access key embedded in application config or environment variables. Long-lived credentials in instance storage are a persistent vulnerability — they survive reboots, get copied into AMIs, appear in config backups, and are difficult to rotate without downtime. The correct pattern is an IAM role attached to the instance, which causes the EC2 metadata service to vend rotating temporary credentials automatically.

Creating the Role

In IAM, create a new role with the following configuration:

  • Trusted entity type: AWS service
  • Use case: EC2

This trust policy, which AWS generates automatically, allows the EC2 service to call sts:AssumeRole on behalf of any instance the role is attached to. The resulting trust policy document looks like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Name the role EC2DocumentProcessorRole.

Creating the Permission Policy

Create a customer managed policy named DocumentProcessorS3Access and attach it to this role:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadFromSource",
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::cloudboxio-lab-source-{your-account-id}/*"
    },
    {
      "Sid": "WriteToOutput",
      "Effect": "Allow",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::cloudboxio-lab-output-{your-account-id}/*"
    }
  ]
}

This role can read from source and write to output. It cannot list buckets, delete objects, modify bucket policy, or touch any other AWS service. An EC2 instance carrying this role cannot escalate its own privileges, create other IAM entities, or access resources outside these two specific paths.

Launching the EC2 Instance

Launch a t2.micro EC2 instance (free tier eligible) with the following configuration:

  • AMI: Amazon Linux 2023
  • Instance type: t2.micro
  • IAM instance profile: select EC2DocumentProcessorRole
  • No key pair is required if you use EC2 Instance Connect for access
  • Security group: allow SSH inbound from your IP only (port 22)

The instance profile is the container that binds the role to the instance. When the instance starts, the metadata service at 169.254.169.254 begins serving temporary credentials for this role on a rotating basis.

Validation From Inside the Instance

Connect to the instance via EC2 Instance Connect. Run the following commands to verify the role is active and permissions are scoped correctly:

# Confirm the role identity
aws sts get-caller-identity
 
# Should return the EC2DocumentProcessorRole ARN, not a user ARN
# Test read access from source bucket
aws s3 cp s3://cloudboxio-lab-source-{your-account-id}/your-test-file.txt /tmp/test.txt
echo $?  # Should return 0
# Test write access to output bucket
echo "processed output" > /tmp/result.txt
aws s3 cp /tmp/result.txt s3://cloudboxio-lab-output-{your-account-id}/result.txt
echo $?  # Should return 0
# Test that write to source bucket is denied
aws s3 cp /tmp/result.txt s3://cloudboxio-lab-source-{your-account-id}/attempt.txt
# Should return: An error occurred (AccessDenied)
# Test that EC2 actions are denied (the role has no EC2 permissions)
aws ec2 describe-instances
# Should return: An error occurred (UnauthorizedOperation)

If aws sts get-caller-identity returns a user ARN rather than a role ARN, the instance profile was not attached correctly. Stop the instance, attach the instance profile under Actions > Security > Modify IAM Role, and restart.

EC2 instance connect terminal showing role identity and S3 test results

In this section, I confirmed:

0 of 8 completed

Choose your language

Select your preferred language for the site