【问题标题】:User Authentication for aws using Python使用 Python 对 aws 进行用户身份验证
【发布时间】:2019-02-01 14:04:18
【问题描述】:

我正在使用 Python(3.6) 和 Django(1.10) 开展一个项目,其中我使用的是 aws api,但我是 aws 新手,不知道如何验证用户身份。

我的情况是: 我需要访问用户的 aws 资源,例如 projects listbuckets list 等,为此,我需要在发出请求时验证用户特定的 API。

如何在 python 中做到这一点? 我是 aws 的新手。所以,请不要介意我的问题。

更新:

这是我尝试过的: 来自views.py:

def boto3_with_role(role_arn, session_prefix, external_id, **kwargs):
"""
Create a partially applied session to assume a role with an external id.
A unique session_name will be generated by {session_prefix}_{time}
`session` can be passed, otherwise the default sesion will be used
see: http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-api.html
"""
sts = boto3.client('sts')
res = sts.assume_role(
    RoleArn=role_arn,
    RoleSessionName='{}_{}'.format(session_prefix, int(time.time())),
    ExternalId=external_id,
)
creds = res['Credentials']
return partial(boto3.session.Session,
               aws_access_key_id=creds['AccessKeyId'],
               aws_secret_access_key=creds['SecretAccessKey'],
               aws_session_token=creds['SessionToken']
               )

class AwsAuthentication(LoginRequiredMixin, CreateView):
def post(self, request, *args, **kwargs):
    AwsSession = boto3_with_role('ARN_LINK_FROM_CUSTOMER', 'MyPrefix',
                                 'EXTERNAL_ID_FROM_CUSTOMER')
    my_session = AwsSession()
    client = my_session.resource('s3')
    for bucket in client.buckets.all():
        print(bucket.name)
        return HttpResponse('Your Bucket is: {}'.format(bucket.name))

现在,它返回:botocore.exceptions.ClientError: An error occurred (InvalidClientTokenId) when调用 AssumeRole 操作:请求中包含的安全令牌无效。

请帮帮我!

提前致谢!

【问题讨论】:

  • 您可以使用 boto3 或 awscli 来访问这些 aws 资源。但我不明白您所说的用户是您的应用程序用户还是试图访问另一个用户的资源的第三方用户是这样吗?
  • 用户将自己从我的应用程序验证到 aws,然后我的应用程序将能够访问他的资源!
  • 是的,您可以,但您必须拥有该用户的 aws 凭据。
  • 使用 boto3 python 库,“官方”aws 库。您可以在 settings.py 中存储一些环境变量,然后您应该对您发出的任何请求进行身份验证。
  • 我要构建的流程如下:我的应用中有一个按钮,上面写着 Authorize with aws 当用户单击此按钮时,他应该被重定向到另一个他需要登录到他的 aws 帐户的浏览器选项卡。

标签: python django amazon-web-services boto aws-api-gateway


【解决方案1】:

我不确定为什么其他人建议您不能这样做。这是完全正常且得到良好支持的——许多 AWS 账户用户允许第三方代表用户在用户的 AWS 账户中进行操作。例如,任何第三方监控服务或成本分析服务。

[坏方法] 第一种方法是简单地向用户询问 IAM 凭证(访问密钥和秘密密钥)。您的应用程序可以使用它们来访问用户的 AWS 账户。这很简单,但不要这样做。

[好方法] 更好的方法是通过跨帐户访问。您有一个 AWS 账户,您的用户也有一个 AWS 账户。您指示用户使用适当的 IAM 策略(您的应用程序所需的最低权限集)在其账户中创建 IAM 角色,并指示用户如何允许您的账户在用户账户中担任此角色 - 执行此操作您宣传所需的 IAM 政策和您的 AWS 帐号。然后,用户可以创建一个 IAM 策略,使用该策略创建一个角色,然后在您的账户之间建立信任关系,以便您可以代入该 IAM 角色并在他的账户中操作。有关更多信息,请参阅 herehere

【讨论】:

  • 嗨,@jarmod!首先感谢您的回答,这是有道理的,但是当用户使用我们的帐户 ID 为我的应用程序创建所需的 IAM 角色时,我如何通过 api 使用他的应用程序凭据?请你帮我提供一个代码示例!
  • 我建议您设置两个 AWS 账户,在账户 #1 中配置 IAM 策略、角色和信任关系,然后使用账户 #2 凭证使用 @987654323 代入跨账户角色@.
  • 我需要为假设角色传递哪个 RoleArn 和外部 ID?
  • 外部 ID 是可选的并且提供了更多的安全性。角色 ARN 用于标识客户账户中的 IAM 角色。用户需要与您共享两者。通常,当用户告诉您的系统您可以使用哪个 IAM 角色访问他们的账户时,您会要求用户同时提供 ARN 和外部 ID。您应该查看教程:docs.aws.amazon.com/IAM/latest/UserGuide/…
  • 授予您访问权限的用户应使用 AWS 控制台使用 IAM 创建跨账户角色 |角色 |创建角色 |另一个 AWS 账户。这将提示他们输入您的 AWS 账户 ID(用于信任关系)。一旦他们完成此操作并共享角色 ARN 和外部 ID,您账户中的任何管理员用户(或任何具有担任该命名角色的明确权限的用户)都应该能够担任该角色。我会用 awscli 试试这个,然后从图片中删除你的 Django 应用程序,直到它工作为止。
