Skip to content

Deploy Docker Swarm on AWS EC2 via cloud-formation templates - Step 3 - Roles

In this step we create the IAM roles and policies needed by the EC2 instances.

This post is part of a thread that includes these steps:

  1. Network Setup
  2. Storage
  3. Roles (this post)
  4. Manager Instance
  5. Worker Launch Template
  6. Worker Instances
  7. Docker Swarm
  8. Cleanup

Identity and Access Management (AWS IAM)

Start in the project directory:

cd ~/swift-aws-ec2-swarm

cloud-formation Template

We need to create IAM Role and Instance Profile for two types of instances:

  1. Manager - this will be used by the Manager instance
  2. Worker - this will be used by the Worker instances

Manager

Create a folder iam and a iam-manager.yml file in it.

mkdir -p iam
touch iam/iam-manager.yml
nano iam/iam-manager.yml

Copy and paste this code into iam-manager.yml:

Description:  IAM role and instance profile for the Manager instance

Parameters:
  Prefix:
    Description: An environment name that is prefixed to resource names
    Type: String

# Permissions for the Manager instance
Resources:
  Role:
    Type: AWS::IAM::Role
    Properties:
      # categories:
        - Key: Name
          Value: !Sub ${Prefix}-iam-role-manager
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: 
                  - ec2:DescribeTags
                  - ec2:AttachVolume
                  - ec2:DetachVolume
                  - ecr:DescribeRegistry
                  - route53:*
                Resource: '*'

  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref Role

Outputs:
  InstanceProfile:
    Description: A reference to the created InstanceProfile
    Value: !Ref InstanceProfile

Worker

Create a file iam/iam-worker.yml

touch iam/iam-worker.yml
nano iam/iam-worker.yml

Copy and paste this code into iam-worker.yml:

Description:  IAM role and instance profile for the Worker instances

Parameters:
  Prefix:
    Description: An environment name that is prefixed to resource names
    Type: String

# Permissions for the Worker instance(s)
Resources:
  Role:
    Type: AWS::IAM::Role
    Properties:
      # categories:
        - Key: Name
          Value: !Sub ${Prefix}-iam-role-worker
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: 
                  - ec2:DescribeTags
                  - ec2:AttachVolume
                  - ec2:DetachVolume
                  - ecr:DescribeRegistry
                  - route53:*
                Resource: '*'

  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref Role

Outputs:
  InstanceProfile:
    Description: A reference to the created InstanceProfile
    Value: !Ref InstanceProfile

Scripts

Manager

Add a script iam/deploy-iam-manager.sh and paste this code in it:

#!/usr/bin/env bash

# switch to parent directory
script_path=`dirname ${BASH_SOURCE[0]}`
pushd $script_path/..

source config/names.sh

echo
echo "Deploying $stack_iam_manager stack via cloud-formation:"
echo 'https://us-west-2.console.aws.amazon.com/cloudformation/home'
echo

set -x

# NOTE: `--capabilities CAPABILITY_IAM` is needed because the `iam.yml` cloud-formation template creates roles and instance profiles.

aws cloudformation deploy \
    --capabilities CAPABILITY_IAM \
    --template-file iam/iam-manager.yml \
    --stack-name $stack_iam_manager \
    --parameter-overrides Prefix=$prefix

popd

Worker

Add a script iam/deploy-iam-worker.sh and paste this code in it:

#!/usr/bin/env bash

# switch to parent directory
script_path=`dirname ${BASH_SOURCE[0]}`
pushd $script_path/..

source config/names.sh

echo
echo "Deploying $stack_iam_worker stack via cloud-formation:"
echo 'https://us-west-2.console.aws.amazon.com/cloudformation/home'
echo

set -x

# NOTE: `--capabilities CAPABILITY_IAM` is needed because the `iam.yml` cloud-formation template creates roles and instance profiles.

aws cloudformation deploy \
    --capabilities CAPABILITY_IAM \
    --template-file iam/iam-worker.yml \
    --stack-name $stack_iam_worker \
    --parameter-overrides Prefix=$prefix

popd

Let's also add clean up scripts. First the rm-iam-manager.sh:

#!/usr/bin/env bash

# switch to parent directory
script_path=`dirname ${BASH_SOURCE[0]}`
pushd $script_path/..

source config/names.sh

echo
echo "Removing $stack_iam_manager stack via cloud-formation:"
echo 'https://us-west-2.console.aws.amazon.com/cloudformation/home'
echo

set -x

aws cloudformation delete-stack \
    --stack-name $stack_iam_manager 

aws cloudformation wait stack-delete-complete \
    --stack-name $stack_iam_manager

popd

and another one for the worker - rm-iam-worker.sh:

#!/usr/bin/env bash

# switch to parent directory
script_path=`dirname ${BASH_SOURCE[0]}`
pushd $script_path/..

source config/names.sh

echo
echo "Removing $stack_iam_worker stack via cloud-formation:"
echo 'https://us-west-2.console.aws.amazon.com/cloudformation/home'
echo

set -x

aws cloudformation delete-stack \
    --stack-name $stack_iam_worker 

aws cloudformation wait stack-delete-complete \
    --stack-name $stack_iam_worker

popd

Make all scripts executable:

chmod +x iam/deploy-iam-manager.sh 
chmod +x iam/rm-iam-manager.sh

chmod +x iam/deploy-iam-worker.sh 
chmod +x iam/rm-iam-worker.sh

Deploy

Finally let's run the "deploy" scripts to create the IAM roles. First for the Manager:

./iam/deploy-iam-manager.sh

You should see output similar to this:

Deploying swift-swarm-iam-manager stack via cloud-formation:
https://us-west-2.console.aws.amazon.com/cloudformation/home

+ aws cloudformation deploy --capabilities CAPABILITY_IAM --template-file iam/iam-manager.yml --stack-name swift-swarm-iam-manager --parameter-overrides Prefix=swift-swarm

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - swift-swarm-iam-manager

then for the Worker:

./iam/deploy-iam-worker.sh

You should see output similar to this:

Deploying swift-swarm-iam-worker stack via cloud-formation:
https://us-west-2.console.aws.amazon.com/cloudformation/home

+ aws cloudformation deploy --capabilities CAPABILITY_IAM --template-file iam/iam-worker.yml --stack-name swift-swarm-iam-worker --parameter-overrides Prefix=swift-swarm

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - swift-swarm-iam-worker

At this point your project structure should look like this:

.
├── config
│   └── names.sh
├── ebs
│   ├── deploy-ebs.sh
│   ├── ebs.yml
│   └── rm-ebs.sh
├── iam
│   ├── deploy-iam-manager.sh
│   ├── deploy-iam-worker.sh
│   ├── iam-manager.yml
│   ├── iam-worker.yml
│   ├── rm-iam-manager.sh
│   └── rm-iam-worker.sh
└── vpc
    ├── deploy-vpc.sh
    ├── rm-vpc.sh
    └── vpc.yml

Congratulations!

We are done with Step 3. Roles.

Next step is: Step 4. Manager Instance