Delegating Access To AWS Resources Using IAM and STS (Switch Roles)

Amazon secure most of their services using IAM (Identity Access Management) which is a policy based access mechanism which relies on users, groups, roles, policies etc — by Craig Godden-Payne@beardy.digital

Image for post
Image for post
Photo by Jose Fontano on Unsplash
Image for post
Image for post
Photo by Philipp Katzenberger on Unsplash

What makes up IAM?

Image for post
Image for post
Photo by Marc-Olivier Jodoin on Unsplash

How are policies built up?

- Principal

- Anonymous Users
"Principal":"AWS":"*.*"
- Specific Accounts
"Principal":{"AWS":"arn:aws:iam::123456789012:root"}
- Individual IAM User
"Principal":{"AWS":"arn:aws:iam::123456789012:user/name"}
- Federated User
"Principal":{"Federated":"www.amazon.com"}
- Specific Role
"Principal":{"AWS":"arn:aws:iam::123456789012:role/rolename"}
- Specific Service
"Principal":{"Service":"ec2.amazonaws.com"}

- Actions

- EC2 Action
"Action":"ec2:StartInstances"
- IAM Action
"Action":"iam:ChangePassword"
- S3 Action
"Action":"s3:GetObject"
- Multiple Action
"Action":["sqs:SendMessage", "sqs:RecieveMessage"]
- Wildcard Action
"Action":"sns:*"
- Wildcard Action (would deny all sns)
"NotAction":"sns:*"
- Using Multiples (this example will allow everything, except for IAM)
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
},
{
"Effect": "Deny",
"Action": "iam:*",
"Resource": "*"
}]
}

- Resource

- S3 Bucket
"Resource": "arn:aws:s3:::/bucketname/*"
- SQS Queue
"Resource": "arn:aws:sqs:eu-west-2:123456789012:queuename"
- Multiple Dynamo Tables
"Resource": ["arn:aws:dynamodb:eu-west-2:123456789012:table/tablename","arn:aws:dynamodb:eu-west-2:123456789012:table/tablename2"]
- EC2 instances for an account in a region
"Resource": "arn:aws:ec2:eu-west-2:123456789012:instance/*"

- Conditions

"Condition": {
"DateGreaterThan": { "aws:CurrentTime": "2018-05-01T00:00:00Z" },
"DateLessThan": { "aws:CurrentTime": "2018-05-22T00:00:00Z" }
"IpAddress": { "aws:SourceIp": ["192.0.1.0/24", "192.0.2.0/24"] }
}
Image for post
Image for post
Photo by chris panas on Unsplash

Example 1

{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["ec2:TerminateInstances"],
"Resource": "arn:aws:ec2:eu-west-2:123456789012:instance/*"
}]
}

Example 2

{
"Version": "2012-10-17",
"Statement": [{
"Sid": "ManageUsersPermissions",
"Effect": "Allow",
"Action": ["iam:ChangePassword","iam:CreateAccessKey","iam:CreateLoginProfile","iam:CreateUser",
"iam:DeleteAccessKey","iam:DeleteLoginProfile","iam:DeleteUser","iam:UpdateAccessKey",
"iam:ListAttachedUserPolicies","iam:ListPolicies"],
"Resource": "*"
},
{
"Sid": "LimitedAttachmentPermissions",
"Effect": "Allow",
"Action": ["iam:AttachUserPolicy", "iam:DetachUserPolicy"],
"Resource": "*",
"Condition": {
"ArnEquals": {
"iam:PolicyArn": [
"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"
]
}
}
}]
}
Image for post
Image for post
Photo by Scott Webb on Unsplash

So now we know what IAM can do, how can I now delegate access to an AWS resource using STS?

Image for post
Image for post

Lets see how this would work in the AWS CLI

aws sts assume-role \
--duration-seconds 3600 \
--role-arn "arn:aws:iam::000000000000:role/switch-role-my-dynamo-role" \
--role-session-name craig-session-1 | \
jq '.Credentials.SecretAccessKey , .Credentials.AccessKeyId , .Credentials.SessionToken' | \
xargs sh -c 'echo AWS_ACCESS_KEY_ID=$1 AWS_SECRET_ACCESS_KEY=$0 AWS_SESSION_TOKEN=$2'
AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXXX AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx AWS_SESSION_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxYSKzATOB2E/k4SYji5R7nR/tPUOtPCfchVa7pLJQQ1x7fMiH3veJIxdj7RhQ//2q+cxpx9naJRR06H7HpikBpO5gE/iAOM2/hDmg3m28cT1oGj/hKsyb9lW9jeg8RTvsDeekXWFn88T+RGT/KJjdvj4+/yT3e/qVelBNTZxqBx9MWN6bxgXKVMYyyCmOT1iZBYSWr5VHC2smDmDRmJMm0Rmw1PUrtYioG2c/CFDHXLfRtbmPvwq+KOK+p/MFMi2j/IJz4HSGoANwylhylByYNY1GAkqVKvQ2qZKfKEOTHxxxxxxvxxxxxxxxx/x=
Image for post
Image for post
Photo by Chris Yang on Unsplash

How can we setup access between the two roles?

resource "aws_iam_role" "task_iam_role" {
name = "my-fargate-task-role"
assume_role_policy = "${file("${path.module}/policies/iam/ecs-task-service-trust.json")}"
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": [
"ecs-tasks.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
resource "aws_iam_role" "switch_role" {
name = "switch-role"
assume_role_policy = "${data.template_file.trust_policy_file.rendered}"
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::${ACCOUNT1_ID}:role/my-fargate-task-role"
]
},
"Action": "sts:AssumeRole"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["dynamodb:*"],
"Resource": "arn:aws:dynamodb:eu-west-1:${ACCOUNT2_ID}:table/*"
}
]
}
Image for post
Image for post
Photo by Dmitry Ratushny on Unsplash

Testing

def assumed_role_session(role_arn: str):
role = boto3.client('sts').assume_role(RoleArn=role_arn, RoleSessionName='switch-role')
credentials = role['Credentials']
aws_access_key_id = credentials['AccessKeyId']
aws_secret_access_key = credentials['SecretAccessKey']
aws_session_token = credentials['SessionToken']
return boto3.session.Session(
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
aws_session_token=aws_session_token)
def call_dynamo(*args, **kwargs):
assumed_session = assumed_role_session('arn:aws:iam::ACCOUNT2_ID:role/switch-role')
dynamo_client = assumed_session.client('dynamodb')
response = dynamo_client.list_tables(Limit=100)
print(str(response))

Written by

Technologist who enjoys writing and working with software and infra. I write up all the things I learn as I go along to share the knowledge! beardy.digital

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store