IAM 教程:使用 AWS CloudFormation 模板创建 SAML 身份提供者 (IdP) - AWS Identity and Access Management

IAM 教程:使用 AWS CloudFormation 模板创建 SAML 身份提供者 (IdP)

要为您的 AWS 账户设置 SAML 联合身份验证,需要创建 SAML 身份提供者 (IdP)。本教程展示如何使用 AWS CloudFormation 模板创建 SAML IdP,以便在 AWS 和外部 IdP 之间建立信任。

该模板会创建一个使用 IdP 元数据文档进行配置的 SAML IdP。然后,联合 IAM 角色可引用此 IdP,以允许来自外部 IdP 的经过身份验证的用户访问 AWS 资源。

所部署的资源中含有一个配置了 IdP 元数据文档和可选加密设置的 SAML IdP。

先决条件

本教程假定您已准备好以下各项:

  • 本地计算机上安装了 Python 3.6 或更高版本,可运行本教程中用于对 IdP 的 SAML 元数据 XML 文件进行格式化的 Python 命令。

  • 来自外部 IdP 的 SAML 元数据文档,另存为 XML 文件。

使用 AWS CloudFormation 创建 SAML IdP

要创建 SAML IdP,您需要创建 CloudFormation 模板,并使用此模板创建包含 IdP 资源的堆栈。

创建 模板

首先,创建 CloudFormation 模板。

  1. 模板 部分中,单击 JSONYAML 选项卡上的复制图标,以复制模板内容。

  2. 将模板内容粘贴到新文件中。

  3. 将该文件保存在本地。

创建堆栈

接下来,使用已保存的模板来预置 CloudFormation 堆栈。

  1. 通过以下网址打开 AWS CloudFormation 控制台:https://console.aws.amazon.com/cloudformation

  2. 堆栈页面,从创建堆栈菜单中选择(采用新资源(标准))

  3. 指定模板:

    1. 先决条件下,选择选择现有模板

    2. 指定模板下,选择上传模板文件

    3. 选择选择文件,导航到模板文件并将其选中。

    4. 选择下一步

  4. 指定以下堆栈详细信息:

    1. 输入堆栈名称。

    2. 对于 IdentityProviderName,可将其留空以根据堆栈名称自动生成名称,也可以为 SAML IdP 输入自定义名称。自定义名称只能包含字母数字字符、句点、下划线和连字符。

    3. 对于 IdentityProvidersamlMetadataDocument,在将 SAML 元数据 XML 文件粘贴到此字段之前,需要将其格式化为单行。这是必要的,因为 CloudFormation 控制台要求 XML 内容在通过控制台参数传递时需格式化为单行。

      使用以下 Python 命令重新格式化 XML 文件:

      python3 -c "import sys, re; content=open(sys.argv[1]).read(); print(re.sub(r'>\s+<', '><', content.replace('\n', '').replace('\r', '').strip()))" saml-metadata.xml
      注意

      IdP 的 SAML 元数据文档必须格式化为单行才能输入控制台参数。Python 命令删除了换行符和多余空格以创建所需的格式,同时保留所有原始内容和结构。

      复制 Python 命令的输出并将其粘贴到 IdentityProviderSAMLMetadataDocument 字段中。

      格式化的 SAML 元数据文档示例(缩减版):

      <?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://portal.sso.example.com/saml/assertion/CompanyIdP"><md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIDXTCCAkWgAwIBAgIJAJC1HiIAZAiIMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV...</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://portal.sso.example.com/saml/logout/CompanyIdP"/><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://portal.sso.example.com/saml/assertion/CompanyIdP"/></md:IDPSSODescriptor></md:EntityDescriptor>
    4. 对于其他参数,请接受默认值或根据需要输入自己的值:

      • IdentityProviderAddPrivateKey - 解密 SAML 断言的可选私钥

      • IdentityProviderAssertionEncryptionMode - 可选项,可设置 SAML 断言加密模式(“允许”、“必需”或空)

    5. 选择下一步

  5. 配置堆栈选项:

    1. 堆栈故障选项下,选择删除所有新创建的资源

      注意

      如果选择此选项,即使堆栈创建失败,您可能也不会因为删除策略规定保留资源而向资源付费。

    2. 接受其他所有默认值。

    3. 功能下勾选复选框,确认 CloudFormation 可能在您的账户中创建 IAM 资源。

    4. 选择下一步

  6. 查看堆栈详细信息并选择提交

