Introduction

AWS Secure Token Service (STS) is a service provided by AWS that enables you to request temporary credentials with limited privilege for AWS IAM users. In this article, we will learn how to use the AWS Boto3 with STS to temporarily assume a different role.

Table of contents

Prerequisites

  • Python3
  • Boto3: Boto3 can be installed using pip: pip install boto3
  • AWS Credentials: If you haven’t set up your AWS credentials before, this resource from AWS is helpful.

Create an IAM User with no permissions

For this tutorial, we will use an IAM user that has no permissions. This is what the user looks like in the AWS console:

AWS IAM User

Querying S3 API

We can confirm that this user has no permissions by running the following script:

import boto3
session = boto3.Session(profile_name="learnaws-test")
s3 = session.client("s3")
s3.list_buckets()

The output of the script is:


ClientError: An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied

How to create a new IAM role that can be assumed?

Next, we will create a new IAM role that has read only access to all S3 buckets in my account. This is the role that our IAM user will assume.

To ensure that our IAM user can assume this role, we need to add a Trust policy in the IAM role where the Principal is our IAM user. The trust policy for this IAM role looks something like this:


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::641879703613:user/learnaws-test-user"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

AWS IAM Role

AWS IAM Role Trust Relationship

How to assume an IAM role?

We will assume this new IAM role that we created in the previous step using the assume_role method in the AWS Boto3 STS SDK.The command returns a set of temporary credentials that will allow us to access AWS resources associated with the IAM Role that we want to assume. These temporary credentials consist of an access key ID, a secret access key, and a security token.

The arguments for this command are:

  • RoleArn: ARN for the IAM role we want to assume
  • RoleSessionName: Name for session to uniquely identify

import boto3
session = boto3.Session(profile_name="learnaws-test")
sts = session.client("sts")
response = sts.assume_role(
    RoleArn="arn:aws:iam::xxx:role/s3-readonly-access",
    RoleSessionName="learnaws-test-session"
)
print(response)

Output of the command:

{'Credentials': {'AccessKeyId': 'xxxx',
  'SecretAccessKey': 'xxxx',
  'SessionToken': 'FwoGZXIvYXdzEL3//////////wEaDLJyT8rgOs0jo9y9oCKvAbmzz80PQvWqhdQ9t5QKwQYoD4q8qCHi8GUtfuU97IS6xjsq32FfobiGX/gYjJLZ4S4igiMhSCXmqUBdeCneJHVQ30Sdzrzoa3TobxhBkT8wKeAb43EjmS7qaXrR5u6aCCDC0ak4LPWfhMwGxj2Ni5BcnKT9UDw2b28FsAKFZukAS6Ce+9A7Cup5Rtalv0i3ifCGWlh+4kcji6+pzwzi2rsQWJXACzvYq/oq+yjwrz4o1pPdmQYyLZrKVVWOrQ2Jn5mSyWLl+u+EQr7gtecx1nNL8DfmloRpcZxVTif8zrpjfFTsLg==',
  'Expiration': datetime.datetime(2022, 9, 30, 20, 56, 6, tzinfo=tzutc())},
 'AssumedRoleUser': {'AssumedRoleId': 'AROA2V2OH2EKNKNXNBG5Q:TestSession',
  'Arn': 'arn:aws:sts::xxx:assumed-role/s3-readonly-access/TestSession'},
 'ResponseMetadata': {'RequestId': 'fa89c2ce-d219-4ecb-af3f-3af0dd84a1dc',
  'HTTPStatusCode': 200,
  'HTTPHeaders': {'x-amzn-requestid': 'fa89c2ce-d219-4ecb-af3f-3af0dd84a1dc',
   'content-type': 'text/xml',
   'content-length': '1063',
   'date': 'Fri, 30 Sep 2022 19:56:06 GMT'},
  'RetryAttempts': 0}}

How to make queries using the temporary credentials?

We will now use the temprary credentials to assume the IAM role and make queries to the S3 API. The script looks like this:


# Assume the IAM role
# ...

new_session = Session(aws_access_key_id=response['Credentials']['AccessKeyId'],
                      aws_secret_access_key=response['Credentials']['SecretAccessKey'],
                      aws_session_token=response['Credentials']['SessionToken'])

 s3 = new_session.client("s3")
 s3.list_buckets()

We can now query S3 to verify that our credentials are working as expected:

{'ResponseMetadata': {'RequestId': '7TV125SMHNJ29DKB',
  'HostId': 'y9VbkFsOdiK/yoyuARs7H48SsCfSHlGOV6SEJBsOFDeWjAEGIJBlu7zH9VJ24y2cr8eTAmu30Ik=',
  'HTTPStatusCode': 200,
  'HTTPHeaders': {'x-amz-id-2': 'y9VbkFsOdiK/yoyuARs7H48SsCfSHlGOV6SEJBsOFDeWjAEGIJBlu7zH9VJ24y2cr8eTAmu30Ik=',
   'x-amz-request-id': '7TV125SMHNJ29DKB',
   'date': 'Fri, 30 Sep 2022 19:57:25 GMT',
   'content-type': 'application/xml',
   'transfer-encoding': 'chunked',
   'server': 'AmazonS3'},
  'RetryAttempts': 0},
 'Buckets': [{'Name': 'abhishek-test-bucket',
   'CreationDate': datetime.datetime(2020, 1, 23, 5, 13, 9, tzinfo=tzutc())}
 ],
}

These credentials are valid for an hour by default, after which they expire. If you try to use these credentials after they have expired, you will get an Access Denied error.

Conclusion

The entire code for this example looks like this:


import boto3
session = boto3.Session(profile_name="learnaws-test")

sts = session.client("sts")
response = sts.assume_role(
    RoleArn="arn:aws:iam::xxx:role/s3-readonly-access",
    RoleSessionName="learnaws-test-session"
)

new_session = boto3.Session(aws_access_key_id=response['Credentials']['AccessKeyId'],
                      aws_secret_access_key=response['Credentials']['SecretAccessKey'],
                      aws_session_token=response['Credentials']['SessionToken'])
s3 = new_session.client("s3")
s3.list_buckets()