10
10
from os import environ
11
11
from platform import system
12
12
13
+ import boto3
13
14
import botocore
14
15
import botocore .exceptions
15
16
import botocore .session
97
98
is_flag = True ,
98
99
help = 'Output a URL that lets users who sign in to your organization\' s network securely access the AWS Management Console.' ,
99
100
)
101
+ @click .option (
102
+ "--console-role-arn" ,
103
+ help = "Role to assume for use in conjunction with --print-console-signin-url" ,
104
+ )
105
+ @click .option (
106
+ "--console-external-id" ,
107
+ help = "External ID to pass in assume role for use in conjunction with --print-console-signin-url" ,
108
+ )
100
109
@click .option (
101
110
'--role-arn' ,
102
111
help = 'Predefined role arn to selects, e.g. aws-adfs login --role-arn arn:aws:iam::123456789012:role/YourSpecialRole' ,
@@ -141,6 +150,8 @@ def login(
141
150
stdout ,
142
151
printenv ,
143
152
print_console_signin_url ,
153
+ console_role_arn ,
154
+ console_external_id ,
144
155
role_arn ,
145
156
session_duration ,
146
157
no_session_cache ,
@@ -269,7 +280,9 @@ def login(
269
280
_emit_summary (config , aws_session_duration )
270
281
_print_environment_variables (aws_session_token , config )
271
282
elif print_console_signin_url :
272
- _print_console_signin_url (aws_session_token , adfs_host )
283
+ _print_console_signin_url (
284
+ aws_session_token , adfs_host , console_role_arn , console_external_id
285
+ )
273
286
else :
274
287
_store (config , aws_session_token )
275
288
_emit_summary (config , aws_session_duration )
@@ -300,9 +313,43 @@ def _print_environment_variables(aws_session_token, config):
300
313
u"""{} AWS_DEFAULT_REGION={}""" .format (envcommand , config .region ))
301
314
302
315
303
- def _print_console_signin_url (aws_session_token , adfs_host ):
316
+ def _print_console_signin_url (
317
+ aws_session_token , adfs_host , console_role_arn , console_external_id
318
+ ):
304
319
# The steps below come from https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html
305
320
321
+ if console_role_arn :
322
+ # Step 2: Using the access keys for an IAM user in your AWS account,
323
+ # call "AssumeRole" to get temporary access keys for the federated user
324
+
325
+ # Note: Calls to AWS STS AssumeRole must be signed using the access key ID
326
+ # and secret access key of an IAM user or using existing temporary credentials.
327
+ # The credentials can be in EC2 instance metadata, in environment variables,
328
+ # or in a configuration file, and will be discovered automatically by the
329
+ # client('sts') function. For more information, see the Python SDK docs:
330
+ # http://boto3.readthedocs.io/en/latest/reference/services/sts.html
331
+ # http://boto3.readthedocs.io/en/latest/reference/services/sts.html#STS.Client.assume_role
332
+
333
+ # FIXME: use botocore instead of boto3: https://github.com/boto/botocore/blob/1.21.49/botocore/credentials.py#L766
334
+ sts_connection = boto3 .client (
335
+ "sts" ,
336
+ aws_access_key_id = aws_session_token ["Credentials" ]["AccessKeyId" ],
337
+ aws_secret_access_key = aws_session_token ["Credentials" ]["SecretAccessKey" ],
338
+ aws_session_token = aws_session_token ["Credentials" ]["SessionToken" ],
339
+ )
340
+
341
+ if console_external_id :
342
+ aws_session_token = sts_connection .assume_role (
343
+ RoleArn = console_role_arn ,
344
+ RoleSessionName = "aws-adfs" ,
345
+ ExternalId = console_external_id ,
346
+ )
347
+ else :
348
+ aws_session_token = sts_connection .assume_role (
349
+ RoleArn = console_role_arn ,
350
+ RoleSessionName = "aws-adfs" ,
351
+ )
352
+
306
353
# Step 3: Format resulting temporary credentials into JSON
307
354
url_credentials = {}
308
355
url_credentials ['sessionId' ] = aws_session_token ['Credentials' ]['AccessKeyId' ]
@@ -314,7 +361,11 @@ def _print_console_signin_url(aws_session_token, adfs_host):
314
361
# the sign-in action request, a 12-hour session duration, and the JSON document with temporary credentials
315
362
# as parameters.
316
363
request_parameters = "?Action=getSigninToken"
317
- request_parameters += "&SessionDuration=43200"
364
+
365
+ # https://signin.aws.amazon.com/federation endpoint returns a HTTP/1.1 400 Bad Request error with AssumeRole credentials when SessionDuration is set
366
+ if not console_role_arn :
367
+ request_parameters += "&SessionDuration=43200"
368
+
318
369
request_parameters += "&Session=" + urllib .parse .quote_plus (json_string_with_temp_credentials )
319
370
request_url = "https://signin.aws.amazon.com/federation" + request_parameters
320
371
r = requests .get (request_url )
0 commit comments