View a markdown version of this page

IAM 教學課程:使用 CloudFormation 範本建立 SAML 身分提供者 (IdP) 和 SAML 聯合 IAM 角色 - AWS Identity and Access Management

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

IAM 教學課程:使用 CloudFormation 範本建立 SAML 身分提供者 (IdP) 和 SAML 聯合 IAM 角色

若要熟悉 SAML 聯合及其功能,您將使用 CloudFormation 範本來設定 SAML 身分提供者 (IdP) 和相關聯的聯合 IAM 角色。本教學課程說明如何在單一堆疊中同時建立這兩個資源。

範本會建立 SAML IdP,可用於聯合存取 AWS 資源,以及信任 SAML 供應商的 IAM 角色。外部 IdP 驗證的使用者可以擔任此角色來存取 AWS 資源。

部署的資源包含下列項目:

  • 使用 IdP 中繼資料文件設定的 SAML IdP。

  • 信任 SAML IdP 且可由經過身分驗證之使用者擔任的聯合身分 IAM 角色。

  • 可連接至角色以授予特定許可的可設定受管政策。

先決條件

此教學課程假設您已備妥下列項目:

  • 在本機電腦上安裝的 Python 3.6 或更新版本,以便執行本教學課程中用於格式化 IdP SAML 中繼資料 XML 檔案的 Python 命令。

  • 外部 IdP 中儲存為 XML 檔案的 SAML 中繼資料文件。

使用 建立 SAML IdP 和角色 CloudFormation

若要建立 SAML IdP 和聯合角色,您將建立 CloudFormation 範本,並使用它來建立包含這兩個資源的堆疊。

建立範本

首先,建立 CloudFormation 範本。

  1. 在 範本 區段中,按一下 JSON 或 YAML 索引標籤上的複製圖示,以複製範本內容。

  2. 在新檔案中貼上範本內容。

  3. 在本機儲存檔案。

建立 堆疊。

接下來,使用剛儲存的範本來佈建 CloudFormation 堆疊。

  1. 在 https://https://console.aws.amazon.com/cloudformation 開啟 CloudFormation 主控台。

  2. 在堆疊頁面上,從建立堆疊功能表中選擇使用新資源 (標準)。

  3. 指定範本:

    1. 在必要條件下,選擇選擇現有範本。

    2. 在指定範本下,選擇上傳範本檔案。

    3. 選擇選擇檔案,導覽至範本檔案並選取它。

    4. 選擇下一步。

  4. 指定下列堆疊詳細資訊:

    1. 輸入堆疊名稱。

    2. 對於 IdentityProviderName,您可以將其留空,以根據堆疊名稱自動產生名稱,或輸入 SAML IdP 的自訂名稱。

      範例:CompanyIdP 或 EnterpriseSSO

    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. 對於 RoleName,可以將其留空,以根據堆疊名稱自動產生名稱,或輸入聯合身分 IAM 角色的自訂名稱。

      範例:SAML-Developer-Access 或 SAML-ReadOnly-Role

    5. 對於其他參數,請接受預設值或根據需求輸入自己的值:

      • IdentityProviderAddPrivateKey:用於解密 SAML 聲明的選用私有金鑰

      • IdentityProviderAssertionEncryptionMode – SAML 聲明的加密模式

        範例值:Allowed、Required 或留空表示不加密

      • RoleSessionDuration – 工作階段持續時間上限 (以秒為單位,3600-43200,預設值 7200)

        範例:14400 (4 小時)

      • RolePermissionsBoundary – 許可界限政策的選用 ARN

        範例:arn:aws:iam::123456789012:policy/DeveloperBoundary

      • RolePath – IAM 角色的路徑 (預設為 /)

        範例:/saml-roles/

      • RoleManagedPolicy1-5 – 最多可連接 5 個受管政策的選用 ARN

        RoleManagedPolicy1 的範例:arn:aws:iam::aws:policy/ReadOnlyAccess

        RoleManagedPolicy2 的範例:arn:aws:iam::123456789012:policy/CustomPolicy

    6. 選擇下一步。

  5. 設定堆疊選項:

    1. 在堆疊失敗選項下,選擇刪除所有新建立的資源。

      注意

      選擇此選項可避免堆疊建立失敗時,因資源刪除政策指定為保留而可能產生的資源費用。

    2. 接受所有其他預設值。

    3. 在功能下,勾選方塊以確認 CloudFormation 可能會在帳戶中建立 IAM 資源。

    4. 選擇下一步。

  6. 檢閱堆疊詳細資訊,然後選擇提交。

