使自定义身份代理能够访问 AWS 控制台 - AWS Identity and Access Management

使自定义身份代理能够访问 AWS 控制台

您可以通过编写和运行代码来创建 URL 以使登录到您组织网络的用户能够安全访问 AWS Management Console。该 URL 包含您从 AWS 获得的登录令牌,而令牌则用于对访问 AWS 的用户进行身份验证。由于联合身份验证的原因,显示的控制台会话可能包含不同的 AccessKeyId。要通过相关 CloudTrail 事件跟踪联合身份验证登录的访问密钥使用情况,请参阅 使用 AWS CloudTrail 记录 IAM 和 AWS STS API 调用AWS Management Console 登录事件

注意

如果您的组织使用与 SAML 兼容的身份提供程序 (IdP),则无需编写代码即可设置对控制台的访问权限。这适用于 Microsoft 的 Active Directory 联合身份验证服务或开源 Shibboleth 等提供商。有关详细信息,请参阅使 SAML 2.0 联合身份用户能够访问 AWS Management Console

要使您组织的用户能够访问 AWS Management Console,可以创建执行以下步骤的自定义身份代理

  1. 确认您的本地身份系统已对用户进行身份验证。

  2. 调用 AWS Security Token Service (AWS STS) AssumeRole(推荐)或 GetFederationToken API 操作为该用户获取临时安全凭证。要了解在担任角色时使用的各种方法,请参阅担任角色的方法。要了解在获取安全凭证时如何传递可选的会话标签,请参阅在 AWS STS 中传递会话标签

    • 如果使用某个 AssumeRole* API 操作获取角色的临时安全凭证,您可以在调用中包含 DurationSeconds 参数。该参数指定 900 秒 (15 分钟) 到角色的最大会话持续时间设置之间的角色会话持续时间。在 AssumeRole* 操作中使用 DurationSeconds 时,必须以具有长期凭证的 IAM 用户身份调用该操作。否则,在步骤 3 中对联合终端节点的调用将失败。要了解如何查看或更改角色的最大值,请参阅更新角色的最长会话持续时间

    • 如果使用 GetFederationToken API 操作获取凭证,您可以在调用中包含 DurationSeconds 参数。该参数指定您的角色会话的持续时间。该值的范围是 900 秒 (15 分钟) 到 129,600 秒 (36 小时)。您只能使用 IAM 用户的长期 AWS 安全凭证进行该 API 调用。您还可以使用 AWS 账户根用户凭证进行这些调用,但我们不建议使用这种方法。如果您以根用户身份进行该调用,则会话默认持续 1 小时。或者,您可以指定 900 秒 (15 分钟) 到 3,600 秒 (1 小时) 之间的会话。

  3. 调用 AWS 联合终端节点并提供临时安全凭证来请求登录令牌。

  4. 构造包含该令牌的控制台 URL:

    • 如果在 URL 中使用某个 AssumeRole* API 操作,您可以包含 SessionDuration HTTP 参数。该参数指定控制台会话持续时间,范围是 900 秒 (15 分钟) 到 43200 秒 (12 小时)。

    • 如果在 URL 中使用 GetFederationToken API 操作,您可以包含 DurationSeconds 参数。该参数指定联合控制台会话的持续时间。该值的范围是 900 秒 (15 分钟) 到 129,600 秒 (36 小时)。

      注意
      • 如果使用 GetFederationToken 获取临时凭证,请不要使用 SessionDuration HTTP 参数。这会导致操作失败。

      • 使用一个角色的凭证担任其他角色称为 role chaining(角色链)。在使用角色链时,新凭证的最大持续时间限制为 1 小时。当您使用角色向 EC2 实例上运行的应用程序授予权限时,则这些应用程序不受制于此限制。

  5. 将 URL 分配给用户或代表用户调用 URL。

联合终端节点提供的 URL 在创建后的 15 分钟内有效。这不同于与 URL 关联的临时安全凭证会话的持续时间 (以秒为单位)。这些凭证在创建时指定的持续时间内有效,从创建时算起。

重要

如果您在关联的临时安全凭证中启用了权限,则该 URL 授予通过 AWS Management Console访问您的 AWS 资源的权限。因此,您应该视 URL 为机密。我们建议您通过安全的重定向返回 URL,例如,在 SSL 连接上使用 302 HTTP 响应状态代码。有关 302 HTTP 响应状态代码的详细信息,请参阅 RFC 2616,第 10.3.3 节

