boto / boto3

AWS SDK for Python
https://aws.amazon.com/sdk-for-python/
Apache License 2.0
9.06k stars 1.87k forks source link

Allow using AWS_ROLE_ARN to assume role without web identity #2360

Open IuryAlves opened 4 years ago

IuryAlves commented 4 years ago

Is your feature request related to a problem? Please describe.

I recently discovered that boto has the feature of assuming a role using a web identity if AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE are provided.

But it is not possible to assume a role (AssumeRole operation) using only AWS_ROLE_ARN.

The only way we have to assume role is to execute the following steps:

aws sts assume-role --role-arn arn:aws:iam::ACCOUNT:role/ROLE_NAME --role-session-name my-role
# Then get the credentials from the output of the command above and export them 

I am also open to suggestions on how to make that easier.

Describe the solution you'd like

I would like to be able to assume other roles by providing the AWS_ROLE_ARN env var.

NOTE: I want to assume a role using AssumeRole, not AssumeRoleWithWebIdentity

Thanks!

vaisakhpisharody commented 3 years ago

This would be a helpful feature for everyone who has their custom wrappers create the assume role. If boto3, could get the credentials on its own, a lot of code duplication would go away.

I have setup something for this for my need, which was something like

import boto3

def get_aws_sts_assume_role_credentials():
    sts_client = boto3.client("sts")
    aws_assume_role_arn = os.environ.get("AWS_ASSUME_ROLE_ARN")

    credentials = sts_client.assume_role(
        RoleArn="aws_assume_role_arn", RoleSessionName="mlflow_user", DurationSeconds=3600)

    return credentials["Credentials"]

And in my code where I create the s3 Client

import boto3

credentials = get_aws_sts_assume_role_credentials()
my_s3_client = boto3.client(
    "s3",
    aws_access_key_id=credentials["AccessKeyId"],
    aws_secret_access_key=credentials["SecretAccessKey"],
    aws_session_token=credentials["SessionToken"]
    # add other params if needed
)

I would be happy to raise a PR and merge this code if this solution works. Please let me know in case I missed something.

Thanks, Vaisakh Pisharody

benkehoe commented 3 years ago

@vaisakhpisharody This request would require a new botocore.credentials.CredentialProvider subclass or an update to botocore.credentials.AssumeRoleProvider, which currently doesn't look at environment variables (unlike AssumeRoleWithWebIdentityProvider).

For programmatic role assumption, I opened PR https://github.com/boto/botocore/pull/2096 months ago to add the necessary CredentialProvider but it has not received a response. I created aws-assume-role-lib to get around that; it has a patch_boto3() function that adds boto3.assume_role() and boto3.Session.assume_role().

vaisakhpisharody commented 3 years ago

Hi @benkehoe

This looks like something cool that could be merged, but I still don't understand how this change would refresh credentials on its own?

Also, we would have to write patching refreshing credentials function, and that would work only in case where we use the boto3 client directly right? That won't be possible if we are using packages which use boto3 internally, right? (where we can't edit code). For example: mlflow.

Please let me know in case I missed something.

Thanks, Vaisakh Pisharody

benkehoe commented 3 years ago

@vaisakhpisharody The original request is that there is an environment variable that cause a role to be assumed based on other AWS credentials. This would need to be implemented in botocore, and would then work for both the AWS CLI and boto3. Currently, role assumption is possible using ~/.aws/config, which looks like:

[profile my-source-profile]
region = us-east-2

[profile my-assume-role-profile]
role_arn = arn:aws:iam::ACCOUNT:role/ROLE_NAME
source_profile = my-source-profile
region = us-east-2

where the credentials for my-source-profile are in ~/.aws/credentials.

Then you can do (for example) aws sts get-caller-identity --profile my-assume-role-profile or in python boto3.Session(profile_name='my-assume-role-profile').client('sts').get_caller_identity().

The web identity provider works a similar way. You can have your ~/.aws/config look like this:

[profile my-web-identity-profile]
role_arn = arn:aws:iam::ACCOUNT:role/ROLE_NAME
web_identity_token_file = /path/to/file

However, the web identity provider is implemented in such a way that it also looks for role_arn and web_identity_token_file in environment variables. The assume role provider doesn't. Note that there's several more parameters you can use with AssumeRole than with AssumeRoleWithWebIdentity.

As you say, the aws-assume-role-lib option, and the code you provided above, only works if you are in control of the code that uses boto3, or if such code takes a boto3 session as input.

However, if the code uses the module-level boto3.client() or boto3.resource() function, rather than first creating a session and using that, you can, in your code, create the assumed role session using aws-assume-role-lib and set boto3.DEFAULT_SESSION to that (which is what the module-level client and resource functions use).

mattghali commented 2 years ago

Hi! Just pinging to see if there is motion on this request- it would make our use of cloudwatch log pushers (from the v1 awscli) much more flexible.

talayalon commented 2 months ago

Hi! Pinging to see if there is any progress here