我已经编写了一个脚本,使用python SDK和Boto3查询DynamoDB表。AWS IAM角色需要MFA,并且使用VSCode终端(版本:1.71.1-通用(,我可以成功地进行身份验证并运行以下操作以获取session_token,用于创建经过身份验证的Dynamo DB客户端:
def create_authenticated_dynamo_dict() -> dict:
user_serial_number = input('Enter ARN serial number, e.g. arn:aws:iam::123456789012:mfa/user: ')
user_role = 'arn:aws:iam::XXXXXXXXXXXXXXX:role/{role_name}'
mfa = input('Enter the user device MFA code: ')
client = boto3.client('sts')
mfa_sts_client = client.get_session_token(
DurationSeconds=900,
SerialNumber=user_serial_number,
TokenCode=mfa
) ...
然而,当我在PyCharm(PyCharm 2022.2.2(或本机Mac终端(M1 2020,macOS Monterey v 12.5.1(中运行相同的代码时,我收到了AWS对MFA的额外(额外(请求(在将MFA代码输入到终端输入后(,身份验证失败,出现以下错误:
botocore.exceptions.ClientError: An error occurred (AccessDenied) when
calling the GetSessionToken operation: Cannot call GetSessionToken
with session credentials
我为VSCode、PyCharm和macOS终端验证了zsh-shell,但很明显,PyCharm/Mac本地终端和VSCode之间存在一些配置差异。我想在PyCharm中运行这个。最终,我想了解为什么会发生这种情况,特别是当应该从参数中读取到client.get_session_token
时,是什么导致了对MFA令牌的额外请求。
我最终能够在Pycharm、VSCode和本机OSX终端上成功进行身份验证。我认为问题在于,无论是Pycharm还是原生OSX,Boto3都会默认为假设当前终端窗口中最近导出的AWS配置文件。这解释了对MFA的意外额外请求——我的脚本中的用户值被忽略了,并且使用的会话凭据不正确。
所以我总是从一个新的终端窗口运行脚本来解决这个问题。我还更新了Pycharm(2022.2.3(。以下是我现在用于身份验证的完整方法:
- 创建新的boto3
sts
客户端 - 此客户端上的
get_session_token
,带有用户MFA代码 - 使用第一个客户端的
credentials
创建另一个新的boto3sts
客户端 - 具有第二客户端和用户IAM角色的
assume_role
- 使用第二个客户端的凭据创建新的boto3
DynamoDB
客户端
使用这个客户端,我能够使用表的名称成功地进行DynamoDB查询,如下所示:
user_serial_number = input('Enter ARN serial number, e.g. arn:aws:iam::123456789012:mfa/user: ')
role = input('Enter AWS Role: e.g. arn:aws:iam::XXXXXXXXXXXXXXXX:role/{name of aws role from credentials file}: ')
mfa = input('Enter the MFA code: ')
mfa_sts_client = boto3.client('sts')
# Credentials are good for 1 hour
mfa_credentials = mfa_sts_client.get_session_token(
DurationSeconds=3600,
SerialNumber=user_serial_number,
TokenCode=mfa
)['Credentials']
# Create a new client with credentials from the MFA enabled session we created above:
assumed_role_sts_client = boto3.client(
'sts',
aws_access_key_id=mfa_credentials['AccessKeyId'],
aws_secret_access_key=mfa_credentials['SecretAccessKey'],
aws_session_token=mfa_credentials['SessionToken']
)
# assume role with the authenticated client
assumed_role_res = assumed_role_sts_client.assume_role(
RoleArn=role,
RoleSessionName='{session name can be anything}'
)
# get temporary credentials from the assumed role
tmp_creds = assumed_role_res['Credentials']
# create authenticated DynamoDB client with the temporary credentials
dynamo_client = boto3.client(
'dynamodb',
region_name='{aws region of table, e.g. 'us-east-1'}',
aws_access_key_id=tmp_creds['AccessKeyId'],
aws_secret_access_key=tmp_creds['SecretAccessKey'],
aws_session_token=tmp_creds['SessionToken']
)
response = dynamo_client.describe_table(
TableName='{name_of_table}'
)