要完成这些任务,您可以使用适用于 AWS Identity and Access Management 的 HTTPS 查询 API (IAM)AWS Security Token Service (AWS STS)。或者,您可以将编程语言(例如 Java、Ruby 或 C#)与相应的 AWS 开发工具包结合使用。以下主题分别说明了这些方式。

您可以构造一个 URL,此 URL 向您的联合身份用户授予对 AWS Management Console的直接访问权限。此任务使用 IAM 和 AWS STS HTTPS 查询 API。有关提出查询请求的详细信息,请参阅提出查询请求

注意

以下过程包括了文本字符串的例子。为增加可读性,一些较长的例子中添加了换行符。如果您要创建并使用这些字符串,必须省略所有换行符。

向联合身份用户授予从 AWS Management Console访问您的资源的权限
  1. 在您的身份验证系统里验证该用户

  2. 为用户获取临时安全凭证。临时凭证由访问密钥 ID、秘密访问密钥和会话令牌组成。有关创建临时凭证的详细信息,请参阅IAM 临时安全凭证

    要获取临时凭证,您可以调用 AWS STS AssumeRole API(推荐)或 GetFederationToken API。有关这些 API 操作之间区别的更多信息,请参阅 AWS 安全博客中的了解安全地委派您的 AWS 账户访问权限的 API 选项

    重要

    在使用 GetFederationToken API 创建临时安全凭证时,您必须指定这些凭证为担任角色的用户授予的权限。对于任何以 AssumeRole* 开头的 API 操作,可使用 IAM 角色来分配权限。对于其他 API 操作,机制因 API 而异。有关更多详细信息,请参阅控制临时安全凭证的权限。此外,如果使用 AssumeRole* API 操作,您还必须以具有长期凭证的 IAM 用户身份调用这些操作。否则,在步骤 3 中对联合终端节点的调用将失败。

  3. 在获取临时安全凭证后,将其构建到 JSON 会话字符串以将其交换为登录令牌。下例展示如何将凭证编码。请将占位符文本替换为上一步骤中接收的凭证中的相应值。

    {"sessionId":"*** temporary access key ID ***", "sessionKey":"*** temporary secret access key ***", "sessionToken":"*** session token ***"}
  4. URL 编码上一步骤中的会话字符串。由于您编码的信息是敏感信息,因此建议您避免对此编码使用 Web 服务。请改用开发工具包中在本地安装的函数或功能来安全地编码这些信息。您可以使用 Python 的 urllib.quote_plus 函数、Java 的 URLEncoder.encode 函数或 Ruby 的 CGI.escape 函数。请参阅本主题后面的示例。

  5. 注意

    AWS 在此处支持 POST 请求。

    最后,创建联合身份用户可用于访问 AWS Management Console的 URL。此 URL 与您在步骤 5 中使用的联合 URL 终端节点相同,外加以下参数:

    ?Action = login &Issuer = *** the form-urlencoded URL for your internal sign-in page *** &Destination = *** the form-urlencoded URL to the desired AWS console page *** &SigninToken = *** the value of SigninToken received in the previous step ***
    注意

    此步骤中的以下说明仅适用于 GET API。

    下列 URL 为 URL 最终形式的示例。URL 的有效期为 15 分钟,自创建时算起。在 URL 中嵌入的临时安全凭证和控制台会话的有效期为在最初请求它们时在 SessionDuration HTTP 参数中指定的持续时间。

    https://signin.aws.amazon.com/federation ?Action=login &Issuer=https%3A%2F%2Fexample.com &Destination=https%3A%2F%2Fconsole.aws.amazon.com%2F &SigninToken=VCQgs5qZZt3Q6fn8Tr5EXAMPLEmLnwB7JjUc-SHwnUUWabcRdnWsi4DBn-dvC CZ85wrD0nmldUcZEXAMPLE-vXYH4Q__mleuF_W2BE5HYexbe9y4Of-kje53SsjNNecATfjIzpW1 WibbnH6YcYRiBoffZBGExbEXAMPLE5aiKX4THWjQKC6gg6alHu6JFrnOJoK3dtP6I9a6hi6yPgm iOkPZMmNGmhsvVxetKzr8mx3pxhHbMEXAMPLETv1pij0rok3IyCR2YVcIjqwfWv32HU2Xlj471u 3fU6uOfUComeKiqTGX974xzJOZbdmX_t_lLrhEXAMPLEDDIisSnyHGw2xaZZqudm4mo2uTDk9Pv 9l5K0ZCqIgEXAMPLEcA6tgLPykEWGUyH6BdSC6166n4M4JkXIQgac7_7821YqixsNxZ6rsrpzwf nQoS14O7R0eJCCJ684EXAMPLEZRdBNnuLbUYpz2Iw3vIN0tQgOujwnwydPscM9F7foaEK3jwMkg Apeb1-6L_OB12MZhuFxx55555EXAMPLEhyETEd4ZulKPdXHkgl6T9ZkIlHz2Uy1RUTUhhUxNtSQ nWc5xkbBoEcXqpoSIeK7yhje9Vzhd61AEXAMPLElbWeouACEMG6-Vd3dAgFYd6i5FYoyFrZLWvm 0LSG7RyYKeYN5VIzUk3YWQpyjP0RiT5KUrsUi-NEXAMPLExMOMdoODBEgKQsk-iu2ozh6r8bxwC RNhujg

以下示例说明了如何使用 Python 以编程方式构造授予联合用户 AWS Management Console 直接访问权限的 URL。以下是两个示例:

  • 通过 GET 请求联合到 AWS

  • 通过 POST 请求联合到 AWS

这两个示例都使用 AWS SDK for Python (Boto3)AssumeRole API 获取临时安全凭证。

使用 GET 请求

import urllib, json, sys import requests # 'pip install requests' import boto3 # AWS SDK for Python (Boto3) 'pip install boto3' # Step 1: Authenticate user in your own identity system. # Step 2: Using the access keys for an IAM user in your AWS 账户, # call "AssumeRole" to get temporary access keys for the federated user # Note: Calls to AWS STS AssumeRole must be signed using the access key ID # and secret access key of an IAM user or using existing temporary credentials. # The credentials can be in Amazon EC2 instance metadata, in environment variables, # or in a configuration file, and will be discovered automatically by the # client('sts') function. For more information, see the Python SDK docs: # http://boto3.readthedocs.io/en/latest/reference/services/sts.html # http://boto3.readthedocs.io/en/latest/reference/services/sts.html#STS.Client.assume_role sts_connection = boto3.client('sts') assumed_role_object = sts_connection.assume_role( RoleArn="arn:aws:iam::account-id:role/ROLE-NAME", RoleSessionName="AssumeRoleSession", ) # Step 3: Format resulting temporary credentials into JSON url_credentials = {} url_credentials['sessionId'] = assumed_role_object.get('Credentials').get('AccessKeyId') url_credentials['sessionKey'] = assumed_role_object.get('Credentials').get('SecretAccessKey') url_credentials['sessionToken'] = assumed_role_object.get('Credentials').get('SessionToken') json_string_with_temp_credentials = json.dumps(url_credentials) # Step 4. Make request to AWS federation endpoint to get sign-in token. Construct the parameter string with # the sign-in action request, a 12-hour session duration, and the JSON document with temporary credentials # as parameters. request_parameters = "?Action=getSigninToken" request_parameters += "&SessionDuration=43200" if sys.version_info[0] < 3: def quote_plus_function(s): return urllib.quote_plus(s) else: def quote_plus_function(s): return urllib.parse.quote_plus(s) request_parameters += "&Session=" + quote_plus_function(json_string_with_temp_credentials) request_url = "https://signin.aws.amazon.com/federation" + request_parameters r = requests.get(request_url) # Returns a JSON document with a single element named SigninToken. signin_token = json.loads(r.text) # Step 5: Create URL where users can use the sign-in token to sign in to # the console. This URL must be used within 15 minutes after the # sign-in token was issued. request_parameters = "?Action=login" request_parameters += "&Issuer=Example.org" request_parameters += "&Destination=" + quote_plus_function("https://console.aws.amazon.com/") request_parameters += "&SigninToken=" + signin_token["SigninToken"] request_url = "https://signin.aws.amazon.com/federation" + request_parameters # Send final URL to stdout print (request_url)

使用 POST 请求

import urllib, json, sys import requests # 'pip install requests' import boto3 # AWS SDK for Python (Boto3) 'pip install boto3' import os from selenium import webdriver # 'pip install selenium', 'brew install chromedriver' # Step 1: Authenticate user in your own identity system. # Step 2: Using the access keys for an IAM user in your AAWS 账户, # call "AssumeRole" to get temporary access keys for the federated user # Note: Calls to AWS STS AssumeRole must be signed using the access key ID # and secret access key of an IAM user or using existing temporary credentials. # The credentials can be in Amazon EC2 instance metadata, in environment variables, # or in a configuration file, and will be discovered automatically by the # client('sts') function. For more information, see the Python SDK docs: # http://boto3.readthedocs.io/en/latest/reference/services/sts.html # http://boto3.readthedocs.io/en/latest/reference/services/sts.html#STS.Client.assume_role if sys.version_info[0] < 3: def quote_plus_function(s): return urllib.quote_plus(s) else: def quote_plus_function(s): return urllib.parse.quote_plus(s) sts_connection = boto3.client('sts') assumed_role_object = sts_connection.assume_role( RoleArn="arn:aws:iam::account-id:role/ROLE-NAME", RoleSessionName="AssumeRoleDemoSession", ) # Step 3: Format resulting temporary credentials into JSON url_credentials = {} url_credentials['sessionId'] = assumed_role_object.get('Credentials').get('AccessKeyId') url_credentials['sessionKey'] = assumed_role_object.get('Credentials').get('SecretAccessKey') url_credentials['sessionToken'] = assumed_role_object.get('Credentials').get('SessionToken') json_string_with_temp_credentials = json.dumps(url_credentials) # Step 4. Make request to AWS federation endpoint to get sign-in token. Construct the parameter string with # the sign-in action request, a 12-hour session duration, and the JSON document with temporary credentials # as parameters. request_parameters = {} request_parameters['Action'] = 'getSigninToken' request_parameters['SessionDuration'] = '43200' request_parameters['Session'] = json_string_with_temp_credentials request_url = "https://signin.aws.amazon.com/federation" r = requests.post( request_url, data=request_parameters) # Returns a JSON document with a single element named SigninToken. signin_token = json.loads(r.text) # Step 5: Create a POST request where users can use the sign-in token to sign in to # the console. The POST request must be made within 15 minutes after the # sign-in token was issued. request_parameters = {} request_parameters['Action'] = 'login' request_parameters['Issuer']='Example.org' request_parameters['Destination'] = 'https://console.aws.amazon.com/' request_parameters['SigninToken'] =signin_token['SigninToken'] jsrequest = ''' var form = document.createElement('form'); form.method = 'POST'; form.action = '{request_url}'; request_parameters = {request_parameters} for (var param in request_parameters) {{ if (request_parameters.hasOwnProperty(param)) {{ const hiddenField = document.createElement('input'); hiddenField.type = 'hidden'; hiddenField.name = param; hiddenField.value = request_parameters[param]; form.appendChild(hiddenField); }} }} document.body.appendChild(form); form.submit(); '''.format(request_url=request_url, request_parameters=request_parameters) driver = webdriver.Chrome() driver.execute_script(jsrequest);

以下示例说明了如何使用 Java 以编程方式构造授予联合身份用户 AWS Management Console直接访问权限的 URL。下列代码段使用 AWS SDK for Java

import java.net.URLEncoder; import java.net.URL; import java.net.URLConnection; import java.io.BufferedReader; import java.io.InputStreamReader; // Available at http://www.json.org/java/index.html import org.json.JSONObject; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient; import com.amazonaws.services.securitytoken.model.Credentials; import com.amazonaws.services.securitytoken.model.GetFederationTokenRequest; import com.amazonaws.services.securitytoken.model.GetFederationTokenResult; /* Calls to AWS STS API operations must be signed using the access key ID and secret access key of an IAM user or using existing temporary credentials. The credentials should not be embedded in code. For this example, the code looks for the credentials in a standard configuration file. */ AWSCredentials credentials = new PropertiesCredentials( AwsConsoleApp.class.getResourceAsStream("AwsCredentials.properties")); AWSSecurityTokenServiceClient stsClient = new AWSSecurityTokenServiceClient(credentials); GetFederationTokenRequest getFederationTokenRequest = new GetFederationTokenRequest(); getFederationTokenRequest.setDurationSeconds(1800); getFederationTokenRequest.setName("UserName"); // A sample policy for accessing Amazon Simple Notification Service (Amazon SNS) in the console. String policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"sns:*\"," + "\"Effect\":\"Allow\",\"Resource\":\"*\"}]}"; getFederationTokenRequest.setPolicy(policy); GetFederationTokenResult federationTokenResult = stsClient.getFederationToken(getFederationTokenRequest); Credentials federatedCredentials = federationTokenResult.getCredentials(); // The issuer parameter specifies your internal sign-in // page, for example https://mysignin.internal.mycompany.com/. // The console parameter specifies the URL to the destination console of the // AWS Management Console. This example goes to Amazon SNS. // The signin parameter is the URL to send the request to. String issuerURL = "https://mysignin.internal.mycompany.com/"; String consoleURL = "https://console.aws.amazon.com/sns"; String signInURL = "https://signin.aws.amazon.com/federation"; // Create the sign-in token using temporary credentials, // including the access key ID, secret access key, and session token. String sessionJson = String.format( "{\"%1$s\":\"%2$s\",\"%3$s\":\"%4$s\",\"%5$s\":\"%6$s\"}", "sessionId", federatedCredentials.getAccessKeyId(), "sessionKey", federatedCredentials.getSecretAccessKey(), "sessionToken", federatedCredentials.getSessionToken()); // Construct the sign-in request with the request sign-in token action, a // 12-hour console session duration, and the JSON document with temporary // credentials as parameters. String getSigninTokenURL = signInURL + "?Action=getSigninToken" + "&DurationSeconds=43200" + "&SessionType=json&Session=" + URLEncoder.encode(sessionJson,"UTF-8"); URL url = new URL(getSigninTokenURL); // Send the request to the AWS federation endpoint to get the sign-in token URLConnection conn = url.openConnection (); BufferedReader bufferReader = new BufferedReader(new InputStreamReader(conn.getInputStream())); String returnContent = bufferReader.readLine(); String signinToken = new JSONObject(returnContent).getString("SigninToken"); String signinTokenParameter = "&SigninToken=" + URLEncoder.encode(signinToken,"UTF-8"); // The issuer parameter is optional, but recommended. Use it to direct users // to your sign-in page when their session expires. String issuerParameter = "&Issuer=" + URLEncoder.encode(issuerURL, "UTF-8"); // Finally, present the completed URL for the AWS console session to the user String destinationParameter = "&Destination=" + URLEncoder.encode(consoleURL,"UTF-8"); String loginURL = signInURL + "?Action=login" + signinTokenParameter + issuerParameter + destinationParameter;

以下示例说明了如何使用 Ruby 以编程方式构造授予联合身份用户 AWS Management Console直接访问权限的 URL。下列代码段使用 AWS SDK for Ruby

require 'rubygems' require 'json' require 'open-uri' require 'cgi' require 'aws-sdk' # Create a new STS instance # # Note: Calls to AWS STS API operations must be signed using an access key ID # and secret access key. The credentials can be in EC2 instance metadata # or in environment variables and will be automatically discovered by # the default credentials provider in the AWS Ruby SDK. sts = Aws::STS::Client.new() # The following call creates a temporary session that returns # temporary security credentials and a session token. # The policy grants permissions to work # in the AWS SNS console. session = sts.get_federation_token({ duration_seconds: 1800, name: "UserName", policy: "{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Allow\",\"Action\":\"sns:*\",\"Resource\":\"*\"}}", }) # The issuer value is the URL where users are directed (such as # to your internal sign-in page) when their session expires. # # The console value specifies the URL to the destination console. # This example goes to the Amazon SNS console. # # The sign-in value is the URL of the AWS STS federation endpoint. issuer_url = "https://mysignin.internal.mycompany.com/" console_url = "https://console.aws.amazon.com/sns" signin_url = "https://signin.aws.amazon.com/federation" # Create a block of JSON that contains the temporary credentials # (including the access key ID, secret access key, and session token). session_json = { :sessionId => session.credentials[:access_key_id], :sessionKey => session.credentials[:secret_access_key], :sessionToken => session.credentials[:session_token] }.to_json # Call the federation endpoint, passing the parameters # created earlier and the session information as a JSON block. # The request returns a sign-in token that's valid for 15 minutes. # Signing in to the console with the token creates a session # that is valid for 12 hours. get_signin_token_url = signin_url + "?Action=getSigninToken" + "&SessionType=json&Session=" + CGI.escape(session_json) returned_content = URI.parse(get_signin_token_url).read # Extract the sign-in token from the information returned # by the federation endpoint. signin_token = JSON.parse(returned_content)['SigninToken'] signin_token_param = "&SigninToken=" + CGI.escape(signin_token) # Create the URL to give to the user, which includes the # sign-in token and the URL of the console to open. # The "issuer" parameter is optional but recommended. issuer_param = "&Issuer=" + CGI.escape(issuer_url) destination_param = "&Destination=" + CGI.escape(console_url) login_url = signin_url + "?Action=login" + signin_token_param + issuer_param + destination_param