KeycloakとAWSのSAML SSO環境構築 ── IdPの設定からSSOログイン確認まで

目次

概要

シングルサインオン(SSO)は、1つのIDとパスワードで複数のサービスにログインできる仕組みです。IdP(アイデンティティプロバイダー)にユーザー情報を集約し、各サービスはIdPが発行する認証情報を信頼してアクセスを許可します。これにより、ユーザーはサービスごとにパスワードを管理する必要がなくなり、管理者はIdP上でユーザーを無効化するだけで全サービスへのアクセスを一括で停止できます。

この記事では、オープンソースのIdPであるKeycloakをDockerでローカルに起動し、AWSマネジメントコンソールへのSAML SSOを構築します。今回はAWSとの連携のみを行いますが、同じ要領でKeycloakにSAMLクライアントを追加すれば、他のサービスにも同じIDでログインできるようになります。

複数のAWSアカウントへのSSOを一元管理する場合は、AWS IAM Identity Center(旧AWS SSO)の利用がベストプラクティスです。この記事では、SAML連携の仕組みを理解するためにIAMフェデレーションを使用します。

top-image: この記事全体の概要を掴める図解を挿入

 この記事のメリット

  • SAML連携の基本構成と認証フローを理解できる
  • KeycloakとAWSのSAML SSO環境を実際に構築し、フェデレーションログインの仕組みを体験できる
  • IAMアイデンティティプロバイダーとIAMロールの信頼関係の設定方法を理解できる
  • SAML属性マッピング(RoleSessionName・Role)の設定を習得できる

 技術解説

 SAML連携の基本構成

SAML(Security Assertion Markup Language)2.0は、異なるドメイン間で認証情報を安全にやり取りするためのXMLベースの標準規格です。AWSとのSAML連携では、以下の3つの要素が関係します。

要素説明具体例
アイデンティティプロバイダー(IdP)ユーザーの認証を行い、SAMLアサーションを発行するActive Directory Federation Services(AD FS)、Okta、Keycloakなど
サービスプロバイダー(SP)IdPが発行したSAMLアサーションを受け取り、アクセスを許可するAWS(IAM)
メタデータIdPとSPの間の信頼関係を定義するXMLドキュメント発行者名、有効期限、認証レスポンス検証用のX.509証明書などを含む

メタデータの有効期限(IAMコンソール上の「Valid until」)は、メタデータドキュメント内のvalidUntil属性またはcacheDuration属性から算出されます。validUntilは絶対的な有効期限(タイムスタンプ)を、cacheDurationはメタデータ取得時点からの相対的なキャッシュ有効期間を表します。どちらの属性も存在しない場合、「Valid until」はX.509証明書の有効期限とは一致しません。なお、この有効期限はメタデータドキュメント自体の期限であり、メタデータに含まれるX.509署名証明書の有効期限とは別のものです。

SAML認証フローの概要

SAML連携によるAWSマネジメントコンソールへのログインは、以下のフローで行われます。

sequenceDiagram
    participant Browser as ブラウザ
    participant IdP as IdP<br>(Keycloak)
    participant AWS as AWS<br>(IAM + STS)

    Browser->>IdP: 1. 認証リクエスト(ID/パスワード)
    IdP->>IdP: 2. ユーザー認証
    IdP->>Browser: 3. SAMLアサーション(署名付き)をHTMLフォームで返却
    Browser->>AWS: 4. ブラウザがAWSサインインエンドポイントにSAMLアサーションをPOST
    AWS->>AWS: 5. 署名証明書でSAMLアサーションを検証
    AWS->>AWS: 6. AssumeRoleWithSAMLで一時認証情報を発行
    AWS->>Browser: 7. マネジメントコンソールにリダイレクト

ステップ5の署名検証では、AWSはIAMアイデンティティプロバイダーに登録されているメタデータ内の証明書を使用します。この証明書がIdP側の現在の署名証明書と一致しない場合、検証が失敗し、フェデレーションログインが拒否されます。

