個人的に知識があいまいな認証回りの最小限の知見整理として、Traefik を用いて Keycloak で発行したアクセストークンが無いとアプリケーションにアクセスできないようにする最小限の設定を考えてみました。
ちなみに GPT-4o にフォローしてもらって大枠を整理し、動作に不具合が起きた部分を再度調べて…という流れで進めました。
【要注意】 この手順に従って構成した環境は本番利用するにはセキュリティ面で問題があるので、あくまで Keycloak や Traefik の設定ポイントの参考としてください。
検証した各ミドルウェアのバージョン
- minikube: v1.33.1
- Keycloak: 24.0.4
- Traefik: 2.11.2
- traefik-jwt-plugin: v0.7.1
前提条件
- Minikube がインストールされている
- kubectl がインストールされている
- Helm がインストールされている
ステップ 1: Minikube のセットアップ
まず、Minikube を起動します。
minikube start
ステップ 2: Keycloak のデプロイ
Keycloak を最低限の構成でデプロイするために、以下の Kubernetes マニフェストファイルを作成します。keycloak-deployment.yaml
という名前で保存してください。
apiVersion: apps/v1
kind: Deployment
metadata:
name: keycloak
labels:
app: keycloak
spec:
replicas: 1
selector:
matchLabels:
app: keycloak
template:
metadata:
labels:
app: keycloak
spec:
containers:
- name: keycloak
image: quay.io/keycloak/keycloak:24.0.4
args: ["start-dev"]
env:
- name: KEYCLOAK_ADMIN
value: admin
- name: KEYCLOAK_ADMIN_PASSWORD
value: admin
- name: KC_PROXY
value: "edge"
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: keycloak
spec:
ports:
- port: 8080
targetPort: 8080
selector:
app: keycloak
次に、Keycloak のデプロイメントとサービスを作成します。
kubectl apply -f keycloak-deployment.yaml
これで、管理者ユーザー名が admin、パスワードが admin で構成された Keycloak の環境が立ち上がりました。
Keycloak には CLUSTER-IP 経由で接続できました。CLUSTER-IP の取得には kubectl get svc keycloak
を使用します。
得られた CLUSTER-IP の値はメモして把握しておきます。
ステップ 3: Traefik のデプロイ
Helm を使用して traefik-jwt-plugin を使用できる Traefik v2.11 をインストールしていきます。
まずは下記で Helm のリポジトリの準備をします。
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
続いて以下の内容で traefik-values.yaml というファイルを作成します。
additionalArguments:
- "--log.level=DEBUG"
- "--api.insecure=true" # ダッシュボードを有効にする
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--providers.kubernetescrd"
- "--providers.kubernetesingress"
- "--experimental.plugins.jwt.moduleName=github.com/traefik-plugins/traefik-jwt-plugin"
- "--experimental.plugins.jwt.version=v0.7.1"
service:
type: LoadBalancer
rbac:
enabled: true
experimental:
plugins:
jwt:
moduleName: github.com/traefik-plugins/traefik-jwt-plugin
version: v0.7.1
次に、バージョン 27.0.2 のチャートを使用することで Traefik v2.11 をインストールします。
helm install traefik traefik/traefik --version 27.0.2 -f traefik-values.yaml
ステップ 4: Whoami アプリのデプロイ
アクセストークンが無いと使用できないアプリケーションのサンプルとして、Whoami アプリを利用します。
Whoami アプリをデプロイするために、以下の Kubernetes マニフェストファイルを作成します。whoami-deployment.yaml
という名前で保存してください。
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
labels:
app: whoami
spec:
replicas: 1
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: containous/whoami
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: whoami
spec:
ports:
- name: web
port: 80
targetPort: 80
selector:
app: whoami
次に、Whoami アプリのデプロイメントとサービスを作成します。
kubectl apply -f whoami-deployment.yaml
ステップ 5: Traefik の Ingress と Middleware の設定
Keycloak から発行されたトークンを検証するための Middleware と Whoami アプリへの Ingress を設定します。traefik-config.yaml
という名前で以下の内容を保存してください。
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: jwt
spec:
plugin:
jwt:
PayloadFields:
- exp
Keys:
- http://<KeyCloakのCLUSTER-IPの値>:8080/realms/myrealm/protocol/openid-connect/certs
Alg: RS256
Required: true
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: whoami
annotations:
traefik.ingress.kubernetes.io/router.middlewares: default-jwt@kubernetescrd
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: whoami
port:
number: 80
次に、この設定を適用します。
kubectl apply -f traefik-config.yaml
ステップ 6: Keycloak の設定
ブラウザで Keycloak の管理コンソールにアクセスします。URL は次の通りです。
http://<Keycloak の CLUSTER-IP の値>:8080
ここで、デフォルトの管理者アカウント(ユーザー名: admin
, パスワード: admin
)を使用してログインします。
レルムとクライアントの作成
※ Keycloak はデータの永続化をしていないので、ここからの作業は minikube を落とさないように進めましょう…
- 新しいレルムを作成します(
myrealm
)。 - myrealm にクライアントを追加します(
whoami-client
)。- General settings
- Client type:
OpenID Connect
- Client ID:
whoami-client
- Client type:
- Capability config
- Client authentication: On
- Login settings
- Valid redirect URIs:
http://127.0.0.1:8080
- Valid redirect URIs:
- General settings
ユーザーの作成
- myrealm にユーザーを追加します。
- ユーザー名:
testuser
- パスワード:
password
- ユーザー名:
クライアントシークレットの把握
- whoami-client クライアントの設定画面を開き、Credentials タブで、Client Secret の値をコピーします。
動作確認
動作確認の準備
Traefik のアプリへのアクセスは、ポートフォワーディングで動作しました(その想定で上記を設定しています)。
kubectl port-forward deployment/traefik 8080:80
アクセストークンの取得
認可コードフローで取得してみます。
まずはブラウザ(シークレットウィンドウを利用)で下記にアクセスします。
http://<Keycloak の CLUSTER-IP>:8080/realms/myrealm/protocol/openid-connect/auth?response_type=code&client_id=whoami-client&redirect_uri=http://127.0.0.1:8080&scope=openid
ログイン画面が出るので、myrealm に追加しておいた下記のユーザーでログインします。
- ユーザー名:
testuser
- パスワード:
password
ログインすると authorization header missing
とエラー画面が出ますが Traefik の設定によるもので正常です。
そのままブラウザは閉じずに・・・ブラウザの URL 部分に code=
で認証コードが出力されるので、これをコピーします。
コピーした認証コードを用いて、下記の curl を実行します。
curl -X POST "http://<KeycloakのCLUSTER-IP>:8080/realms/myrealm/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "code=<先ほど取得した認証コード>" \
-d "redirect_uri=http://127.0.0.1:8080" \
-d "grant_type=authorization_code" \
-d "client_id=whoami-client" \
-d "client_secret=<whoami-clientのクライアントシークレット>" | jq .
成功すると、Open ID Connect のトークンが得られ、access_token
の値がアクセストークンになります。
アプリへのアクセス
アクセストークンが無いとエラーになります。
$ curl http://127.0.0.1:8080
authorization header missing
有効期限内のアクセストークンがあれば whoami アプリの応答を返します。
$ curl -H "Authorization: Bearer <有効なアクセストークン>" http://127.0.0.1:8080
Hostname: whoami-b577bd888-2hbtd
IP: 127.0.0.1
IP: ::1
IP: 10.244.0.4
IP: fe80::(略)
RemoteAddr: 10.244.0.10:(ポート番号)
GET / HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: curl/7.47.0
Accept: */*
Accept-Encoding: gzip
Authorization: Bearer <アクセストークン>
X-Forwarded-For: 127.0.0.1
X-Forwarded-Host: 127.0.0.1:8080
X-Forwarded-Port: 8080
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-(略)
X-Real-Ip: 127.0.0.1
有効期限が切れたアクセストークンが渡されると期限切れのエラーになります。
$ curl -H "Authorization: Bearer <期限切れのアクセストークン>" http://127.0.0.1:8080
token is expired
終わりに
この記事では、Minikube 上に Keycloak と Traefik、Whoami アプリをデプロイし、Traefik で Whoami アプリへのアクセスに Keycloak 発行のアクセストークンを必須とする方法を示しました。
繰り返しになりますが、セキュリティのために本番環境では TLS の設定やその他のセキュリティ対策を講じることが必須です。