AWS CloudFormation 将创建堆栈。一旦堆栈创建完成之后,堆栈资源就即可投入使用。可使用堆栈详细信息页面上的资源选项卡来查看账户中预置的资源。

堆栈将输出以下值,可参见输出选项卡:

  • ProviderARN:已创建的 SAML IdP 的 ARN(例如,arn:aws:iam::123456789012:saml-provider/CompanyIdP)。在创建信任此提供商的角色时需要此 ARN。

  • ProviderName:已创建的 SAML IdP 的名称(例如 CompanyIdP,如果指定自定义名称;或者 my-saml-stack-saml-provider,如果使用默认命名)。

这些输出还会被导出,以便由其他 AWS CloudFormation 堆栈使用 Fn::ImportValue 函数进行导入。

验证 SAML IdP

一旦创建 SAML IdP 后,即可验证其配置并记下其 ARN 以供联合角色使用。

  1. 通过 https://console.aws.amazon.com/iam/ 打开 IAM 控制台。

  2. 在导航窗格中,选择 Identity providers(身份提供程序)。

    您应该能在列表中看到新创建的 SAML IdP。

  3. 选择 IdP 名称以查看其详细信息。

    在 IdP 详细信息页面上,可以看到 SAML 元数据文档和其他配置详细信息。

  4. 记下详细信息页面上显示的提供者 ARN

    在创建信任此 IdP 的联合 IAM 角色时需要此 ARN。

  5. 查看元数据文档,确保其与您从外部 IdP 提供的文档相符。

您的 SAML IdP 现已准备好供联合 IAM 角色使用。您可以创建信任此 IdP 的角色,以允许来自外部 IdP 的经过身份验证的用户代入这些角色并访问 AWS 资源。

清理:删除资源

最后一步,您将删除该堆栈及其包含的资源。

  1. 打开 AWS CloudFormation 控制台。

  2. 堆栈页面上,选择根据该模板创建的堆栈,选择删除,然后确认删除

    CloudFormation 启动删除堆栈及其包含的所有资源。

CloudFormation 模板详细信息

资源

本教程的 AWS CloudFormation 模板将在您的账户中创建以下资源:

AWS::IAM::SAMLProvider:一个在 AWS 和外部 IdP 之间建立信任的 SAML IdP。

配置

模板包含如下可配置参数:

  • IdentityProviderName - SAML IdP 的名称(自动生成的名字请留空)

    示例:CompanyIdPEnterpriseSSO

  • IdentityProviderSAMLMetadataDocument - 来自外部 IdP 的 SAML 元数据文档(格式化为单行)

  • IdentityProviderAddPrivateKey - 解密 SAML 断言的可选私钥

  • IdentityProviderAssertionEncryptionMode - 可选项,可设置 SAML 断言加密模式

CloudFormation 模板

将以下 JSON 或 YAML 代码另存为单独文件,以用作本教程的 CloudFormation 模板。

