閉域に Keycloak を構築して SAML 2.0 で AWS マネージメントコンソールに SSO を試す

標準化でシステム間のファイル連携を考える時、標準準拠システムが AWS 同士ならば AWS の認証認可の仕組みを使ってオブジェクトストレージ S3 で比較的簡単にファイルを連携できます。しかし、標準準拠システムが AWS とその他の CSP で構成されていたり、オンプレミスと AWS との間でファイル連携が必要だったりする場合、[地方公共団体情報システム認証機能・ファイル連携機能に関するリファレンス（推奨指針）ガイド](https://www.digital.go.jp/policies/local_governments/common-feature-specification#specifics-reference) によると認証認可サーバを自前で構築する必要があるとされています。

標準準拠システムのファイル連携における認証認可サーバのため、認証認可サーバは閉域内に設置する必要があります。閉域内で使える認証認可サーバとして、オープンソースの [Keycloak](https://www.keycloak.org/) を採用することが多いようです。

そこで、閉域内に Keycloak をテストで構築し、AWS マネージメントコンソールに SSO する手順を試すことで、Keycloak の動作を学んでみたいと思います。

なお、実際にガバメントクラウド環境で Keycloak を導入する場合、閉域内から AWS マネージメントコンソールにアクセスすることはできません。ファイル連携の認証認可サーバとして Keycloak を使うには、別途クレデンシャルから必要な情報を抜き出し、閉域内で S3 へのアクセスに使う仕組みを構築する必要があると思います。

今回は実際にガバメントクラウドで使える手順にはなっていないのでお気を付けください。また、セキュリティも一切考慮していないテストのため、実運用時はしっかりセキュリティ対策を行う必要があります。

## Keycloak の事前設定

### Keycloak を Docker で起動する

Keycloak をテストするのに一番簡単なのは、Keycloak は公式の Doceker イメージを使うことかと思います。

今回、プライベートサブネットのみの VPC に Amazon Linux の EC2 を立て、Docker を使えるようにしました。AWS に閉域環境を作る手順は過去に記事にしているので興味があれば参照してください。

https://qiita.com/takeda_h/items/32416c0536aac3698065

詳細な手順は省略しますが、インターネットアクセス可能な環境で Keycloak の Doceker イメージを pull し、SCP で Docker イメージを転送し、EC2 側の Docker で load しました。公式の手順は以下のとおりです。

https://www.keycloak.org/getting-started/getting-started-docker

以下のコマンドで TCP 8080 番でサービスが上がり、ユーザー名とパスワードが admin で Keycloak の管理コンソールにアクセスできるようになります。

```
$ docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.1.0 start-dev
```

### Client の設定

Doceker イメージが正常に起動したら、作業用のクライアントから、SSH ポートフォワーディングでクライアントのローカルホストから閉域の EC2 の Keycloak の TCP 8080 番ポートにアクセスできるようにし、ブラウザでアクセスし、ログインします。

[https://signin.aws.amazon.com/static/saml-metadata.xml](https://signin.aws.amazon.com/static/saml-metadata.xml) から SAML メタデータ（XML）をダウンロードしておきます。

「Clients」から「Import Client」に進み、上記の XML ファイルをアップロードして「Save」します。

![スクリーンショット 2025-01-26 150828.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/eba8204b-5d86-f3b6-40d6-da5ed69ab0d9.png)

次の画面で以下のとおり設定します。

| Item                       | Value                                         |
|:---------------------------|:----------------------------------------------|
| Root URL                   | http://localhost:8080                         |
| Home URL                   | /realms/master/protocol/saml/clients/aws-saml |
| Valid Redirect URIs        | https://signin.aws.amazon.com/saml            |
| IDP-Initiated SSO URL name | aws-saml                                      |

![スクリーンショット 2025-01-26 162346.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/81405d4d-0483-6039-bde0-c238602ee483.png)

### SAML 2.0 Identity Provider Metadata のダウンロード

「Realm Settings」から「SAML 2.0 Identity Provider Metadata」をダウンロードします。

![スクリーンショット 2025-01-26 162446.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/88ff285d-fe48-b490-ba19-ecef856d2e9f.png)

次に AWS マネージメントコンソール側で ID プロバイダなどの設定をしていきます。

## IAM の設定

### ID プロバイダの追加

マネージメントコンソールから「IAM」→「ID プロバイダの追加」に進みます。

先の手順でダウンロードした SAML 2.0 Identity Provider Metadata の XML ファイルをアップロードします。

![スクリーンショット 2025-01-26 162657.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/8fdc38aa-511a-013e-f451-97240e0a143c.png)

### IAM ロールの割り当て

作成した ID プロバイダに IAM ロールを割り当てます。

![スクリーンショット 2025-01-26 162726.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/c6908412-686d-615e-1c71-f7e86c3b2e83.png)

テストなので、新規に S3ReadOnlyAccess ポリシーをセットしたロールを作成して割り当てました。

![スクリーンショット 2025-01-26 163013.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/4158a4bd-d046-bc43-a5e5-cbbbbf61017b.png)

![スクリーンショット 2025-01-26 163220.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/d55ae734-c24b-71c5-949d-e1c0eade9521.png)

任意のロール名を設定します。

![スクリーンショット 2025-01-26 163323.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/54ac7f2f-7596-94c0-e1cf-a75e1b042a2f.png)

IAM ロールの設定が終わったら、ID プロバイダと IAM ロールのそれぞれの ARN をコピーしておきます。後で Keycloak の設定に使います。

![スクリーンショット 2025-01-26 163527.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/9ecb88b2-1d36-a086-a72a-10635c56454e.png)

![スクリーンショット 2025-01-26 163553.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/6a80c765-89bd-3f4a-64db-5b384f82d790.png)

## Keycloak の 設定

### Role の作成

「Clients」から「urn:amazon:webservices」→「Roles」→「Create Role」へ進みます。

「Role Name」に先ほどコピーした IAM ロールの ARN、カンマ、ID プロバイダの ARN の順で繋げた文字列を入力します。

![スクリーンショット 2025-01-26 163727.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/42c649c1-3761-ba0e-d25f-41116ce14fbf.png)

次に「Client Scopes」に進みます。表示されている「Assigned client scope」から「role_list」を削除しておきます。

![スクリーンショット 2025-01-26 164356.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/94a85686-ef95-cb77-25e7-81ddade35518.png)

次に表示されている「Assigned client scope」から「urn:amazon:webservices-dedicated」→「Mappers」のに進みます。

表示されている一覧の項目を一旦全部消したら、「Add Mapper」→「By Configuration」に進みます。

![スクリーンショット 2025-01-26 164929.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/fb9d8cf1-6e8f-8532-5318-c8ce389a002f.png)

「User Property」と「Role list」を作成していきます。

![スクリーンショット 2025-01-26 165016.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/bc04ac24-3cce-3a3e-d006-39419078f840.png)

まずは「User Property」です。

| Item                | Value                                                  |
|:--------------------|:-------------------------------------------------------|
| Mapper Type         | User Property                                          |
| Name                | Session Name                                           |
| Property            | username                                               |
| Friendly Name       | Session Name                                           |
| SAML Attribute Name | https://aws.amazon.com/SAML/Attributes/RoleSessionName |

![スクリーンショット 2025-01-26 170033.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/715cba0c-3f2c-949c-9bff-7217a0306260.png)

次に「Role list」です。

| Item                | Value                                       |
|:--------------------|:--------------------------------------------|
| Mapper Type         | Role list                                   |
| Name                | Session Role                                |
| Role Attribute Name | https://aws.amazon.com/SAML/Attributes/Role |
| Friendly Name       | Session Role                                |

![スクリーンショット 2025-01-26 174206.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/bb863302-8b98-390f-3b18-378e89d3ce41.png)

Mappers の設定が終わったら「Scope」へ進み、「Full scope allowed」を「off」にします。

![スクリーンショット 2025-01-26 172308.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/506ae803-2d7d-8551-f12b-db588de6c7ac.png)

### Group の作成

Keycloak で認証するユーザーを作成していきます。先にユーザーを所属させるグループを作成します。

「Groups」から「Create Group」に進み、任意のグループ名でグループを作成します。

![スクリーンショット 2025-01-26 170258.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/d498244d-5873-faa6-61a2-b12986d4aad6.png)

グループを作成したら、このグループの詳細設定から「Role Mapping」→「Assign Role」に進みます。

![スクリーンショット 2025-01-26 170425.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/a1df5d37-5f73-a921-5732-ea47bdcc17c6.png)

先の手順で作成した「urn:amazon:webservice」になっているロールを「Assign」します。

![スクリーンショット 2025-01-26 170445.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/1b90604b-f89b-b21f-be77-6a3d861a9b19.png)

### User の作成

「Users」から新規ユーザーを作成します。先ほど作成したグループに所属するよう設定し、任意の名前でユーザーを作成します。

![スクリーンショット 2025-01-26 170649.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/c4eb6ef1-56f3-30fb-c5c4-882e460bfd8d.png)

ユーザーを作成したら、このユーザー詳細設定から「Credentials」→「Set password」に進み、適当なパスワードを設定します。

![スクリーンショット 2025-01-26 171006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/461de873-ebe1-5c04-a2b3-4d9923f1eb79.png)

ここまで来たら Keycloak の設定は完了です。早速 AWS のマネージメントコンソールに Keycloak を使った SSO ができるか試してみましょう。

## Keycloak の URL から作成したユーザーでログインする

一旦 Keycloak の管理コンソールからログアウトします（重要）。そのままだと admin というユーザーで SSO しようとして当然ですが失敗します。

ログアウトしたら http://localhost:8080/realms/master/protocol/saml/clients/aws-saml にブラウザでアクセスします。

![スクリーンショット 2025-01-26 171545.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/46578681-4cf4-cb15-61c6-830fcad7b537.png)

AWS のマネージメントコンソールにリダイレクトされ、フェデレーテットユーザーとして紐づけられた IAM ロールの権限でアクセスできていれば成功です。

![スクリーンショット 2025-01-26 172509.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/dc67527c-7174-6156-f837-e2dc197f8fdf.png)

## 分かったことなど

SAML 2.0 を使った認証であれば、Keycloak で作成した公開鍵を AWS の ID プロバイダに設定しているので、AWS 環境から Keycloak にアクセスできなくても認証ができるため、閉域のオンプレミスなどに Keycloak を構築する方法でもよいことが分かりました。

ガバメントクラウドのファイル連携で、他 CSP やオンプレミスから S3 にアクセスするために AWS の認証認可が使えない場合は、他 CSP、オンプレミスからアクセスできる閉域内に Keycloak などの IdP を構築する必要がある理由が腹落ちしました。

実際に SAML 認証で得たクレデンシャルを使って S3 にアクセスするアクセスキーを取り出すためには、もう一歩踏み込まないとならないですが、かなり難しそうなので検証は一旦ここまでにしたいと思います。

## 参考サイト

https://qiita.com/gaichi/items/4e58d1d1c3ad4a024ffd

https://qiita.com/wadahiro/items/ff0f45b474001f515705

https://aws.amazon.com/jp/blogs/news/auth-lg-governmentcloud-jp/