Concourse CI のログインは Keycloak で SSO したい
社内プロジェクトの CI に Concourse CI どうだろう?と試してみましたが、なかなか好感触だったのでもうちょっとしっかりと使いこんでみようかな、ということで Concourse CI の豊富なログイン方式を備えているので Keycloak と SSO をやってみたいと思います。
とは言え、Concourse CIもKeycloakも豊富な接続方式を持っていますので・・・まずはシンプルにOpenID Connect での SSO に挑戦してみたいと思います!
以下の Concourse CI の OpenID Connect のページを参考に、手順をご説明いたします。
1. Concourse CI、Keycloak の準備
今回も docker-compose でサクッと立ち上げてしまいます。
本家サイトの"Quick Start"にある docker-compose.yml
をダウンロードし、サービス:"keycloak" を加えました。
version: '3'
services:
concourse-db:
image: postgres
environment:
POSTGRES_DB: concourse
POSTGRES_PASSWORD: concourse_pass
POSTGRES_USER: concourse_user
PGDATA: /database
concourse:
image: concourse/concourse
command: quickstart
privileged: true
depends_on: [concourse-db,keycloak]
ports: ["8080:8080"]
environment:
CONCOURSE_POSTGRES_HOST: concourse-db
CONCOURSE_POSTGRES_USER: concourse_user
CONCOURSE_POSTGRES_PASSWORD: concourse_pass
CONCOURSE_POSTGRES_DATABASE: concourse
CONCOURSE_EXTERNAL_URL: http://cc.10.143.60.16.xip.io:8080/
CONCOURSE_ADD_LOCAL_USER: test:test
CONCOURSE_MAIN_TEAM_LOCAL_USER: test
CONCOURSE_WORKER_BAGGAGECLAIM_DRIVER: overlay
keycloak:
image: jboss/keycloak:7.0.1
container_name: keycloak
restart: always
ports:
- 8180:8180
environment:
- KEYCLOAK_USER=kcadmin
- KEYCLOAK_PASSWORD=kcadmin
command: >
-b 0.0.0.0
-Djboss.http.port=8180
tty: true
CONCOURSE_EXTERNAL_URL
に ワイルドカードDNSのxip.io を使ってローカルアドレスに無理やりドメイン名を与えてしまいます。cc.10.143.60.16.xip.io
というドメインから10.143.60.16
を解決してくれるありがたいサービスです。
このIPアドレスは実行時のホストのIPアドレスに差し替えてください。
これを docker-compose up -d
で立ち上げます。
$ docker-compose up -d
はい、サーバーの起動は以上です!
ちなみに keycloak は 8.0.0 がリリースされていますが、jboss/keycloak:8.0.0.
はエントリーポイントのスクリプトのエラーで立ち上がりませんでした。。。何か、設定が変わっているのでしょう・・・
2. Keycloak でレルム定義
続いて OpenID Connect 用のレルム定義を、Keycloak で行います。
以下の記事などを参考に、クライアントの"Access Type"が"Credential"で繋がるように設定を行います。
2-1. レルムの追加
新規のレルムとして concourse-ci
としてレルムを追加します。この名前は適当で大丈夫です。
作成後の詳細画面でエンドポイントが確認できます。今回は issuer
のエントリポイントのみを使用します。
また他のログインに対応するにはここからエンドポイントのURLをコピペしてください。
2-2. クライアントの追加
クライアントの新規追加から concourse-ci
を追加し、"アクセスタイプ" をconfidential
に変更します。
ここでリダイレクト先のURLにはConcourseのURL + "/sky/issuer/callback"を宛先とします。
今回の場合は、"http://cc.10.143.60.16.xip.io:8080/sky/issuer/callback" となります。
設定が完了したら、"save" ボタンをクリックしてください。
2-3. 認証キーの取得
アクセスタイプを"confidential"に変更したことで、"Credential"のタブが表示されるようになったはずです。
"Credential"のタブをクリックして認証キーをコピペしておきましょう。
2-4. ロールの追加
クライアントconcourse
のロールということで、今回はuser
ロールを追加しましょう。
2-5. マッパーの追加と編集
Mapper
タブから"Add builtin"をクリックします。
Mapperの一覧が表示されるので、"client roles" と "username" を選択し、"Add Selected" をクリックでマッパーを追加します
続いて、"username"の"Token Claim Name"を "username"に変更します。
続いて、"client roles"の"Client ID"にconcourse-ci"とし、"Token Claim Name"を "groups"に変更します。
また、ID Token、Access Token、Userinfoのどれにも追加されるようにADDのチェックをそれぞれ入れます。
2-6. ユーザーの追加とロールのアサイン
今回は "cc001" というユーザを追加し、concourse-ci
のクライアントロール user
にアサインいたしました。
Keycloak での作業は以上です。
3. Concourse の環境変数変更
Concouse CI が起動するときの環境変数で、Keycloak を OIDC サーバーとして参照するように設定します。
以下のように docker-compose.yml に環境変数を追加します。
...
concourse:
image: concourse/concourse
...
environment:
CONCOURSE_POSTGRES_HOST: concourse-db
CONCOURSE_POSTGRES_USER: concourse_user
CONCOURSE_POSTGRES_PASSWORD: concourse_pass
CONCOURSE_POSTGRES_DATABASE: concourse
CONCOURSE_EXTERNAL_URL: http://cc.10.143.60.16.xip.io:8080/
CONCOURSE_ADD_LOCAL_USER: test:test
CONCOURSE_MAIN_TEAM_LOCAL_USER: test
CONCOURSE_WORKER_BAGGAGECLAIM_DRIVER: overlay
CONCOURSE_OIDC_DISPLAY_NAME: ConcourseCI
CONCOURSE_OIDC_CLIENT_ID: concourse-ci
CONCOURSE_OIDC_CLIENT_SECRET: xxxxxxxx-xxxx-xxxx-xxx-xxxxxxxxxx
CONCOURSE_OIDC_ISSUER: http://10.145.61.6.xip.io:8180/auth/realms/concourse-ci
...
まず、CONCOURSE_OIDC_DISPLAY_NAME
はログイン画面で表示されるOIDCでログインする際のボタンのラベルです。これはわかりやすければなんでもOKかと思います。
続いてCONCOURSE_OIDC_CLIENT_ID
と、CONCOURSE_OIDC_CLIENT_SECRET
はKeycloakで追加したクライアントconcourse-ci
のクライアントIDと、"Credential"のタブで表示されていた認証キーです。
最後のCONCOURSE_OIDC_ISSUER
がissuer
のエントリポイントのURLとなります。
docker-compose.ymlの修正後、再度 docker-compose up -d
を実行してコンテナを再作成させてください。
docker-compose ps
などで concourse コンテナが止まっていた場合は docker-compose logs concourse
などでエラーメッセージをチェックしてみてください。
http://10.145.61.6.xip.io
にアクセスできないエラーが出ている場合は、nslookup
を一度実行すれば、ちゃんと名前解決できるようになります。
4. チームの追加
Keycloak でログインするユーザーを受け付ける"チーム"を作成します。
まず以下のコマンドで test
ユーザーでログインします。
$ fly login -t hello -u test -p test -c http://localhost:8080
logging in to team 'main'
target saved
続いて、Keycloakで設定したロールuser
にmyAppDevTeam
を割り当ててみます。
$ fly -t hello set-team -n myAppDevTeam --oidc-group user
setting team: myAppDevTeam
role owner:
users:
- local:test
groups:
none
apply team configuration? [yN]: y
team created
これで、user
ロールでログインしたユーザーはmyAppDevTeam
チームに配属されることとなりました。
ちなみに、環境変数 CONCOURSE_MAIN_TEAM_OIDC_GROUP
で特定のロールを丸ごとmain
チームに割り当てることも可能です。
concourse:
...
environment:
...
CONCOURSE_MAIN_TEAM_OIDC_GROUP: admin
...
などと設定すると、Keycloak で admin
ロールにアサインしたユーザーは、自動的にmain
チームに参加いたします。
5. ログイン
いよいよログインの時です!
ブラウザで http://cc.ホストのIPアドレス.xip.io:8080/
を開き login here
からログイン画面へ移動してください。
CONCOURSE_OIDC_DISPLAY_NAME
で設定した "ConcourseCI" ボタンが表示されているかと思います。(今更ですが、命名間違えたな・・・)
ここをクリックするとKeycloakのログイン画面へ移ります。
はい、ここで cc001
ユーザーでログインします。
初回はパスワードリセットが走ると思います。うまくいくと・・・
cc001
ユーザーが無事にmyAppDevTeam
に参加できました!
6. fly
でログイン
Concourse CI は基本的な操作を fly
コマンドから行います。つまり、fly
コマンドでもログイン必要、ですよね・・・?
という場合もOKです。以下のように fly login
が使えます。(ブラウザの方からは一旦ログアウトしておいたほうがいいかもしれません。)
$ fly -t hello login -n myAppDevTeam -c http://cc.10.4.97.184.xip.io:8080/
logging in to team 'myAppDevTeam'
navigate to the following URL in your browser:
http://cc.10.4.97.184.xip.io:8080/login?fly_port=58077
or enter token manually:
で、表示されるURLをブラウザから開くと先ほどと同様にログイン方法の選択からログインの流れが行えて・・・
とブラウザに表示されます。
ターミナルの方では、
...
or enter token manually:
target saved
と表示され、keycloakでユーザーがログインした状態が-t hello
に保持され、これ以降は、cc001
ユーザーとして fly
コマンドが利用可能になります!
まとめ
Concourse CI は本体のユーザー管理機能がほとんど使えない代わりに非常に接続方法が充実しています。
Concourse CI にもロールやグループといった概念は(編集機能がCLIしかない割には)ガッツリ実装されているので、そのマッピングをちゃんとやらなければなりませんが、LDAPやSAMLも使えるのでかなり企業向けの機能もしっかりしているかと思います。
本記事で作成したdocker-compose.yml
は以下のリポジトリに上げました。ご参考にどうぞ。
Concourse CI ネタ、続きます!w