[英]How to use the AWS Python SDK while connecting via SSO credentials
I am attempting to create a python script to connect to and interact with my AWS account.我正在尝试创建一个 python 脚本来连接到我的 AWS 账户并与之交互。 I was reading up on it here https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
我在这里阅读它https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
and I see that it reads your credentials from ~/.aws/credentials (on a Linux machine).我看到它从 ~/.aws/credentials(在 Linux 机器上)读取您的凭据。 I however and not connecting with an IAM user but SSO user.
然而,我并没有连接 IAM 用户而是 SSO 用户。 Thus, the profile connection data I use is located at ~/.aws/sso/cache directory.
因此,我使用的配置文件连接数据位于 ~/.aws/sso/cache 目录。
Inside that directory, I see two json files.在该目录中,我看到两个 json 文件。 One has the following keys:
一个具有以下键:
the second has the following keys:第二个有以下键:
I don't see anywhere in the docs about how to tell it to use my SSO user.我在文档中没有看到任何关于如何告诉它使用我的 SSO 用户的信息。
Thus, when I try to run my script, I get error such as因此,当我尝试运行我的脚本时,出现如下错误
botocore.exceptions.ClientError: An error occurred (AuthFailure) when calling the DescribeSecurityGroups operation: AWS was not able to validate the provided access credentials
even though I can run the same command fine from the command prompt.即使我可以从命令提示符运行相同的命令。
So here's the long and hairy answer tested on boto3==1.21.39
:所以这是在
boto3==1.21.39
上测试的长而多毛的答案:
It's an eight-step process where:这是一个八步过程,其中:
sso-oidc.register_client
sso-oidc.register_client
注册客户端sso-oidc.start_device_authorization
sso-oidc.start_device_authorization
启动设备授权流程webbrowser.open
webbrowser.open
将用户重定向到 sso 登录页面sso-oidc.create_token
until the user completes the signinsso-oidc.create_token
直到用户完成登录sso.list_account_roles
sso.list_account_roles
列出并向用户呈现帐户角色sso.get_role_credentials
sso.get_role_credentials
获取角色凭证Step 8 is really key and should not be overlooked as part of any successful authorization flow.第 8 步非常关键,在任何成功的授权流程中都不应被忽视。
In the sample below the account_id
should be the account id of the account you are trying to get credentials for.在下面的示例中,
account_id
应该是您尝试获取凭据的帐户的帐户 ID。 And the start_url
should be the url that aws generates for you to start the sso flow (in the AWS SSO management console, under Settings). start_url
应该是 aws 为您生成的 url 以启动 sso 流程(在 AWS SSO 管理控制台中的“设置”下)。
from time import time, sleep
import webbrowser
from boto3.session import Session
session = Session()
account_id = '1234567890'
start_url = 'https://d-0987654321.awsapps.com/start'
region = 'us-east-1'
sso_oidc = session.client('sso-oidc')
client_creds = sso_oidc.register_client(
clientName='myapp',
clientType='public',
)
device_authorization = sso_oidc.start_device_authorization(
clientId=client_creds['clientId'],
clientSecret=client_creds['clientSecret'],
startUrl=start_url,
)
url = device_authorization['verificationUriComplete']
device_code = device_authorization['deviceCode']
expires_in = device_authorization['expiresIn']
interval = device_authorization['interval']
webbrowser.open(url, autoraise=True)
for n in range(1, expires_in // interval + 1):
sleep(interval)
try:
token = sso_oidc.create_token(
grantType='urn:ietf:params:oauth:grant-type:device_code',
deviceCode=device_code,
clientId=client_creds['clientId'],
clientSecret=client_creds['clientSecret'],
)
break
except sso_oidc.exceptions.AuthorizationPendingException:
pass
access_token = token['accessToken']
sso = session.client('sso')
account_roles = sso.list_account_roles(
accessToken=access_token,
accountId=account_id,
)
roles = account_roles['roleList']
# simplifying here for illustrative purposes
role = roles[0]
role_creds = sso.get_role_credentials(
roleName=role['roleName'],
accountId=account_id,
accessToken=access_token,
)
session = Session(
region_name=region,
aws_access_key_id=role_creds['accessKeyId'],
aws_secret_access_key=role_creds['secretAccessKey'],
aws_session_token=role_creds['sessionToken'],
)
This was fixed in boto3 1.14 .这已在boto3 1.14中修复。
So given you have a profile like this in your ~/.aws/config
:因此,假设您在
~/.aws/config
中有这样的配置文件:
[profile sso_profile]
sso_start_url = <sso-url>
sso_region = <sso-region>
sso_account_id = <account-id>
sso_role_name = <role>
region = <eu-west-1>
output = text
And then login with aws sso login --profile sso_profile
然后使用
aws sso login --profile sso_profile
You will be able to create a session:您将能够创建 session:
import boto3
boto3.setup_default_session(profile_name='sso_profile')
client = boto3.client('<whatever service you want>')
Your current.aws/sso/cache folder structure looks like this:您的 current.aws/sso/cache 文件夹结构如下所示:
$ ls
botocore-client-XXXXXXXX.json cXXXXXXXXXXXXXXXXXXX.json
The 2 json files contain 3 different parameters that are useful. 2 个 json 文件包含 3 个有用的不同参数。
botocore-client-XXXXXXXX.json -> clientId and clientSecret
cXXXXXXXXXXXXXXXXXXX.json -> accessToken
Using the access token in cXXXXXXXXXXXXXXXXXXX.json you can call get-role-credentials .使用 cXXXXXXXXXXXXXXXXXXXXX.json 中的访问令牌,您可以调用get-role-credentials 。 The output from this command can be used to create a new session.
此命令中的 output 可用于创建新的 session。
Your Python file should look something like this:您的 Python 文件应如下所示:
import json
import os
import boto3
dir = os.path.expanduser('~/.aws/sso/cache')
json_files = [pos_json for pos_json in os.listdir(dir) if pos_json.endswith('.json')]
for json_file in json_files :
path = dir + '/' + json_file
with open(path) as file :
data = json.load(file)
if 'accessToken' in data:
accessToken = data['accessToken']
client = boto3.client('sso',region_name='us-east-1')
response = client.get_role_credentials(
roleName='string',
accountId='string',
accessToken=accessToken
)
session = boto3.Session(aws_access_key_id=response['roleCredentials']['accessKeyId'], aws_secret_access_key=response['roleCredentials']['secretAccessKey'], aws_session_token=response['roleCredentials']['sessionToken'], region_name='us-east-1')
A well-formed boto3
-based script should transparently authenticate based on profile name.格式良好的基于
boto3
的脚本应该基于配置文件名称透明地进行身份验证。 It is not recommended to handle the cached files or keys or tokens yourself, since the official code methods might change in the future.不建议自己处理缓存的文件或密钥或令牌,因为官方代码方法将来可能会更改。 To see the state of your profile(s), run
aws configure list
--examples:要查看您的配置文件的 state,请运行
aws configure list
--examples:
$ aws configure list --profile=sso
Name Value Type Location
---- ----- ---- --------
profile sso manual --profile
The SSO session associated with this profile has expired or is otherwise invalid.
To refresh this SSO session run aws sso login with the corresponding profile.
$ aws configure list --profile=old
Name Value Type Location
---- ----- ---- --------
profile old manual --profile
access_key ****************3DSx shared-credentials-file
secret_key ****************sX64 shared-credentials-file
region us-west-1 env ['AWS_REGION', 'AWS_DEFAULT_REGION']
What works for me is the following:对我有用的是以下内容:
import boto 3
session = boto3.Session(profile_name="sso_profile_name")
session.resource("whatever")
using boto3==1.20.18
.使用
boto3==1.20.18
。
This would work if you had previously configured SSO for aws ie.如果您之前为 aws 配置了 SSO,这将起作用,即。
aws configure sso
. aws configure sso
。
Interestingly enough, I don't have to go through this if I use ipython
, I just aws sso login
beforehand and then call boto3.Session()
.有趣的是,如果我使用 ipython
,我不必通过此 go ,我只需预先aws sso login
,然后调用boto3.Session()
。I am trying to figure out whether there is something wrong with my approach - I fully agree with what was said above with respect to transparency and although it is a working solution, I am not in love with it.我试图弄清楚我的方法是否有问题——我完全同意上面关于透明度的说法,虽然这是一个可行的解决方案,但我并不喜欢它。
EDIT: there was something wrong and here is how I fixed it:编辑:出了点问题,这是我修复它的方法:
aws configure sso
(as above);aws configure sso
(如上);aws-vault
- it basically replaces aws sso login --profile <profile-name>
;aws-vault
- 它基本上取代了aws sso login --profile <profile-name>
;aws-vault exec <profile-name>
to create a sub-shell with AWS credentials exported to environment variables.aws-vault exec <profile-name>
以创建一个子 shell,其中 AWS 凭证导出到环境变量。 Doing so, it is possible to run any boto3
command both interactively (eg. iPython) and from a script, as in my case.这样做,可以交互地(例如 iPython)和从脚本运行任何
boto3
命令,就像我的例子一样。 Therefore, the snippet above simply becomes:因此,上面的代码片段就变成了:
import boto 3
session = boto3.Session()
session.resource("whatever")
Here for further details on AWS vault.在此处了解有关 AWS 保管库的更多详细信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.