なお、AWSではフェデレーションの可用性向上のために、グローバルエンドポイント(https://signin.aws.amazon.com/saml)ではなくリージョナルエンドポイント(https://<region-code>.signin.aws.amazon.com/saml)の使用が推奨されています。

 署名証明書の役割

IdPはSAMLアサーションに対してデジタル署名を付与します。この署名に使用されるのがIdPの署名証明書(X.509証明書)です。メタデータドキュメントに含まれるX.509証明書には、以下の要件があります。

  • キーサイズが最小1024ビット以上であること
  • 証明書の拡張(extension)に重複がないこと(各拡張は1回のみ記載可能)

署名の仕組みは以下の通りです。

  • IdP側: 秘密鍵でSAMLアサーションに署名する
  • AWS側: メタデータに含まれる公開鍵(証明書)で署名を検証する

この仕組みにより、SAMLアサーションが正規のIdPから発行されたものであり、改ざんされていないことを確認できます。

AWS公式ドキュメントでは、SAML V2.0 Metadata Interoperability Profileの定義に基づき、IAMはSAMLメタデータドキュメント内のX.509証明書の有効期限を自動的に評価・対応しないと明記されています。証明書の有効期限の監視とローテーションは、組織のガバナンスおよびセキュリティポリシーに従って実施する必要があります。

 SAML暗号化(補足)

AWS IAMでは、SAMLアサーションの署名検証に加えて、SAMLアサーション自体の暗号化にも対応しています。暗号化を有効にする場合は、IAMアイデンティティプロバイダーに.pem形式の秘密鍵ファイルをアップロードします。暗号化キーのローテーションでは、プロバイダーごとに最大2つの秘密鍵ファイルを保存でき、IAMは追加日が新しいキーから順に復号を試みます。これは署名証明書の更新とは独立した仕組みであり、暗号化の秘密鍵はAWS側で管理するものです。

この記事ではSAML暗号化の詳細については割愛します。なお、IAM Identity CenterおよびAmazon CognitoはIAM SAMLアイデンティティプロバイダーからの暗号化SAMLアサーションに対応していません。

 SAML属性マッピング

AWSのSAMLフェデレーションでは、SAMLアサーションに以下の属性を含める必要があります。

属性名説明設定値の例
https://aws.amazon.com/SAML/Attributes/RoleSessionNameAWSコンソールに表示されるセッション名ユーザー名
https://aws.amazon.com/SAML/Attributes/Role引き受けるIAMロールとプロバイダーのARNペアarn:aws:iam::ACCOUNT_ID:role/KeycloakSSORole,arn:aws:iam::ACCOUNT_ID:saml-provider/Keycloak
https://aws.amazon.com/SAML/Attributes/SessionDuration(任意)セッションの有効期間(秒)3600

Role属性は「ロールARN,プロバイダーARN」の形式でカンマ区切りで指定します。

 IAMロールの信頼ポリシー

SAML フェデレーション用のIAMロールには、以下の信頼ポリシーを設定します。IAMロールの信頼ポリシーで参照するSAMLプロバイダーは、そのロールと同じAWSアカウントに存在する必要があります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::ACCOUNT_ID:saml-provider/Keycloak"
      },
      "Action": "sts:AssumeRoleWithSAML",
      "Condition": {
        "StringEquals": {
          "SAML:aud": "https://signin.aws.amazon.com/saml"
        }
      }
    }
  ]
}
  • Principal.Federated: IAMアイデンティティプロバイダーのARN
  • Actionsts:AssumeRoleWithSAML で、SAMLアサーションによるロール引き受けを許可
  • ConditionSAML:aud(オーディエンス)がAWSサインインエンドポイントであることを条件に指定

 実践

ここでは、KeycloakをDockerで起動してAWSとのSAML SSO環境を構築し、SSOログインが正常に動作することを確認します。

 前提条件

  • AWSアカウントを所有していること
  • Dockerがインストール済みであること

 作成するリソース一覧

