如何在通过SSO凭据连接时使用AWS Python SDK

dm7nw8vv  于 11个月前  发布在  Python
关注(0)|答案(6)|浏览(97)

我试图创建一个Python脚本来连接到我的AWS帐户并与之交互。我在这里阅读它https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
我看到它从~/.aws/credentials(在Linux机器上)读取您的凭据。然而,我没有与IAM用户连接,而是与SSO用户连接。因此,我使用的配置文件连接数据位于~/.aws/sso/cache目录。
在该目录中,我看到两个json文件。其中一个具有以下键:

  • startUrl
  • 区域
  • accessToken
  • AmmoresAt

第二个具有以下键:

  • clientId
  • clientSecret
  • AmmoresAt

我在文档中没有看到任何关于如何告诉它使用我的SSO用户的地方。
因此,当我尝试运行我的脚本时,我会得到如下错误:

botocore.exceptions.ClientError: An error occurred (AuthFailure) when calling the DescribeSecurityGroups operation: AWS was not able to validate the provided access credentials

字符串
即使我可以从命令提示符运行相同的命令。

eyh26e7m

eyh26e7m1#

这在boto3 1.14中得到了修复。
因此,如果您在~/.aws/config中有这样的配置文件:

[profile sso_profile]
sso_start_url = <sso-url>
sso_region = <sso-region>
sso_account_id = <account-id>
sso_role_name = <role>
region = <default region>
output = <default output (json or text)>

字符串
然后用$ aws sso login --profile sso_profile登录
您可以创建一个会话:

import boto3
boto3.setup_default_session(profile_name='sso_profile')
client = boto3.client('<whatever service you want>')

vawmfj5a

vawmfj5a2#

已于2023.10.23发布最新的boto 3(hat tip commenter @Adam Smith,他的无形之手引导我们在boto 3的新版本中更新提取角色凭据):
下面是在boto3==1.28.69上测试的一个冗长而令人毛骨悚然的答案:
这是一个八步的过程,其中:
1.使用sso-oidc.register_client注册客户端
1.使用sso-oidc.start_device_authorization启动设备授权流
1.使用webbrowser.open将用户重定向到sso登录页
1.轮询sso-oidc.create_token,直到用户完成登录
1.使用sso.list_account_roles列出并向用户显示帐户角色
1.使用sso.get_role_credentials获取角色凭据
1.使用来自(6)的会话凭证创建新的boto 3会话
1.吃饼干
第8步是真正的关键,不应该被忽视,作为任何成功的授权流程的一部分。
在下面的示例中,account_id应该是您试图获取凭据的帐户的帐户ID。start_url应该是AWS为您生成的用于启动SSO流的URL(在AWS SSO管理控制台中,在设置下)。

from time import time, sleep
import webbrowser
from boto3.session import Session

# if your sso is setup in a different region, you will
# want to include region_name=sso_region in the 
# session constructor below
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]

# earlier versions of the sso api returned the 
# role credentials directly, but now they appear
# to be in a subkey called `roleCredentials`
role_creds = sso.get_role_credentials(
    roleName=role['roleName'],
    accountId=account_id,
    accessToken=access_token,
)['roleCredentials']
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'],
)

字符串

hmmo2u0o

hmmo2u0o3#

您当前的.aws/sso/cache文件夹结构如下所示:

$ ls
botocore-client-XXXXXXXX.json       cXXXXXXXXXXXXXXXXXXX.json

字符串
这两个json文件包含3个不同的有用参数。

botocore-client-XXXXXXXX.json -> clientId and clientSecret
cXXXXXXXXXXXXXXXXXXX.json -> accessToken


使用cXXXXXXXXXXXXXXXXX.json中的访问令牌,您可以调用get-role-credentials。此命令的输出可用于创建新会话。
你的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')

ibps3vxo

ibps3vxo4#

一个格式良好的基于boto3的脚本应该基于配置文件名透明地进行身份验证。不建议您自己处理缓存的文件或密钥或令牌,因为官方代码方法可能会在将来更改。要查看您的配置文件的状态,请运行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']

字符串

rsaldnfx

rsaldnfx5#

对我有效的方法如下:

import boto 3

session = boto3.Session(profile_name="sso_profile_name")
session.resource("whatever")

字符串
使用boto3==1.20.18
如果您之前已为aws(即aws configure sso)配置了SSO,则此操作将有效。
有趣的是,如果我使用ipython,我不必经历这些,我只是事先调用aws sso login,然后调用boto3.Session()。我试图弄清楚我的方法是否有问题-我完全同意上面关于透明度的说法,尽管它是一个可行的解决方案,但我并不喜欢它。
编辑:有一些错误,下面是我如何修复它:
1.运行aws configure sso(如上所述);
1.安装aws-vault-它基本上取代了aws sso login --profile <profile-name>;
1.运行aws-vault exec <profile-name>创建一个子shell,并将AWS凭据导出到环境变量中。
这样,就可以交互地(例如iPython)或从脚本运行任何boto3命令,就像我的例子一样。

import boto 3

session = boto3.Session()
session.resource("whatever")


Here,了解有关AWS存储库的更多详细信息。

btxsgosb

btxsgosb6#

如果您以前在终端中执行过aws sso configure命令并按照提示操作,那么您的~/.aws/config文件中应该有以下内容。

[profile <profile_name>]
sso_session = <sso_session_name>
sso_account_id = <account_id>
sso_role_name = <role_name>
region = <region>
output = text
[sso-session <sso_session_name>]
sso_start_url = <sso_start_url>
sso_region = <region>
sso_registration_scopes = sso:account:access

字符串
在使用aws sso login --profile <profile_name>登录终端后,其中<profile_name>必须与上面~/.aws/config文件中的一个配置文件匹配,您需要将AWS_PROFILE环境变量设置为与上面相同的配置文件名称。如果您只想为当前终端设置环境变量,(在这里运行Python脚本),在终端中运行export AWS_PROFILE=<profile_name>。或者如果它是你经常使用的配置文件,将上面相同的export语句添加到类似~/.bashrc的文件中。

相关问题