Skip to content

Instantly share code, notes, and snippets.

@alsmola
Last active December 27, 2019 04:53
Show Gist options
  • Save alsmola/dd3e51e02db0ba3f9d32fe4385deea53 to your computer and use it in GitHub Desktop.
Save alsmola/dd3e51e02db0ba3f9d32fe4385deea53 to your computer and use it in GitHub Desktop.
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