Skip to main content

AWS IAM User and Policy Management: CloudFormation Template

526 words·
AWS IAM CloudFormation
Table of Contents

This CloudFormation Template creates an IAM user and attaches both a custom policy (for S3 access) and an AWS-managed policy (AmazonEC2FullAccess). It also generates AWS access keys for the user.

CloudFormation IAM Management
#

CloudFormation Template
#

Project Folder
#

# Create a CloudFormation project folder
TF_PROJECT_NAME=aws-cloudformation-iam
mkdir $TF_PROJECT_NAME && cd $TF_PROJECT_NAME

Template
#

  • cloudformation.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: "IAM User and Policy Management"

Parameters:
  # IAM user
  IAMUserName:
    Type: String
    Description: "IAM user name"
    Default: "example-user"

  # IAM custom policy
  IAMCustomPolicyName:
    Type: String
    Description: "The S3 bucket to grant access"
    Default: "example-policy"

  # S3 Bucket name for IAM custom policy
  S3BucketName:
    Type: String
    Description: "The S3 bucket to grant access"
    Default: "jkw-example-bucket"


Resources:
  IAMUser:
    Type: AWS::IAM::User
    Properties:
      UserName: !Ref IAMUserName
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/AmazonEC2FullAccess"

  IAMCustomUserPolicy:
    Type: AWS::IAM::UserPolicy
    Properties:
      PolicyName: !Sub "${IAMUserName}-${IAMCustomPolicyName}"
      UserName: !Ref IAMUser
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - "s3:ListBucket"
            Resource: !Sub "arn:aws:s3:::${S3BucketName}"
          - Effect: Allow
            Action:
              - "s3:GetObject"
              - "s3:PutObject"
              - "s3:DeleteObject"
            Resource: !Sub "arn:aws:s3:::${S3BucketName}/*"

  TerraformS3AccessKey:
    Type: AWS::IAM::AccessKey
    Properties:
      UserName: !Ref IAMUser


Outputs:
  AccessKeyId:
    Description: "Access Key"
    Value: !Ref TerraformS3AccessKey
    Export:
      Name: !Sub "${IAMUserName}AccessKey"

  SecretAccessKey:
    Description: "Secret Access Key"
    Value: !GetAtt TerraformS3AccessKey.SecretAccessKey
    Export:
      Name: !Sub "${IAMUserName}SecretAccessKey"



Deploy CloudFormation Stack
#

Validate Template
#

# Validate the CloudFormation template
aws cloudformation validate-template --template-body file://cloudformation.yml

# Shell output:
{
    "Parameters": [
        {
            "ParameterKey": "S3BucketName",
            "DefaultValue": "jkw-example-bucket",
            "NoEcho": false,
            "Description": "The S3 bucket to grant access"
        },
        {
            "ParameterKey": "IAMUserName",
            "DefaultValue": "example-user",
            "NoEcho": false,
            "Description": "IAM user name"
        },
        {
            "ParameterKey": "IAMCustomPolicyName",
            "DefaultValue": "example-policy",
            "NoEcho": false,
            "Description": "The S3 bucket to grant access"
        }
    ],
    "Description": "IAM User and Policy Management",
    "Capabilities": [
        "CAPABILITY_NAMED_IAM"
    ],
    "CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::AccessKey, AWS::IAM::User]"
}

Deploy Template / Stack
#

# Deploy a stack from the template: Default region
aws cloudformation create-stack --stack-name iam-stack \
  --template-body file://cloudformation.yml \
  --capabilities CAPABILITY_NAMED_IAM

# Shell output:
{
    "StackId": "arn:aws:cloudformation:us-east-1:012345678912:stack/iam-stack/42befe00-defd-11ef-8e6c-12ab64dd2afb"
}
  • --capabilities CAPABILITY_NAMED_IAM Is required when the CloudFormation template creates or modifies IAM resources for security reasons.

Verify the Deployment / Output Access Keys
#

Wait till the “StackStatus” changes to “CREATE_COMPLETE”:

# Monitor the deployment
aws cloudformation describe-stacks --stack-name iam-stack

# Shell output:
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:us-east-1:012345678912:stack/iam-stack/42befe00-defd-11ef-8e6c-12ab64dd2afb",
            "StackName": "iam-stack",
            "Description": "IAM User and Policy Management",
            "Parameters": [
                {
                    "ParameterKey": "S3BucketName",
                    "ParameterValue": "jkw-example-bucket"
                },
                {
                    "ParameterKey": "IAMUserName",
                    "ParameterValue": "example-user"
                },
                {
                    "ParameterKey": "IAMCustomPolicyName",
                    "ParameterValue": "example-policy"
                }
            ],
            "CreationTime": "2025-01-30T11:28:00.011000+00:00",
            "RollbackConfiguration": {},
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Capabilities": [
                "CAPABILITY_NAMED_IAM"
            ],
            "Outputs": [
                {
                    "OutputKey": "AccessKeyId",
                    "OutputValue": "AKIARCHUALINUI4UGXI7",
                    "Description": "Access Key",
                    "ExportName": "example-userAccessKey"
                },
                {
                    "OutputKey": "SecretAccessKey",
                    "OutputValue": "hJxO+BecJ6HGsohBCEGlPgFWnFQjOubm5v4UOC9d",
                    "Description": "Secret Access Key",
                    "ExportName": "example-userSecretAccessKey"
                }
            ],
            "Tags": [],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}

Verify Stack with Management Console
#



Verify IAM user via AWS CLI
#

# List policies that are attached to the IAM user
aws iam list-attached-user-policies --user-name example-user

# Shell output:
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonEC2FullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonEC2FullAccess"
        }
    ]
}
# List inline (directly attached to the user) policies, that are attached to the IAM user
aws iam list-user-policies --user-name example-user

# Shell output:
{
    "PolicyNames": [
        "example-user-example-policy"
    ]
}



Cleanup
#

Delete CloudFormation Stack
#

# Delete the stack: Default region
aws cloudformation delete-stack --stack-name iam-stack