この記事は
- keycloakをcloudflare tunnelを使って,証明書の設定なしに自宅サーバーで運用する方法
- Docker imageのkeycloakをSSLなしに運用する方法
を記す
あらすじ
自前で作成したサービスに認証を追加するにあたって,ロールを用いてアクセスの許可・不許可を制御する仕組みを整えたかったため,keycloakを採用した.そこでkeycloakをdocker-composeで起動できるように色々試行錯誤したので,それをまとめる.また,認証基盤を自身が所有しているドメインで公開するために,cloudflare tunnelを使うための設定もまとめる.
問題点
まず何が困るか
開発段階で,実際に運用するサーバーに設置して,VPNでアクセスできるようにしたかったのだが,quay.ioのimageでは,初期設定でSSLがExternalのアクセスには必須となっており,アクセスができなかった.
FROM quay.io/keycloak/keycloak:latest
services:
keycloak:
build:
context: ./keycloak
dockerfile: Dockerfile
tty: true
stdin_open: true
environment:
DB_VENDOR: POSTGRES
DB_ADDR: postgres
DB_DATABASE: ${POSTGRES_DB_NAME}
DB_USER: ${POSTGRES_USER}
DB_PASSWORD: ${POSTGRES_PASSWORD}
KEYCLOAK_ADMIN: ${KC_ADMIN_NAME}
KEYCLOAK_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD}
TZ: "Asia/Tokyo"
ports:
- "8010:8080"
depends_on:
- postgres
volumes:
- ./keycloak/.data:/opt/keycloak/data
postgres:
image: postgres:latest
environment:
POSTGRES_DB: ${POSTGRES_DB_NAME}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "5432:5432"
volumes:
- ./postgres/.data:/var/lib/postgresql/data
記事( https://qiita.com/ktaka1104/items/d15d5bbf87d5aadbe775 )を参考にしつつ,Dockerfileとyamlを作成し,起動すると起動はするが,外部からアクセスできない.ただし,各サービスには,Volumeでホストのディレクトリをマッピングしており,設定およびデータが永続化されるようにしている.(参考: https://blog.nybeyond.com/tech/article/launching-keycloak-with-docker-compose/ )
解決方法
keycloakには,kcadm.sh
というファイルが用意されており,これに適切なパラメタを渡せば,コンソール上でレルムにアクセスし,設定を変更できる.
まず,レルムにログインするコマンドが以下のコマンドである.
./kcadm.sh config credentials --server <keycloakのURL> --realm master --user <adminのUser Name> --password <adminのパスワード>
そして,以下のコマンドを実行すると,SSLなしでアクセスできるようになる.
./kcadm.sh update realms/master -s sslRequired=NONE
(参考: https://www.mtioutput.com/entry/keycloak-admin-httpserror)
セキュリティ的には問題のある操作ですので,リスクがある場合はこの設定を避けてください
今回の場合は,個人の趣味の範囲なので無視しました.
docker compose up
のたびにこの設定をしてほしい.
次に,これをdocker compose up
で起動させるたびに自動でしてくれるようにしたいという需要が出てくる.上記で,Volumeをマッピングしてはいるが,実際の環境で初めて実行した際などに,この設定をdocker exec -it <ID> /bin/bash
を叩いて,手動で設定するのは面倒なので,一応設定しておく.
まず,quay.io/keycloak/keycloak
では,ENTRYPOINTに/opt/keycloak/bin/kc.shがすでに指定されている.これだと,commandで別のshellスクリプトを実行することができない.そのため,DockerfileでENTRYPOINTを独自のshファイルに上書きする.
FROM quay.io/keycloak/keycloak:latest
WORKDIR /opt/keycloak/bin
COPY ./setup.sh .
ENTRYPOINT ["/opt/keycloak/bin/setup.sh"]
WORKDIRに下記のシェルスクリプトをコピーし,それをENTRYPOINTとする.
#!/bin/bash
cd /opt/keycloak/bin
./kc.sh start-dev &
sleep 30
./kcadm.sh config credentials --server http://localhost:8080 --realm master --user admin --password admin
./kcadm.sh update realms/master -s sslRequired=NONE
while true
do
sleep 1000
done
このシェルスクリプトでは,元のENTRYPOINTで指定されていたshファイルを呼び出して,keycloakを起動するというコマンドをバックグラウンドで実行されるようにしている.
その後,30秒待機し,バックグラウンドでkeycloakが起動するのを待った後,上記に記したコマンドを実行している.ただし,userとpasswordはサンプルである.ここには,yamlで指定したKEYCLOAK_ADMINとKEYCLOAK_ADMIN_PASSWORDと同じものを入力すれば良い.
また,その後の無限ループは,このシェルスクリプトをENTRYPOINTとしているため,これが終了すると,コンテナの実行も終了してしまうのを避けるためである.
これで起動時から自動でSSLなしで接続できるようになる.
cloudflare tunnelでアクセスできるようにするには
あとは,cloudflaredでアクセスできるようにすれば良い.ただし,上記の設定をしたあとなので,public hostのserviceはhttpを指定するようにする.
cloudflareのDashboardでの設定は省略するが,Zero Trustからtuunelを設定できる.そこで,トークンを取得できるので,それを控えておく.
今回は,Dockerを使用しているので,cloudflaredもDockerのものを使っていく.
services:
clouflared:
image: cloudflare/cloudflared:latest
command: tunnel run
restart: always
environment:
- TUNNEL_TOKEN=${TUNNEL_TOKEN}
network_mode: host
yamlは上記のように設定すれば良い.ただし,network_mode
は他のdocker composeで動いているサービスも公開しようとしていたため,hostのネットワークを使用するように追加している.
EXPOSEやportsは設定しなくても,tunnelの通信はできるのでそのままで良いです
また,TUNNEL_TOKEN
は先ほど控えたトークンを.envに設定しておく.
これで,docker compose up
し,Dashboardで設定したドメインを使ってアクセスできるようになっていれば,設定完了である.
外からはhttpsでアクセスできるようになっていますが,keycloak自体はhttpでの通信を想定しているため,oauth2-proxyなどを用いる際は,keycloakのURLにはhttpを指定するようにしましょう
整合性が取れないため,oauth2-proxyでエラーになります
まとめ
以上の設定で,keycloakを証明書をサーバーにインストールすることなく,(見かけは)httpsで運用できるようになりました!