Skip to content

Instantly share code, notes, and snippets.

@alsmola
Last active December 27, 2019 04:53
Embed
What would you like to do?
Using session policies to limit IAM role access

Session Policy Example

First, upload test files to an S3 bucket you control (replace YOUR_BUCKET_NAME) in two directories representing isolated namespaces (123 and 124).

echo "123" > test.txt
aws s3 cp test.txt s3://YOUR_BUCKET_NAME/123/test.txt
echo "124" > test.txt
aws s3 cp test.txt s3://YOUR_BUCKET_NAME/124/test.txt

Next, create the role using the included CloudFormation template, role.json. Make sure to replace the YOUR_BUCKET_NAME value with your S3 bucket.

aws cloudformation create-stack --stack-name SelfAssumingRole --template-body file://role.json --capabilities CAPABILITY_IAM --parameters ParameterKey=S3BucketName,ParameterValue=YOUR_BUCKET_NAME

Once the stack has been created, you can get the role ARN from the Outputs of the stack:

 aws cloudformation describe-stacks --stack-name SelfAssumingRole

Replace the S3 bucket name and role ARN in the main.go file.

Make sure your environment is configured with IAM credentials that can assume a role, and then assume the role you created, doing something like:

self_assuming_role=$(aws sts assume-role \
                    --role-arn "YOUR_ROLE_ARN" \
                    --role-session-name "SelfAssumingRoleSession")

export AWS_ACCESS_KEY_ID=$(echo $self_assuming_role | jq .Credentials.AccessKeyId | xargs)
export AWS_SECRET_ACCESS_KEY=$(echo $self_assuming_role | jq .Credentials.SecretAccessKey | xargs)
export AWS_SESSION_TOKEN=$(echo $self_assuming_role | jq .Credentials.SessionToken | xargs)

Run the main.go file:

go run main.go
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/sts"
)
func main() {
// Replace these values
bucketName := "S3_BUCKET_NAME"
roleArn := "arn:aws:iam::ACCOUNT_NUMBER:role/ROLE_NAME"
// Assume role with session policy and use credentials for S3 client
customerNumber := "123"
bucketWithPrefix := fmt.Sprintf("arn:aws:s3:::%s/%s/*", bucketName, customerNumber)
policy := `{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowAllS3ActionsWithinPrefix",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "` + bucketWithPrefix + `"
}]
}`
stsService := sts.New(session.New(), aws.NewConfig())
input := &sts.AssumeRoleInput{
RoleArn: aws.String(roleArn),
RoleSessionName: aws.String("customer-" + customerNumber),
Policy: aws.String(policy),
}
resp, err := stsService.AssumeRole(input)
if err != nil {
panic(err)
}
creds := credentials.NewStaticCredentials(
*resp.Credentials.AccessKeyId,
*resp.Credentials.SecretAccessKey,
*resp.Credentials.SessionToken,
)
session := session.New()
s3Client := s3.New(session, aws.NewConfig().WithCredentials(creds))
// File access code looks the same, using the customer number and S3 client
key := fmt.Sprintf("%s/test.txt", customerNumber)
_, err = s3Client.GetObject(&s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(key),
})
if err != nil {
panic(err)
}
fmt.Println("Self-assuming role allowed correct access")
// This call will fail with an AccessDenied error if the customer number isn't the authenticated user
wrongCustomerNumber := "124"
key = fmt.Sprintf("%s/test.txt", wrongCustomerNumber)
_, err = s3Client.GetObject(&s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(key),
})
if err == nil {
panic("Incorrect acccess permitted")
}
fmt.Println("Self-assuming role prevented incorrect access")
}
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"S3BucketName": {
"Description": "Name of S3 Bucket",
"Type": "String"
}
},
"Outputs" : {
"RoleArn" : {
"Description": "The ARN of the IAM role created",
"Value" : {"Fn::GetAtt" : ["SelfAssumingRole", "Arn"] }
}
},
"Resources": {
"SelfAssumingRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"AWS": { "Fn::Join": ["", [ "arn:aws:iam::", { "Ref" : "AWS::AccountId" }, ":root"] ] }
}
}
],
"Version": "2012-10-17"
},
"Path": "/"
}
},
"S3AccessPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "AllowS3Access",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": { "Fn::Join": ["", [ "arn:aws:s3:::", { "Ref" : "S3BucketName" }, "/*"] ] }
} ]
},
"Roles": [ {
"Ref": "SelfAssumingRole"
} ]
}
},
"SelfAssumeRolePolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "AllowSelfAssumeRole",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": {"Fn::GetAtt" : ["SelfAssumingRole", "Arn"] }
} ]
},
"Roles": [ {
"Ref": "SelfAssumingRole"
} ]
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment