ブログ

ryuzeeによるブログ記事。不定期更新
アジャイル開発に取り組むチーム向けのコーチングや、技術顧問、認定スクラムマスター研修などの各種トレーニングを提供しています。ぜひお気軽にご相談ください(初回相談無料)

Keycloakを使ってAWSにSSO接続する方法

みなさんこんにちは。@ryuzeeです。

たくさんのAWSアカウントを持っていたり、さまざまな外部サービスを使っていたりすると面倒なのが、アカウント自体の管理です。 今日はKeycloakを使って、たくさんのAWSアカウントにSSO接続するようにしてみたいと思います。

Keycloakとは

Keycloakは認証・認可のためのオープンソースソフトウェアです。最新のバージョンは4.1.0です。 より詳細については@ITの記事がわかりやすいです。

Keycloakの導入

KeycloakはJavaで書かれており、動作にはアプリケーションサーバが必要です。 アプリケーションで利用可能なデータベースは、MySQL、PostgreSQL、MariaDB、そして主に開発や試用用途のH2です。

また、公式のDockerイメージも用意されており、それを使えばアプリケーションサーバの設定などは不要です。 今回は簡単にするため、Dockerを使ってみましょう。

docker-composeを使うのが簡単で、以下から入手できます。

ここでは、PostgreSQLを使います。

wget https://github.com/jboss-dockerfiles/keycloak/raw/master/docker-compose-examples/keycloak-postgres.yml
docker-compose -f keycloak-postgres.yml

とすれば起動します。起動後にhttp://localhost:8080にアクセスして以下のような画面が表示されればOKです。

Keycloakへのログイン

画面のAdministration Consoleをクリックして管理者画面にログインします。 管理者アカウントの初期ユーザーとパスワードはdocker-composeの中で、KEYCLOAK_USERKEYCLOAK_PASSWORDで定義されているので、それを使います。

ログイン後には以下のような画面が表示されます。

ここは特にいじる箇所がないので、AWSのSSOの設定に進みましょう。

AWSのSAML情報を取得する

まず、AWSのSAML情報を以下のコマンドで取得し、ローカルに保存します。

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

クライアントを追加する

Clientsにアクセスすると、以下のようにクライアントの一覧が表示されます。 画面右側にあるCreateボタンをクリックします。

クライアントの追加画面が下のように表示されます。

  • Importを選択し、先程ダウンロードしたsaml-metadata.xmlを指定します
  • Base URLには/auth/realms/master/protocol/saml/clients/amazon-awsを指定します
  • IDP Initiated SSO URL Nameにはamazon-awsを指定します

それが終わったらSaveボタンをクリックします。 以下のような画面が表示されるはずです。

AWSのSAML Provider用の設定ファイルを取得する

Installation タブにアクセスし、SAML Metadata IDPSSODescriptorを選択します。 以下のように表示されますので、Downloadをクリックしてファイルを保存します。 client-tailored-saml-idp-metadata.xmlという名前のファイルができたことを確認しておきます。

AWS(統合したいアカウントそれぞれ)上でSAML Providerの設定をする

SSO接続したいAWSアカウントの設定を行います。

  • マネジメントコンソールでIAMにアクセスし、Identity providers(日本語だとIDプロバイダ)を選択します
  • Create Providerをクリック。Provider TypeSAMLを選択します
  • Provider Nameには適当な名前を指定します
  • Metadata Documentには先ほどKeycloakからダウンロードしたXML(client-tailored-saml-idp-metadata.xml)を指定します

なお、awscliを利用する場合は以下のようなコマンドで作成できます(nameオプションは自分の好みにします)。

aws iam create-saml-provider --saml-metadata-document file://./client-tailored-saml-idp-metadata.xml --name docker-keycloak

ここで作成されたSAMP ProviderのARN(arn:aws:iam::211111666666:saml-provider/docker-keycloakのようなもの)は後で使いますので控えておきます(※1)。

AWS(統合したいアカウントそれぞれ)上にIAM Roleを作成する

次に、SSO経由でログインしたユーザーに割り当てるIAM Roleを作成します。

またIAM Roleの画面で信頼関係を編集し、以下のようなポリシードキュメントに更新します。 Principalの値は各自異なります(アカウント番号やSAM Provierの名前など自分のものに合わせます)。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::211111666666:saml-provider/docker-keycloak"
      },
      "Action": "sts:AssumeRoleWithSAML",
      "Condition": {
        "StringEquals": {
          "SAML:aud": "https://signin.aws.amazon.com/saml"
        }
      }
    }
  ]
}

なお、CloudFormationで作成したい場合は、こちらからスクリプトをダウンロードし、中身を書き換えて(RoleNameなど)以下のように実行すると良いでしょう。

aws cloudformation create-stack --capabilities CAPABILITY_NAMED_IAM --stack-name sso-roles --template-body file://./sso-roles-cfn.yaml

ここで作成したIAM RoleのARNもあとで使いますので控えておきます(※2)。

以上ができたらKeycloak側に戻ります。

ロールの作成

新規でロールを作成するためにAdd Roleを選択します。 以下のような画面が表示されるので、

  • Nameの箇所にIAM RoleのARN、SAML ProviderのARNをカンマで結合して入力します(※1と※2を結合します)。
  • Descriptionの箇所は説明なので、適当に入れておきます。