リソース種別リソース名作成場所用途
Keycloakサーバーローカル(Docker)ローカル環境IdP
SAMLクライアントurn:amazon:webservicesKeycloak(masterレルム)AWS向けSAML連携設定
クライアントロールIAMロールARN,プロバイダーARNKeycloakAWSロールとの対応付け
ユーザーtestuserKeycloakSSO検証用ユーザー
IAMアイデンティティプロバイダーKeycloakAWS(IAM)SAMLプロバイダー登録
IAMロールKeycloakSSORoleAWS(IAM)SSOログイン用ロール

IAMアイデンティティプロバイダーとIAMロールはグローバルリソースのため、リージョンに依存しません。

 手順1: KeycloakをDockerで起動する

以下のコマンドでKeycloakを開発モードで起動します。

docker run -d -p 8080:8080 \
  -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
  -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
  --name keycloak \
  quay.io/keycloak/keycloak:latest \
  start-dev

起動後、ブラウザで http://localhost:8080 にアクセスし、Keycloakのトップページが表示されることを確認します。ユーザー名 admin、パスワード admin でログインします。

 手順2: AWSのSAMLメタデータを取得する

AWSが公開しているSAMLメタデータをダウンロードします。このメタデータをKeycloakにインポートすることで、SAMLクライアントの設定が自動的に行われます。

curl -o saml-metadata.xml https://signin.aws.amazon.com/static/saml-metadata.xml

 手順3: SAMLクライアントを作成する

AWSのメタデータをインポートしてSAMLクライアントを作成します。

  • 左側ナビゲーションの「Clients」を選択し、「Import client」をクリックします。
  • 「Browse…」をクリックし、手順2でダウンロードした saml-metadata.xml を選択します。
  • Client IDに urn:amazon:webservices が自動的に入力されていることを確認します。
  • 「Save」をクリックします。

 手順4: SAMLクライアントの追加設定

作成されたクライアントの「Settings」タブで、以下の追加設定を行います。

  • IDP-Initiated SSO URL name: aws-saml

この値は任意の文字列ですが、SSOログイン時のURLの一部になります。

  • 「Save」をクリックします。

 手順5: デフォルトMapperを削除して再作成する

Mapper(マッパー)とは、Keycloak内部のユーザー情報(ユーザー名やロールなど)をSAMLレスポンスのどの属性にどのような形式で出力するかを定義する変換ルールです。

メタデータインポート時にデフォルトで作成されるMapperは、AWSが期待する属性名や形式と一致しないため、削除して再作成する必要があります。特にRole listMapperはデフォルトでロールごとに個別のSAML属性要素を生成しますが、AWSはすべてのロールを1つの属性要素にまとめた形式を期待します。

  • クライアント画面の「Client scopes」タブを選択します。
  • urn:amazon:webservices-dedicated をクリックします。
  • 一覧に表示されているMapper(RoleSessionNameRole など)をすべて削除します。

以下の2つのMapperを新規作成します。

Mapper 1: Session Name(RoleSessionName)

  • 「Configure a new mapper」→「User Property」を選択します。
  • 以下を設定します。
    • Name: Session Name
    • Property: username
    • SAML Attribute Name: https://aws.amazon.com/SAML/Attributes/RoleSessionName
    • SAML Attribute NameFormat: Basic
  • 「Save」をクリックします。

Mapper 2: Session Role(Role)

  • 「Add mapper」→「By configuration」→「Role list」を選択します。
  • 以下を設定します。
    • Name: Session Role
    • Role attribute name: https://aws.amazon.com/SAML/Attributes/Role
    • SAML Attribute NameFormat: Basic
    • Single Role Attribute: ON
  • 「Save」をクリックします。

「Single Role Attribute」は必ず ON にしてください。OFF の場合、ロールごとに別のSAML属性が生成され、AWSがパースできずにエラーになります。

 手順6: Client ScopeとScopeの設定

  • クライアント画面の「Client scopes」タブに戻ります。
  • 「Assigned default client scopes」に role_list やsaml_organizationが含まれている場合は、選択して「Remove」をクリックし除外します。