CloudFormation 會建立堆疊。堆疊建立完成後,堆疊資源即可使用。您可以使用堆疊詳細資訊頁面上的資源索引標籤,來檢視帳戶中佈建的資源。

堆疊將輸出下列值,您可以在輸出索引標籤上檢視:

  • RoleARN:已建立 IAM 角色的 ARN (例如 arn:aws:iam::123456789012:role/SAML-Developer-Access,或者如果使用自動產生的名稱,則為 arn:aws:iam::123456789012:role/stack-name-a1b2c3d4)。

  • IdentityProviderARN:已建立 SAML IdP 的 ARN (例如 arn:aws:iam::123456789012:saml-provider/CompanyIdP)。

在設定 IdP 以傳送用於擔任角色的相應 SAML 屬性時,您將需要這兩個 ARN。

測試 SAML 聯合身分

SAML IdP 和聯合身分角色建立後,您可以測試聯合身分設定。

  1. 在以下網址開啟 IAM 主控台:https://console.aws.amazon.com/iam/。

  2. 在導覽窗格中,請選擇 Identity providers (身分提供者)。

    您應該會在清單中看到新建立的 SAML IdP。

  3. 選擇 IdP 名稱以檢視其詳細資訊。

    在 IdP 詳細資訊頁面上,可以查看 SAML 中繼資料文件及其他組態詳細資訊。

  4. 在導覽窗格中,選擇角色。

  5. 找到並選擇新建立的聯合身分角色。

    在角色詳細資訊頁面上,可以查看允許 SAML IdP 擔任此角色的信任政策。

  6. 選擇信任關係索引標籤以檢閱信任政策。

    信任政策應該會顯示 SAML IdP 受信任可擔任此角色,條件是 SAML 對象 (SAML:aud) 與 https://signin.aws.amazon.com/saml 相符。

清理:刪除資源

最後一個步驟是,刪除堆疊及其包含的資源。

  1. 開啟 CloudFormation 主控台。

  2. 在堆疊頁面上,選擇從範本建立的堆疊,然後選擇刪除,接著確認刪除。

    CloudFormation 會啟動刪除堆疊及其包含的所有資源。

CloudFormation 範本詳細資訊

Resources

本教學課程的 CloudFormation 範本會在您的帳戶中建立下列資源:

  • AWS::IAM::SAMLProvider:在 AWS 和外部 IdP 之間建立信任的 SAML IdP。

  • AWS::IAM::Role:可由透過 SAML IdP 進行身分驗證之使用者擔任的聯合身分 IAM 角色。

組態

範本包含下列可設定的參數:

  • IdentityProviderName – SAML IdP 的名稱 (留空以自動產生名稱)

  • IdentityProviderSAMLMetadataDocument – 來自 IdP 的 SAML 中繼資料文件 (必要)

  • IdentityProviderAddPrivateKey:用於解密 SAML 聲明的選用私有金鑰

  • IdentityProviderAssertionEncryptionMode – SAML 聲明的加密模式

  • RoleName – IAM 角色的名稱 (留空以自動產生名稱)

  • RolePath – IAM 角色的路徑 (預設值 /)

  • RolePermissionsBoundary – 許可界限政策的選用 ARN

  • RoleSessionDuration – 工作階段持續時間上限 (以秒為單位,3600-43200,預設值 7200)

  • RoleManagedPolicy1-5 – 最多可連接 5 個受管政策的選用 ARN

CloudFormation 範本

將下列 JSON 或 YAML 程式碼儲存為個別檔案,以用作本教學課程的 CloudFormation 範本。

