From 3bd975940e2c8e8287eb43bfdd150a62ed911754 Mon Sep 17 00:00:00 2001 From: "Michael Barney, Jr" Date: Wed, 16 Oct 2024 11:05:50 -0400 Subject: [PATCH 1/3] feat(assume_role): support specifying session policy arns --- awsume/awsumepy/default_plugins.py | 25 ++++++++++++++++++++++++- awsume/awsumepy/lib/aws.py | 5 ++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/awsume/awsumepy/default_plugins.py b/awsume/awsumepy/default_plugins.py index bddcb58..648257b 100644 --- a/awsume/awsumepy/default_plugins.py +++ b/awsume/awsumepy/default_plugins.py @@ -149,6 +149,13 @@ def add_arguments(config: dict, parser: argparse.ArgumentParser): metavar='session_policy', help='Custom session policy JSON', ) + parser.add_argument('--session-policy-arns', + nargs='+', + default=[], + dest='session_policy_arns', + metavar='session_policy_arns', + help='List of policy ARNs', + ) parser.add_argument('--role-duration', action='store', dest='role_duration', @@ -345,7 +352,17 @@ def assume_role_from_cli(config: dict, arguments: dict, profiles: dict): logger.debug('Session name: {}'.format(session_name)) if not arguments.source_profile: logger.debug('Using current credentials to assume role') - role_session = aws_lib.assume_role({}, arguments.role_arn, session_name, session_policy=arguments.session_policy, region=region, external_id=arguments.external_id, role_duration=role_duration, tags=arguments.session_tags) + role_session = aws_lib.assume_role( + {}, + arguments.role_arn, + session_name, + session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, + region=region, + external_id=arguments.external_id, + role_duration=role_duration, + tags=arguments.session_tags, + ) else: logger.debug('Using the source_profile from the cli to call assume_role') source_profile = profiles.get(arguments.source_profile) @@ -364,6 +381,7 @@ def assume_role_from_cli(config: dict, arguments: dict, profiles: dict): arguments.role_arn, session_name, session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=region, external_id=arguments.external_id, role_duration=role_duration, @@ -378,6 +396,7 @@ def assume_role_from_cli(config: dict, arguments: dict, profiles: dict): arguments.role_arn, session_name, session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=region, external_id=arguments.external_id, role_duration=role_duration, @@ -403,6 +422,7 @@ def assume_role_from_cli(config: dict, arguments: dict, profiles: dict): arguments.role_arn, session_name, session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=region, external_id=arguments.external_id, role_duration=role_duration, @@ -423,6 +443,7 @@ def get_assume_role_credentials(config: dict, arguments: argparse.Namespace, pro target_profile.get('role_arn'), profile_lib.get_session_name(config, arguments, profiles, target_profile_name), session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=region, external_id=external_id, role_duration=role_duration, @@ -469,6 +490,7 @@ def get_assume_role_credentials_mfa_required(config: dict, arguments: argparse.N target_profile.get('role_arn'), profile_lib.get_session_name(config, arguments, profiles, target_profile_name), session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=region, external_id=external_id, role_duration=role_duration, @@ -500,6 +522,7 @@ def get_assume_role_credentials_mfa_required_large_custom_duration(config: dict, target_profile.get('role_arn'), profile_lib.get_session_name(config, arguments, profiles, target_profile_name), session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=region, external_id=external_id, role_duration=role_duration, diff --git a/awsume/awsumepy/lib/aws.py b/awsume/awsumepy/lib/aws.py index c4f5e04..6c7af8a 100644 --- a/awsume/awsumepy/lib/aws.py +++ b/awsume/awsumepy/lib/aws.py @@ -1,5 +1,5 @@ import os -from typing import Union +from typing import List, Union import boto3 import botocore @@ -33,6 +33,7 @@ def assume_role( role_arn: str, session_name: str, session_policy: str = None, + session_policy_arns: List[str] = [], external_id: str = None, region: str = None, role_duration: int = None, @@ -56,6 +57,8 @@ def assume_role( kwargs = { 'RoleSessionName': session_name, 'RoleArn': role_arn } if session_policy: kwargs['Policy'] = session_policy + if session_policy_arns: + kwargs['PolicyArns'] = [{'arn': arn} for arn in session_policy_arns] if external_id: kwargs['ExternalId'] = external_id if role_duration: From a5f579fa8fdfdc1b0190608712b67aeaa994ba57 Mon Sep 17 00:00:00 2001 From: "Michael Barney, Jr" Date: Wed, 16 Oct 2024 11:10:00 -0400 Subject: [PATCH 2/3] fix(tests): fix session policy arn in arg namespace --- test/unit/awsume/awsumepy/test_default_plugins.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/unit/awsume/awsumepy/test_default_plugins.py b/test/unit/awsume/awsumepy/test_default_plugins.py index 8496fca..21a41d0 100644 --- a/test/unit/awsume/awsumepy/test_default_plugins.py +++ b/test/unit/awsume/awsumepy/test_default_plugins.py @@ -11,6 +11,7 @@ def generate_namespace_with_defaults( session_policy=None, + session_policy_arns=None, session_tags=None, region=None, source_profile=None, @@ -26,8 +27,10 @@ def generate_namespace_with_defaults( who=None, **kwargs ) -> argparse.Namespace: + arns = [] if session_policy_arns is None else session_policy_arns return argparse.Namespace( session_policy=session_policy, + session_policy_arns=arns, session_tags=session_tags, region=region, source_profile=source_profile, @@ -429,6 +432,7 @@ def test_assume_role_from_cli(aws_lib: MagicMock, profile_lib: MagicMock): aws_lib.assume_role.assert_called_with( {}, arguments.role_arn, 'awsume-cli-role', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=profile_lib.get_region.return_value, external_id=arguments.external_id, role_duration=0, @@ -467,6 +471,7 @@ def test_assume_role_from_cli_source_profile(aws_lib: MagicMock, profile_lib: Ma arguments.role_arn, 'awsume-cli-role', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=profile_lib.get_region.return_value, external_id=arguments.external_id, role_duration=0, @@ -505,6 +510,7 @@ def test_assume_role_from_cli_source_profile_role_duration_mfa(aws_lib: MagicMoc arguments.role_arn, 'awsume-cli-role', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=profile_lib.get_region.return_value, external_id=arguments.external_id, role_duration='43200', @@ -544,6 +550,7 @@ def test_assume_role_from_cli_source_profile_role_duration_no_mfa(aws_lib: Magic arguments.role_arn, 'awsume-cli-role', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=profile_lib.get_region.return_value, external_id=arguments.external_id, role_duration='43200', @@ -589,6 +596,7 @@ def test_assume_role_from_cli_source_profile_no_role_duration_mfa(aws_lib: Magic arguments.role_arn, 'awsume-cli-role', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=profile_lib.get_region.return_value, external_id=arguments.external_id, role_duration=0, @@ -626,6 +634,7 @@ def test_assume_role_from_cli_source_profile_no_role_duration_no_mfa(aws_lib: Ma arguments.role_arn, 'awsume-cli-role', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=profile_lib.get_region.return_value, external_id=arguments.external_id, role_duration=0, @@ -699,6 +708,7 @@ def test_get_credentials(aws_lib: MagicMock, create_autoawsume_profile: MagicMoc 'myrolearn', 'mysessionname', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=None, external_id='myexternalid', role_duration=0, @@ -752,6 +762,7 @@ def test_get_credentials_auto_refresh(aws_lib: MagicMock, create_autoawsume_prof 'myrolearn', 'mysessionname', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=None, external_id='myexternalid', role_duration=0, @@ -795,6 +806,7 @@ def test_get_credentials_role_duration(aws_lib: MagicMock, create_autoawsume_pro 'myrolearn', 'mysessionname', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=None, external_id='myexternalid', role_duration=43200, @@ -910,6 +922,7 @@ def test_get_credentials_no_mfa_role(aws_lib: MagicMock, create_autoawsume_profi 'myrolearn', 'mysessionname', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, region=None, external_id='myexternalid', role_duration=0, @@ -1009,6 +1022,7 @@ def test_post_add_arguments_session_tags(aws_lib: MagicMock): arguments.role_arn, 'awsume-cli-role', session_policy=arguments.session_policy, + session_policy_arns=arguments.session_policy_arns, external_id=arguments.external_id, role_duration='43200', tags=[ From a8c3e787fb32b6cd8601f8e1beb0dd09bdac1345 Mon Sep 17 00:00:00 2001 From: "Michael Barney, Jr" Date: Wed, 11 Dec 2024 15:32:21 -0500 Subject: [PATCH 3/3] fix(docs): add session policy and policy arn usage documentation --- docs/general/usage.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/docs/general/usage.md b/docs/general/usage.md index ca0dcba..fb84ab1 100644 --- a/docs/general/usage.md +++ b/docs/general/usage.md @@ -9,8 +9,9 @@ usage: awsume [-h] [-v] [-r] [-s] [-u] [-a] [-k] [-o] [-l [more]] [--refresh-autocomplete] [--role-arn role_arn] [--source-profile source_profile] [--external-id external_id] [--mfa-token mfa_token] [--region region] - [--session-name session_name] [--role-duration role_duration] - [--with-saml | --with-web-identity] + [--session-name session_name] [--session-policy session_policy] + [--session-policy-arns session_policy_arns [session_policy_arns...]] + [--role-duration role_duration] [--with-saml | --with-web-identity] [--credentials-file credentials_file] [--config-file config_file] [--config [option [option ...]]] [--info] [--debug] [profile_name] @@ -36,6 +37,8 @@ optional arguments: --mfa-token mfa_token Your mfa token --region region The region you want to awsume into --session-name session_name Set a custom role session name + --session-policy session_policy Custom session policy JSON + --session-policy-arns [arns ...] List of policy ARNs --role-duration role_duration Seconds to get role creds for --with-saml Use saml (requires plugin) --with-web-identity Use web identity (requires plugin) @@ -139,6 +142,23 @@ You can target a specific region to awsume with the `--region` flag. This basica You can supply your own session name to the `assume_role` call with the `--session-name` flag. +## Session Policy, Policy ARNs + +You can define your own session policy for a given `awsume` session. +You can do this by specifying the policy JSON or a list of policy ARNs. + +Specifying policy JSON: + +```sh +$ awsume myprofile --session-policy '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*"}]}' +``` + +Specifying policy ARNs: + +```sh +$ awsume myprofile --session-policy-arns 'arn:aws:iam::aws:policy/job-function/Billing' +``` + ## Role Duration You can also supply a custom role duration (up to 43200) for the number of seconds to request role credentials for with the `--role-duration` flag.