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

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

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

若要熟悉 SAML 聯合及其功能,您將使用 AWS 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 和角色 AWS CloudFormation

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

建立範本

首先,建立 CloudFormation 範本。

  1. 範本區段中,按一下 JSONYAML 標籤上的複製圖示,以複製範本內容。

  2. 將範本內容貼到新檔案中。

  3. 在本機儲存檔案。

建立 堆疊。

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

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

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

  3. 指定範本:

    1. 先決條件下,選擇選擇現有範本

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

    3. 選擇選擇檔案,導覽至範本檔案,然後選擇它。

    4. 選擇下一步

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

    1. 輸入堆疊名稱。

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

      範例: CompanyIdPEnterpriseSSO

    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-AccessSAML-ReadOnly-Role

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

      • IdentityProviderAddPrivateKey - 用於解密 SAML 宣告的選用私有金鑰

      • IdentityProviderAssertionEncryptionMode - SAML 聲明的加密模式

        範例值:AllowedRequired或 為無加密保留空白

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

        範例:14400(4 小時)

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

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

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

        範例:/saml-roles/

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

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

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

    6. 選擇下一步

  5. 設定堆疊選項:

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

      注意

      選擇此選項可避免針對刪除政策指定的資源向您收費,即使堆疊建立失敗也一樣。

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

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

    4. 選擇下一步

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

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

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

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

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

設定 IdP 傳送適當的 SAML 屬性以擔任角色時,您將需要這兩個 ARNs。

測試 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. 開啟 AWS CloudFormation 主控台。

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

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

CloudFormation 範本詳細資訊

資源

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

組態

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

  • IdentityProviderName - SAML IdP 的名稱 (為自動產生的名稱保留空白)

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

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

  • IdentityProviderAssertionEncryptionMode - SAML 聲明的加密模式

  • RoleName - IAM 角色的名稱 (為自動產生的名稱保留空白)

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

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

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

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

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'