ローカル環境でOAuth2 ProxyとKeycloakを使用した認証を実装する
はじめに
業務で OAuth2 Proxy を使用した認証をサイトに導入する機会がありました。この記事では、OAuth2 Proxy で学習した内容をまとめます。
成果物
https://github.com/kntks/blog-code/tree/main/2024/09/oauth2-proxy-basic
OAuth2 Proxyとは
OAuth2 Proxy は既存のアプリケーションに変更を加えることなく、認証を追加することができるリバースプロキシです。
複数の認証プロバイダーと連携することができ、認証プロバイダーとして、Google、GitHub、GitLab、Microsoft、Keycloak などをサポートしています。
セッションストレージは、Cookie、Redis をサポートしています。
環境構築
バージョン
node は2024年4月現在のLTSかつ最新である、v20.12.2を使用します。
バージョン | |
---|---|
Mac | Sonoma 14.5 |
Docker | 26.0.0 |
Docker Compose | v2.24.5 |
Keycloak | 25.0.4 |
Terraform | 1.9.5 |
Keycloak のセットアップ
Docker Compose で Keycloak を定義します。
services: keycloak: image: quay.io/keycloak/keycloak:25.0.4 container_name: keycloak ports: - target: 8080 published: 8080 protocol: tcp mode: host environment: - KEYCLOAK_ADMIN=admin - KEYCLOAK_ADMIN_PASSWORD=admin command: ["start-dev"] volumes: - ./keycloak:/opt/keycloak/data healthcheck: # https://gist.github.com/sarath-soman/5d9aec06953bbd0990c648605d4dba07?permalink_comment_id=5120472#gistcomment-5120472 test: ["CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/8080;echo -e 'GET /health/ready HTTP/1.1\r\nhost: http://localhost\r\nConnection: close\r\n\r\n' >&3;if [ $? -eq 0 ]; then echo 'Healthcheck Successful';exit 0;else echo 'Healthcheck Failed';exit 1;fi;"] interval: 10s timeout: 5s retries: 3
Keycloak を起動します。
docker compose up keycloak
Keycloakの設定
Terraformを実行する
Terraform を使用するために Keycloak に terraform クライアント を作成します。
Keycloak で terraform クライアントを作成したら、クライアントシークレットをコピーし、以下ように、client_id, client_secret, url を設定します。
client_id = "terraform"client_secret = "xxxxxxxxxxxxxxxxx"url = "http://localhost:8080"
terraform apply で Keycloak の設定を行います。
cd terraformterraform initterraform planterraform apply -auto-approve
クライアントの設定
今回、Terraform で作成したクライアントは、myapp という名前です。クライアントの設定は以下の通りです。
Valid redirect URIs
には、OAuth2 Proxy のリダイレクト先の URL を設定します。
Authentication flow
は、Standard flow
、Direct Grant
を選択します。
クライアントの設定に Advanced
タブがあります。ここにある Proof Key for Code Exchange Code Challenge Method
は、S256
を選択します。
ユーザーの設定
Username: myuser、Password: myuser でユーザーを作成しています。
nginxの設定
OAuth2 Proxy のドキュメントにある nginx の設定例を参考にし、Docker Compose で起動します。
nginx: container_name: nginx image: nginx:1.27 ports: - "80:80" volumes: - "./nginx.conf:/etc/nginx/conf.d/default.conf" depends_on: oauth2-proxy: condition: service_healthy
server { listen 80; server_name localhost;
location / { auth_request /oauth2/auth; error_page 401 =403 /oauth2/sign_in;
auth_request_set $user $upstream_http_x_auth_request_user; auth_request_set $email $upstream_http_x_auth_request_email; proxy_set_header X-User $user; proxy_set_header X-Email $email;
proxy_pass http://httpbin/; }
location /oauth2/ { proxy_pass http://oauth2-proxy:4180; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Scheme $scheme; proxy_set_header X-Auth-Request-Redirect $request_uri; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-Proto $scheme; }
location = /oauth2/auth { proxy_pass http://oauth2-proxy:4180; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Scheme $scheme; proxy_set_header X-Forwarded-Uri $request_uri; proxy_set_header Content-Length ""; proxy_pass_request_body off; }}
OAuth2 Proxyの設定
OAuth2 Proxy の設定方法は3つあります。
この記事では、基本設定はコマンドライン引数で行い、シークレットは環境変数で設定します。
まず、Docker Compose で OAuth2 Proxy を定義します。
oauth2-proxy: image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0-alpine container_name: oauth2-proxy command: - --http-address=0.0.0.0:4180 - --upstream=http://httpbin:80 - --scope=openid email profile - --oidc-extra-audience=account - --provider=keycloak-oidc - --client-id=myapp - --redirect-url=http://localhost:4180/oauth2/callback - --oidc-issuer-url=http://keycloak:8080/realms/myrealm - --email-domain=* - --code-challenge-method=S256 - --insecure-oidc-allow-unverified-email=true ports: - "4180:4180" - "443:443" environment: # productionで使用するときはシークレットを環境変数として設定する OAUTH2_PROXY_CLIENT_SECRET: "" OAUTH2_PROXY_COOKIE_SECRET: ""
# Keycloakが先に起動していないとエラーが発生するためdepends_onを設定 depends_on: keycloak: condition: service_healthy
healthcheck: test: ["CMD-SHELL", "wget --quiet --spider localhost:4180/ping"] interval: 10s timeout: 5s retries: 3
参考:
起動オプションについて
upstream
は、認証されたリクエストが転送される先の URL です。今回は、httpbin を使用します。
以下のようなエラーが出る場合、--insecure-oidc-allow-unverified-email=true
を追加します。
Error redeeming code during OAuth2 callback: email in id_token isn't verified
引用:https://github.com/oauth2-proxy/oauth2-proxy/issues/1712#issuecomment-1173659513
以下のようなエラーが出る場合、--oidc-extra-audience=account
を追加するか、Keycloak で Hardcoded audience を設定して aud
を myapp にすることで解決します。
Error creating session during OAuth2 callback: audience from claim aud with value [account] does not match with any of allowed audiences map[myapp:{}]`
参考:Keycloak OIDC - OAuth2 Proxy Documentation
環境変数について
OAuth2 Proxy は、すべてのコマンドライン引数は、環境変数として指定できます。環境変数には、OAUTH2_PROXY_
を先頭につけ、大文字にし、ハイフン -
をアンダースコア _
に置き換えます。
Keycloak で作成した myapp
のクライアントシークレットと、OAuth2 Proxy の Cookie シークレットは環境変数として設定します。(Cookie シークレットは、python スクリプトを実行し、生成しています。)
参考:Environment variables - OAuth2 Proxy
動作確認
Web ブラウザで http://localhost
にアクセスし、Keycloak のログイン画面が表示されることを確認します。
しかし、ブラウザは http://keycloak:8080/realms/myrealm/protocol/openid-connect/auth?xxxxxx
になり、サイトにアクセスできません。
これは、OAuth2 Proxy の起動オプションに --oidc-issuer-url=http://keycloak:8080/realms/myrealm
としているためです。
mac で開いた web ブラウザから http://keycloak にアクセスするためには、/etc/hosts
を編集する必要があります。
/etc/hostsに設定を追加する
$ cat /etc/hosts...
127.0.0.1 keycloak# End of section
再度アクセスする
もう一度、Web ブラウザで http://localhost
にアクセスしてみると Keycloak のログイン画面が表示されます。
Username: myuser、Password: myuser でログインすると、httpbin のページが表示されます。
まとめ
OAuth2 Proxy で Keycloak を使用した認証を実装する方法を学びました。
Keycloak と連携するときにいくつかエラーが出ますが、insecure-oidc-allow-unverified-email、oidc-audience-claim、などの設定を追加することで解決できます。もし、エラーが出た場合は、ドキュメントを参照して設定を追加してみてください。