JSON
{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "[AWSDocs] IAM: tutorial_saml-idp", "Parameters": { "IdentityProviderName": { "Type": "String", "Description": "Name of the SAML Identity Provider (leave empty for auto-generated name like '{StackName}-{UniqueId}')", "Default": "", "AllowedPattern": "^$|^[a-zA-Z0-9._-]+$", "ConstraintDescription": "Must be empty or contain only alphanumeric characters, periods, underscores, and hyphens" }, "IdentityProviderSAMLMetadataDocument": { "Type": "String", "Description": "SAML metadata document from identity provider" }, "IdentityProviderAddPrivateKey": { "Type": "String", "Description": "Optional private key for decrypting SAML assertions. The private key must be a .pem file that uses AES-GCM or AES-CBC encryption algorithm to decrypt SAML assertions.", "Default": "" }, "IdentityProviderAssertionEncryptionMode": { "Type": "String", "Description": "Optional, sets encryption mode for SAML assertions", "Default": "", "AllowedValues": ["", "Allowed", "Required"] } }, "Conditions": { "HasPrivateKey": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderAddPrivateKey"}, ""]}]}, "HasEncryptionMode": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderAssertionEncryptionMode"}, ""]}]}, "HasCustomName": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderName"}, ""]}]} }, "Resources": { "SAMLProvider": { "Type": "AWS::IAM::SAMLProvider", "Properties": { "Name": {"Fn::If": ["HasCustomName", {"Ref": "IdentityProviderName"}, {"Ref": "AWS::NoValue"}]}, "SamlMetadataDocument": {"Ref": "IdentityProviderSAMLMetadataDocument"}, "Tags": [ { "Key": "Name", "Value": {"Fn::If": ["HasCustomName", {"Ref": "IdentityProviderName"}, {"Fn::Sub": "${AWS::StackName}-saml-provider"}]} } ], "AddPrivateKey": {"Fn::If": ["HasPrivateKey", {"Ref": "IdentityProviderAddPrivateKey"}, {"Ref": "AWS::NoValue"}]}, "AssertionEncryptionMode": {"Fn::If": ["HasEncryptionMode", {"Ref": "IdentityProviderAssertionEncryptionMode"}, {"Ref": "AWS::NoValue"}]} } } }, "Outputs": { "ProviderARN": { "Description": "ARN of the created SAML Identity Provider", "Value": {"Ref": "SAMLProvider"}, "Export": { "Name": {"Fn::Sub": "${AWS::StackName}-ProviderARN"} } }, "ProviderName": { "Description": "Name of the SAML Identity Provider", "Value": {"Fn::If": ["HasCustomName", {"Ref": "IdentityProviderName"}, {"Fn::Sub": "${AWS::StackName}-saml-provider"}]}, "Export": { "Name": {"Fn::Sub": "${AWS::StackName}-ProviderName"} } } } }
YAML
AWSTemplateFormatVersion: '2010-09-09' Description: '[AWSDocs] IAM: tutorial_saml-idp' Parameters: IdentityProviderName: Type: String Description: Name of the SAML Identity Provider (leave empty for auto-generated name like '{StackName}-{UniqueId}') Default: "" AllowedPattern: '^$|^[a-zA-Z0-9._-]+$' ConstraintDescription: 'Must be empty or contain only alphanumeric characters, periods, underscores, and hyphens' IdentityProviderSAMLMetadataDocument: Type: String Description: SAML metadata document from identity provider IdentityProviderAddPrivateKey: Type: String Description: Optional private key for decrypting SAML assertions. The private key must be a .pem file that uses AES-GCM or AES-CBC encryption algorithm to decrypt SAML assertions. Default: "" IdentityProviderAssertionEncryptionMode: Type: String Description: Optional, sets encryption mode for SAML assertions Default: "" AllowedValues: - "" - "Allowed" - "Required" Conditions: HasPrivateKey: !Not [!Equals [!Ref IdentityProviderAddPrivateKey, ""]] HasEncryptionMode: !Not [!Equals [!Ref IdentityProviderAssertionEncryptionMode, ""]] HasCustomName: !Not [!Equals [!Ref IdentityProviderName, ""]] Resources: SAMLProvider: Type: 'AWS::IAM::SAMLProvider' Properties: Name: !If - HasCustomName - !Ref IdentityProviderName - !Ref AWS::NoValue SamlMetadataDocument: !Ref IdentityProviderSAMLMetadataDocument Tags: - Key: Name Value: !If - HasCustomName - !Ref IdentityProviderName - !Sub '${AWS::StackName}-saml-provider' AddPrivateKey: !If - HasPrivateKey - !Ref IdentityProviderAddPrivateKey - !Ref AWS::NoValue AssertionEncryptionMode: !If - HasEncryptionMode - !Ref IdentityProviderAssertionEncryptionMode - !Ref AWS::NoValue Outputs: ProviderARN: Description: 'ARN of the created SAML Identity Provider' Value: !Ref SAMLProvider Export: Name: !Sub '${AWS::StackName}-ProviderARN' ProviderName: Description: 'Name of the SAML Identity Provider' Value: !If - HasCustomName - !Ref IdentityProviderName - !Sub '${AWS::StackName}-saml-provider' Export: Name: !Sub '${AWS::StackName}-ProviderName'