JSON
{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "[AWSDocs] IAM: tutorial_saml-idp-and-federated-role", "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"] }, "RoleName": { "Type": "String", "Description": "Name of the IAM Role (leave empty for auto-generated name like '{StackName}-{UniqueId}')", "Default": "", "AllowedPattern": "^$|^[\\w+=,.@-]{1,64}$", "ConstraintDescription": "Must be empty or 1-64 characters and can contain alphanumeric characters and +=,.@-" }, "RolePath": { "Type": "String", "Description": "Path for the IAM Role", "AllowedPattern": "(^\\/$)|(^\\/.*\\/$)", "Default": "/" }, "RolePermissionsBoundary": { "Type": "String", "Description": "Optional ARN of the permissions boundary policy (leave empty for none)", "Default": "" }, "RoleSessionDuration": { "Description": "The maximum session duration (in seconds) that you want to set for the specified role (3600-43200)", "Type": "Number", "MinValue": 3600, "MaxValue": 43200, "Default": 7200 }, "RoleManagedPolicy1": { "Type": "String", "Description": "Optional managed policy ARN 1", "Default": "" }, "RoleManagedPolicy2": { "Type": "String", "Description": "Optional managed policy ARN 2", "Default": "" }, "RoleManagedPolicy3": { "Type": "String", "Description": "Optional managed policy ARN 3", "Default": "" }, "RoleManagedPolicy4": { "Type": "String", "Description": "Optional managed policy ARN 4", "Default": "" }, "RoleManagedPolicy5": { "Type": "String", "Description": "Optional managed policy ARN 5", "Default": "" } }, "Conditions": { "HasCustomProviderName": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderName"}, ""]}]}, "HasCustomRoleName": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleName"}, ""]}]}, "HasPermissionsBoundary": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RolePermissionsBoundary"}, ""]}]}, "HasPolicy1": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy1"}, ""]}]}, "HasPolicy2": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy2"}, ""]}]}, "HasPolicy3": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy3"}, ""]}]}, "HasPolicy4": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy4"}, ""]}]}, "HasPolicy5": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy5"}, ""]}]}, "HasPrivateKey": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderAddPrivateKey"}, ""]}]}, "HasAssertionEncryptionMode": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderAssertionEncryptionMode"}, ""]}]} }, "Resources": { "SAMLProvider": { "Type": "AWS::IAM::SAMLProvider", "Properties": { "Name": {"Fn::If": ["HasCustomProviderName", {"Ref": "IdentityProviderName"}, {"Ref": "AWS::NoValue"}]}, "SamlMetadataDocument": {"Ref": "IdentityProviderSAMLMetadataDocument"}, "AddPrivateKey": {"Fn::If": ["HasPrivateKey", {"Ref": "IdentityProviderAddPrivateKey"}, {"Ref": "AWS::NoValue"}]}, "AssertionEncryptionMode": {"Fn::If": ["HasAssertionEncryptionMode", {"Ref": "IdentityProviderAssertionEncryptionMode"}, {"Ref": "AWS::NoValue"}]} } }, "SAMLFederatedRole": { "Type": "AWS::IAM::Role", "Properties": { "RoleName": {"Fn::If": ["HasCustomRoleName", {"Ref": "RoleName"}, {"Ref": "AWS::NoValue"}]}, "Path": {"Ref": "RolePath"}, "Description": "SAML federated IAM role for SSO access with specified permissions", "MaxSessionDuration": {"Ref": "RoleSessionDuration"}, "PermissionsBoundary": {"Fn::If": ["HasPermissionsBoundary", {"Ref": "RolePermissionsBoundary"}, {"Ref": "AWS::NoValue"}]}, "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": {"Ref": "SAMLProvider"} }, "Action": [ "sts:AssumeRole", "sts:SetSourceIdentity", "sts:TagSession" ], "Condition": { "StringEquals": { "SAML:aud": "https://signin.aws.amazon.com/saml" } } } ] }, "ManagedPolicyArns": { "Fn::Split": [ ",", { "Fn::Join": [ ",", [ {"Fn::If": ["HasPolicy1", {"Ref": "RoleManagedPolicy1"}, {"Ref": "AWS::NoValue"}]}, {"Fn::If": ["HasPolicy2", {"Ref": "RoleManagedPolicy2"}, {"Ref": "AWS::NoValue"}]}, {"Fn::If": ["HasPolicy3", {"Ref": "RoleManagedPolicy3"}, {"Ref": "AWS::NoValue"}]}, {"Fn::If": ["HasPolicy4", {"Ref": "RoleManagedPolicy4"}, {"Ref": "AWS::NoValue"}]}, {"Fn::If": ["HasPolicy5", {"Ref": "RoleManagedPolicy5"}, {"Ref": "AWS::NoValue"}]} ] ] } ] } } } }, "Outputs": { "RoleARN": { "Description": "ARN of the created IAM Role", "Value": {"Fn::GetAtt": ["SAMLFederatedRole", "Arn"]}, "Export": { "Name": {"Fn::Sub": "${AWS::StackName}-RoleARN"} } }, "IdentityProviderARN": { "Description": "ARN of the created SAML Identity Provider", "Value": {"Ref": "SAMLProvider"}, "Export": { "Name": {"Fn::Sub": "${AWS::StackName}-IdentityProviderARN"} } } } }
YAML
AWSTemplateFormatVersion: '2010-09-09' Description: '[AWSDocs] IAM: tutorial_saml-idp-and-federated-role' 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" RoleName: Type: String Description: Name of the IAM Role (leave empty for auto-generated name like '{StackName}-{UniqueId}') Default: "" AllowedPattern: '^$|^[\w+=,.@-]{1,64}$' ConstraintDescription: "Must be empty or 1-64 characters and can contain alphanumeric characters and +=,.@-" RolePath: Type: String Description: Path for the IAM Role AllowedPattern: (^\/$)|(^\/.*\/$) Default: "/" RolePermissionsBoundary: Type: String Description: Optional ARN of the permissions boundary policy (leave empty for none) Default: "" RoleSessionDuration: Description: The maximum session duration (in seconds) that you want to set for the specified role (3600-43200) Type: Number MinValue: 3600 MaxValue: 43200 Default: 7200 RoleManagedPolicy1: Type: String Description: Optional managed policy ARN 1 Default: "" RoleManagedPolicy2: Type: String Description: Optional managed policy ARN 2 Default: "" RoleManagedPolicy3: Type: String Description: Optional managed policy ARN 3 Default: "" RoleManagedPolicy4: Type: String Description: Optional managed policy ARN 4 Default: "" RoleManagedPolicy5: Type: String Description: Optional managed policy ARN 5 Default: "" Conditions: HasCustomProviderName: !Not [!Equals [!Ref IdentityProviderName, ""]] HasCustomRoleName: !Not [!Equals [!Ref RoleName, ""]] HasPermissionsBoundary: !Not [!Equals [!Ref RolePermissionsBoundary, ""]] HasPolicy1: !Not [!Equals [!Ref RoleManagedPolicy1, ""]] HasPolicy2: !Not [!Equals [!Ref RoleManagedPolicy2, ""]] HasPolicy3: !Not [!Equals [!Ref RoleManagedPolicy3, ""]] HasPolicy4: !Not [!Equals [!Ref RoleManagedPolicy4, ""]] HasPolicy5: !Not [!Equals [!Ref RoleManagedPolicy5, ""]] HasPrivateKey: !Not [!Equals [!Ref IdentityProviderAddPrivateKey, ""]] HasAssertionEncryptionMode: !Not [!Equals [!Ref IdentityProviderAssertionEncryptionMode, ""]] Resources: SAMLProvider: Type: AWS::IAM::SAMLProvider Properties: Name: !If - HasCustomProviderName - !Ref IdentityProviderName - !Ref AWS::NoValue SamlMetadataDocument: !Ref IdentityProviderSAMLMetadataDocument AddPrivateKey: !If - HasPrivateKey - !Ref IdentityProviderAddPrivateKey - !Ref AWS::NoValue AssertionEncryptionMode: !If - HasAssertionEncryptionMode - !Ref IdentityProviderAssertionEncryptionMode - !Ref AWS::NoValue SAMLFederatedRole: Type: AWS::IAM::Role Properties: RoleName: !If - HasCustomRoleName - !Ref RoleName - !Ref AWS::NoValue Path: !Ref RolePath Description: "SAML federated IAM role for SSO access with specified permissions" MaxSessionDuration: !Ref RoleSessionDuration PermissionsBoundary: !If - HasPermissionsBoundary - !Ref RolePermissionsBoundary - !Ref AWS::NoValue AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Federated: !Ref SAMLProvider Action: - 'sts:AssumeRole' - 'sts:SetSourceIdentity' - 'sts:TagSession' Condition: StringEquals: 'SAML:aud': 'https://signin.aws.amazon.com/saml' ManagedPolicyArns: !Split - ',' - !Join - ',' - - !If [HasPolicy1, !Ref RoleManagedPolicy1, !Ref "AWS::NoValue"] - !If [HasPolicy2, !Ref RoleManagedPolicy2, !Ref "AWS::NoValue"] - !If [HasPolicy3, !Ref RoleManagedPolicy3, !Ref "AWS::NoValue"] - !If [HasPolicy4, !Ref RoleManagedPolicy4, !Ref "AWS::NoValue"] - !If [HasPolicy5, !Ref RoleManagedPolicy5, !Ref "AWS::NoValue"] Outputs: RoleARN: Description: ARN of the created IAM Role Value: !GetAtt SAMLFederatedRole.Arn Export: Name: !Sub '${AWS::StackName}-RoleARN' IdentityProviderARN: Description: ARN of the created SAML Identity Provider Value: !Ref SAMLProvider Export: Name: !Sub '${AWS::StackName}-IdentityProviderARN'