入力が終わったらSaveをクリックします。

この作業もSSO対象のAWSアカウントの数だけ繰り返します。

Mapperの定義

次にMapperを定義します。Mappersを選択して、Createをクリックして3つの設定を作成します。

  • Session Role
    • Name:Session Role
    • Mapper Type:Role list
    • Role attribute name:https://aws.amazon.com/SAML/Attributes/Role
    • Friendly Name:Session Role
    • SAML Attribute Name Format:Basic
    • Single Role Attribute:ON
  • Session Name
    • Name:Session Name
    • Mapper Type:User Property
    • Property:username
    • Friendly Name:Session Name
    • SAML Attribute Name:https://aws.amazon.com/SAML/Attributes/RoleSessionName
    • SAML Attribute Name Format:Basic
  • Session Duration
    • Name:Session Duration
    • Mapper Type:Hardcoded attribute
    • Friendly Name:Session Duration
    • SAML Attribute Name:https://aws.amazon.com/SAML/Attributes/SessionDuration
    • SAML Attribute Name Format:Basic
    • Attribute value:28800

入力の結果、以下のようになればOKです。

続いてClient Scopesを選択し、Assigned Default Client Scopesの中にrole_listがある場合はRemove selectedをクリックして選択を解除します。 以下のようになれば大丈夫です。

スコープの設定

次にScopeにアクセスし、Full Scope Allowed をOffに設定します。

以上で、クライアントの設定は終了です。

ユーザー作成

続いてユーザーを作成して、権限を割り当てていきます。

左ナビゲーションのUsersを選択すると、一覧画面が表示されるので、Add userをクリックします。 そこで必要な情報を入力してSaveします。以下のような画面が表示されるはずです。

Rolle Mappingsタブに移動すると、左側にClient Rolesのプルダウンからurn:amazon:webservicesを選択します。 Available Rolesの中から当該のアカウントに割り当てたいロールを選択して、Add selectedを選択します。

この作業は利用するAWSアカウント分繰り返します。

また初期パスワードも設定します。Credentialsタブに移動して、Manage Passwordの項目を設定しておきます。

準備完了

以上で準備完了です。

http://localhost:8080/auth/realms/master/protocol/saml/clients/amazon-awsにアクセスして、ログインすると、AWSの画面が次のような感じで表示されれば成功です。

おまけ

このままだと、ローカルのPC上なので実用できないので、Azure上に環境を用意します。

Azure上に環境を作るときは、Azure Cloud Shellを活用するのが便利です。以下を貼り付けると10分くらいで環境が出来上がります(※パスワードなどは適宜変更します)。 なお、追加のパラメータでJDBCの設定をしておくとよさそうです。

export rand=$RANDOM
export resourcegroup=keycloak-$rand
export appservice_plan=appserviceplan$rand
export appservice_name=keycloak-app-$rand
export region='Japan West'
export appservice_instance=B1
export db_server_name=db$rand
export db_admin_user=adminuser
# !!!CHANGE VALUE!!!
export db_admin_password=CHANGE_ME_CHANGE_ME!
export db_sku=B_Gen4_1
export db_firewall_rule=db$rand
export db_name=keycloak$rand
export db_addr="$db_server_name.postgres.database.azure.com"
export db_vendor=postgres
export container_image=jboss/keycloak
export keycloak_user=admin
# !!!CHANGE VALUE!!!
export keycloak_password=CHANGE_ME_CHANGE_ME!

az group create \
   --name "$resourcegroup" \
   --location "$region"

az appservice plan create \
   --name "$appservice_plan" \
   --resource-group "$resourcegroup" \
   --sku "$appservice_instance" \
   --is-linux

az postgres server create \
   --resource-group "$resourcegroup" \
   --name "$db_server_name" \
   --location "$region" \
   --admin-user "$db_admin_user" \
   --admin-password "$db_admin_password" \
   --sku-name "$db_sku" \
   --storage-size 51200 \
   --version "9.6" \
   --ssl-enforcement "Disabled"

az postgres server firewall-rule create \
   --name "$db_firewall_rule" \
   --server "$db_server_name" \
   --resource-group "$resourcegroup" \
   --start-ip-address 0.0.0.0 \
   --end-ip-address 255.255.255.255

az postgres db create \
   --resource-group "$resourcegroup" \
   --server-name "$db_server_name" \
   --name "$db_name"

az webapp create \
   --resource-group "$resourcegroup" \
   --plan "$appservice_plan" \
   --name "$appservice_name" \
   --deployment-container-image-name "$container_image"

az webapp config appsettings set \
   --resource-group "$resourcegroup" \
   --name "$appservice_name" \
   --settings \
     PROXY_ADDRESS_FORWARDING=true \
     DB_VENDOR=$db_vendor \
     DB_DATABASE="$db_name" \
     DB_ADDR="$db_addr" \
     DB_USER="$db_admin_user@$db_server_name" \
     DB_PASSWORD="$db_admin_password" \
     KEYCLOAK_USER="$keycloak_user" \
     KEYCLOAK_PASSWORD="$keycloak_password" \
     JDBC_PARAMS="autoReconnect=true"

それでは。