role_list saml_organizationを除外しないと、Keycloakがデフォルトのロール情報をSAMLレスポンスに含めてしまい、AWS側でパースエラーが発生します。

  • urn:amazon:webservices-dedicated をクリックし、「Scope」タブを選択します。
  • 「Full Scope Allowed」を OFF にします。

Full Scope Allowed が ON のままだと、ユーザーに割り当てられたすべてのレルムロールがSAMLレスポンスに含まれてしまい、AWSが期待するARNペア形式と一致しなくなります。

 手順7: AWSでIAMアイデンティティプロバイダーを作成する

先にAWS側のリソースを作成します。後の手順でKeycloak側にAWSのARNを設定する必要があるためです。

まず、KeycloakのSAMLメタデータを取得します。

curl -o keycloak-metadata.xml \
  http://localhost:8080/realms/master/protocol/saml/descriptor
  • AWSマネジメントコンソールにログインし、上部の検索バーに IAM と入力し、表示された「IAM」を選択します。
  • 左側ナビゲーションの「アクセス管理」→「IDプロバイダー」を選択します。
  • 右上のボタン「プロバイダを追加」をクリックします。
  • 「プロバイダの設定」画面で以下を入力します。
    • プロバイダのタイプ: SAML を選択します
    • プロバイダ名: Keycloak
    • メタデータドキュメント: 「ファイルを選択」をクリックし、keycloak-metadata.xml を選択します
    • その他の項目はデフォルトのままにします
  • 「プロバイダを追加」をクリックします。
  • 「アイデンティティプロバイダー」の一覧画面に Keycloak が表示されていることを確認します。プロバイダーのARN(arn:aws:iam::<ACCOUNT_ID>:saml-provider/Keycloak)を控えておきます。

 手順8: IAMロールを作成する

