IAM チュートリアル: AWS CloudFormation テンプレートを使用して SAML ID プロバイダー (IdP) と SAML フェデレーション IAM ロールを作成する - AWS Identity and Access Management

IAM チュートリアル: AWS CloudFormation テンプレートを使用して SAML ID プロバイダー (IdP) と SAML フェデレーション IAM ロールを作成する

SAML フェデレーションとその機能を理解するために、AWS CloudFormation テンプレートを使用して SAML ID プロバイダー (IdP) と関連するフェデレーション IAM ロールを設定します。このチュートリアルでは、両方のリソースを 1 つのスタックにまとめて作成する方法を説明します。

テンプレートは、AWS リソースへのフェデレーションアクセスに使用できる SAML IdP と、SAML プロバイダーを信頼する IAM ロールを作成します。外部 IdP によって認証されたユーザーは、このロールを引き受けて AWS リソースにアクセスできます。

デプロイされたリソースは、以下で構成されます。

  • IdP のメタデータドキュメントで設定された SAML IdP。

  • SAML IdP を信頼し、認証されたユーザーが引き受けることができるフェデレーション IAM ロール。

  • 特定のアクセス許可を付与するためにロールにアタッチできる設定可能なマネージドポリシー。

前提条件

このチュートリアルでは、以下を実行済みであることを前提としています。

  • このチュートリアルで IdP の SAML メタデータ XML ファイルをフォーマットするために使用する Python コマンドを実行するには、ローカル マシンに Python 3.6 以降がインストールされている必要があります。

  • 外部 IdP からの SAML メタデータドキュメントを XML ファイルとして保存していること。

AWS CloudFormation を使用して SAML IdP とロールを作成する

SAML IdP とフェデレーションロールを作成するために、CloudFormation テンプレートを作成し、それを使用して両方のリソースが含まれるスタックを作成します。

テンプレートを作成する

まず、CloudFormation テンプレートを作成します。

  1. テンプレート セクションで、[JSON] または [YAML] タブのコピーアイコンをクリックして、テンプレートの内容をコピーします。

  2. テンプレートの内容を新しいファイルに貼り付けます。

  3. ファイルをローカルに保存します。

スタックを作成します。

次に、保存したテンプレートを使用して CloudFormation スタックをプロビジョニングします。

  1. https://console.aws.amazon.com/cloudformation で AWS CloudFormation コンソール を開きます。

  2. [スタック] ページでは、[スタックの作成] メニューで [新しいリソースを使用 (標準)] を選択します。

  3. テンプレートを指定します。

    1. [前提条件] で、[既存のテンプレートを選択] を選択します。

    2. [テンプレートの指定] で、[テンプレートファイルのアップロード] を選択します。

    3. [ファイルを選択] を選択し、テンプレートファイルに移動して選択します。

    4. [次へ] を選択します。

  4. 次のスタックの詳細を指定します。

    1. スタック名を入力します。

    2. [IdentityProviderName] は、空のままにするとスタック名に基づいて名前を自動生成できます。または、SAML IdP のカスタム名を入力することもできます。

      例: CompanyIdP または EnterpriseSSO

    3. [IdentityProviderSAMLMetadataDocument] では、このフィールドに貼り付ける前に、SAML メタデータ XML ファイルを 1 行にフォーマットする必要があります。CloudFormation コンソールでコンソールパラメータを渡すときに XML コンテンツを 1 行にフォーマットする必要があるため、この処理が必要です。

      次の 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 メタデータドキュメントは、コンソールパラメータ入力用に 1 行にフォーマットする必要があります。この 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 アサーションの暗号化モード

        値の例: AllowedRequired、または暗号化なしの場合は空のままにする

      • 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. スタックの詳細を確認して、[送信] を選択します。

AWS 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 など)。

ロールの引き受けのために適切な SAML 属性を送信するように IdP を設定する場合は、これら両方の ARN が必要です。

SAML フェデレーションをテストする

SAML IdP とフェデレーションロールが作成されたら、フェデレーション設定をテストできます。

  1. IAM コンソール (https://console.aws.amazon.com/iam/) を開きます。

  2. ナビゲーションペインで、[ID プロバイダー] を選択します。

    新しく作成された SAML IdP がリストに表示されるはずです。

  3. IdP 名を選択すると、その詳細が表示されます。

    IdP の詳細ページで、SAML メタデータドキュメントやその他の設定の詳細を確認できます。

  4. ナビゲーションペインで Roles (ロール) を選択してください。

  5. 新しく作成されたフェデレーションロールを見つけて選択します。

    ロールの詳細ページで、SAML IdP がこのロールを引き受けることを許可する信頼ポリシーを確認できます。

  6. [信頼関係] タブを選択して、信頼ポリシーを確認します。

    信頼ポリシーには、SAML オーディエンス (SAML:aud) が https://signin.aws.amazon.com/saml と一致することを条件として、SAML IdP がこのロールを引き受けるように信頼されていることが示されているはずです。

クリーンアップ: リソースを削除する

最後のステップとして、スタックとそれに含まれるリソースを削除します。

  1. AWS CloudFormation コンソールを開きます。

  2. [スタック] ページで、テンプレートから作成されたスタックを選択し、[削除] を選択してから、[削除] で確定します。

    CloudFormation は、スタックとそれに含まれるすべてのリソースの削除を開始します。

CloudFormation テンプレートファイルの詳細

リソース

このチュートリアルで使用する AWS 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'