【解决方案2】:

目前不存在让用户登录其 AWS 账户以允许您的应用程序访问其 AWS 资源的功能。要考虑的一种可能的解决方法是为用户提供一个直接链接,以使用允许特定 AWS 账户的特定托管策略创建 IAM 角色。然后,您可以将其包含在您的注册流程中,并在您需要访问用户帐户中的资源时担任该角色。

示例链接:

https://console.aws.amazon.com/iam/home?region=us-west-2#/roles$new?step=review&roleType=crossAccount&accountID=123412341234&policies=arn:aws:iam::aws:policy%2FAdministratorAccess&roleName=AdminAccessForServiceName

【讨论】:

  • 嗨,@肯尼斯!这是有道理的,我的理解是:我将向用户提供一个链接以创建一个 IAM 角色,但我如何在我的场景中使用它?请您为此编写一个示例 python 代码!
  • 以下 AWS 文档包含一个 Python 示例,说明如何代入角色并使用获得的凭证。 docs.aws.amazon.com/IAM/latest/UserGuide/…
【解决方案3】:

请注意,您从 sts.AssumeRole 调用获得的凭据确实会在一段时间后过期(默认为 15 分钟,但您可以在调用 AssumeRole 时将其设置得更长,直至当前会话的最大 API 会话持续时间,通过默认 -- 1 小时),除非你刷新它们。

如果您需要自动刷新凭据,我在这里分享我在研究 boto 的代码并尝试解决 boto 对文件系统和配置文件的依赖性后编写的代码。

这里我只是使用了内置 boto 的缓存机制,并定期刷新假定的凭据,而不接触任何文件:

from datetime import datetime

import boto3
from botocore.credentials import (
    AssumeRoleProvider,
    AssumeRoleCredentialFetcher,
    DeferredRefreshableCredentials,
    CredentialResolver
)
from dateutil.tz import tzlocal


class CustomAssumeRoleProvider(AssumeRoleProvider):
    """
    Overrides default AssumeRoleProvider to not use profiles from filesystem.
    """

    def __init__(self,
                 source_session: boto3.Session,
                 assume_role_arn: str,
                 expiry_window_seconds: int):
        super().__init__(
            load_config=lambda: source_session._session.full_config,
            client_creator=source_session._session.create_client,
            cache={},
            profile_name='not-used'
        )
        self.expiry_window_seconds = expiry_window_seconds
        self.source_session = source_session
        self.assume_role_arn = assume_role_arn
        assert assume_role_arn, "assume_role_arn is required"

    def load(self):
        fetcher = AssumeRoleCredentialFetcher(
            client_creator=self.source_session._session.create_client,
            source_credentials=self.source_session.get_credentials(),
            role_arn=self.assume_role_arn,
            expiry_window_seconds=self.expiry_window_seconds,
            cache=self.cache,
        )

        return DeferredRefreshableCredentials(
            method=self.METHOD,
            refresh_using=fetcher.fetch_credentials,
            time_fetcher=lambda: datetime.now(tzlocal())
        )


def get_assume_role_session(
    source_session: boto3.Session,
    assume_role_arn: str,
    expiry_window_seconds=15 * 60
) -> boto3.Session:
    """
    Creates a new boto3 session that will operate as of another user.

    Source session must have permission to call sts:AssumeRole on the provided ARN,
    and that ARN role must have been trusted to be assumed from this account (where source_session is from).

    See https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html

    Uses internal session._session to hack it together, as I haven't found another way.
    """
    # must have .load() method to be used in CredentialsResolver.
    provider = CustomAssumeRoleProvider(
        source_session=source_session,
        assume_role_arn=assume_role_arn,
        expiry_window_seconds=expiry_window_seconds
    )

    # must have .load_credentials() method to be used in register_component()
    resolver = CredentialResolver([provider])
    new_session = boto3.Session()
    new_session._session.register_component('credential_provider', resolver)
    return new_session

【讨论】:

    猜你喜欢
    • 2016-09-27
    • 1970-01-01
    • 2018-07-13
    • 1970-01-01
    • 1970-01-01
    • 2021-04-08
    • 2018-05-22
    • 2017-04-26
    • 2020-01-01
    相关资源
    最近更新 更多