SSOログイン時に引き受けるIAMロールを作成します。

  • 左側ナビゲーションの「アクセス管理」→「ロール」を選択します。
  • 「ロールを作成」をクリックします。
  • 「信頼されたエンティティタイプ」で「SAML 2.0 フェデレーション」を選択します。
  • 以下を設定します。
    • SAML 2.0 ベースのプロバイダー: Keycloak を選択します
    • 「AWS マネジメントコンソールへのアクセスを許可する」を選択します
    • 条件(Condition)はデフォルトのままにします(SAML:aud が https://signin.aws.amazon.com/saml に自動設定されます)
  • 「次へ」をクリックします。
  • 「許可ポリシー」画面で AdministratorAccess を検索して選択します(検証用のため)。
  • 「次へ」をクリックします。
  • 「ロール名」に KeycloakSSORole と入力します。
  • 「ロールを作成」をクリックします。
  • ロール一覧画面で KeycloakSSORole が作成されたことを確認し、ロールのARN(arn:aws:iam::<ACCOUNT_ID>:role/KeycloakSSORole)を控えておきます。

 手順9: Keycloakにクライアントロールを作成する

AWSのIAMロールARNとプロバイダーARNのペアを、Keycloakのクライアントロールとして登録します。

  • Keycloak管理コンソールに戻り、「Clients」→ urn:amazon:webservices を選択します。
  • 「Roles」タブを選択し、「Create role」をクリックします。
  • 「Role name」に以下の形式で入力します。
    • arn:aws:iam::<ACCOUNT_ID>:role/KeycloakSSORole,arn:aws:iam::<ACCOUNT_ID>:saml-provider/Keycloak

<ACCOUNT_ID> は実際のAWSアカウントIDに置き換えてください。このロール名がSAMLアサーションのRole属性値としてそのまま送信されます。カンマの前後にスペースを入れないでください。

  • 「Save」をクリックします。

 手順10: Keycloakにユーザーを作成してロールを割り当てる

  • 左側ナビゲーションの「Users」を選択し、「Add user」をクリックします。
  • 以下を入力します。
    • Username: testuser
    • Email: testuser@example.com
    • Email verified: Off
    • First name: Test
    • Last name: User
  • 「Create」をクリックします。
  • 作成されたユーザーの「Credentials」タブを選択し、「Set password」をクリックします。
  • パスワードを設定し、「Temporary」を OFF にして「Save」をクリックします。
  • 「Role mapping」タブを選択します。
  • デフォルトで default-roles-master が割り当てられています。これを選択し、「Unassign」をクリックして削除します。

default-roles-master に含まれるレルムロール(offline_accessuma_authorization など)がSAMLレスポンスのRole属性に混入すると、AWSがARNペア形式としてパースできずエラーになります。

  • 「Assign role」> 「Client roles」をクリックします。
  • urn:amazon:webservices のロール(arn:aws:iam::...)を選択し、「Assign」をクリックします。

 手順11: SSOログインを確認する

SSOログインの確認は、Keycloakの管理者(admin)とは別のブラウザまたはシークレットウィンドウで行ってください。adminユーザーにはAWSロールが割り当てられていないため、そのままではエラーになります。

ブラウザで以下のIdP-initiated SSO URLにアクセスします。

http://localhost:8080/realms/master/protocol/saml/clients/aws-saml

http://localhost:8080/realms/master/protocol/saml/clients/aws-saml
  • Keycloakのログイン画面が表示されます。手順10で作成したユーザー(testuser / 設定したパスワード)でログインします。
  • 認証が成功すると、AWSマネジメントコンソールにリダイレクトされます。
  • 右上のユーザー情報に KeycloakSSORole/testuser のように表示されていれば、SAMLフェデレーションによるSSOログインが成功しています。

トラブルシューティング

SSOログインが失敗する場合は、ブラウザの開発者ツール(Network タブ)で signin.aws.amazon.com へのPOSTリクエストから SAMLResponse を取得し、Base64デコードしてSAMLレスポンスの内容を確認してください。

echo '<SAMLResponseの値>' | base64 -d
エラーメッセージ原因対処
client_not_found(Keycloakログに出力)IDP-Initiated SSO URL nameが未設定クライアントのSettingsで aws-saml を設定する
Your request included an invalid SAML response(Role属性が空)Mapperが正しく設定されていない手順5のMapper設定を再確認する
Your request included an invalid SAML response(Role属性にARN以外の値が混入)role_listが除外されていない、またはFull Scope AllowedON手順6の設定を再確認する
Not authorized to perform sts:AssumeRoleWithSAMLユーザーにdefault-roles-masterのレルムロールが残っており、Role属性にARN以外の値が混入手順10でdefault-roles-masterを削除する
adminでログインするとエラーadminにはクライアントロールが割り当てられていない別のタブでadminにログインしているとそのユーザでログインしていることになってしまします。ログアウトするかシークレットウィンドウで testuser でログインする

 まとめ

KeycloakとAWSのSAML SSO環境構築では、以下のリソースを作成・連携します。

作成場所リソース役割
KeycloakSAMLクライアント urn:amazon:webservicesAWSのSAMLメタデータをインポートして作成。属性マッピングでRole・RoleSessionNameを設定
Keycloakクライアントロール(ARNペア)IAMロールARNとプロバイダーARNの対応付け
AWS(IAM)アイデンティティプロバイダー KeycloakKeycloakのメタデータ(署名証明書)を登録
AWS(IAM)ロール KeycloakSSORoleSSOログイン時に引き受けるロール(信頼ポリシーでSAMLプロバイダーを指定)

Keycloakに別のSAMLクライアントを追加すれば、同じユーザーIDで他のサービスにもSSOログインできるようになります。これがSSOの「1つのIDで複数のサービスにログインできる」というメリットです。

 参照先

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

株式会社Luxy(https://luxy-inc.com)の代表取締役.

2018年〜インフラエンジニアとしてキャリアをスタートし、オンプレミスのネットワーク・サーバ環境で3年半、クラウド環境で4年半の8年間エンジニアとして従事。
2021年に佐藤氏の創業した会社を引き継ぎ、代表に就任。

目次