🔐

TraefikとKeycloakを連携してリクエスト認証を実現する

2025/02/18に公開

概要

Kubernetesクラスタ上でTraefikとKeycloakを連携させてリクエスト認証を行う手順を記載します。

Traefikとは

Traefikは、Go製のクラウドネイティブなリバースプロキシ、およびロードバランサです。ロードバランシング、メトリクス、HTTPS/TLSなど様々な機能を提供します。

https://doc.traefik.io/traefik/

Keycloakとは

Keycloakは、アイデンティティ管理およびアクセス管理を行うアプリケーションです。シングルサインオン(SSO)、ユーザーフェデレーションなどの機能を提供し、認証/認可を実現します。

https://www.keycloak.org/

構成図

以下のような構成になります。Traefikに届いたリクエストに対し、認証プロキシがKeycloakのログイン画面にリダイレクトします。
ログインに成功した場合、リクエスト先のレスポンスが表示されます。

structure

手順

Traefik,Keycloakはすでにデプロイされているものとします。

認証をかけるリソース(API)をデプロイする

リクエスト認証をかける対象のAPIをデプロイします。
今回はnginxをたてました。

kubectl apply -f nginx.yaml
nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx 
  namespace: test
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    app: nginx
  namespace: test
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

KeyCloakで、realm,client,userを作成する

認証に使用するrealm及びclientとuserを作成します。
adminとしてログインし、Create realmページでrealmを作成します。
create realm

Usersにて、Create new userをクリックします。
create user 1

Usernameを入力し、Createをクリックします。
create user 2

作成したユーザのページにて、Set passwordをクリックします。
create user 4

Passwordを入力し、Saveします。Temporaryはオフにしました。
create user 5

次はClientを作成します。
ClientsページにてCreate clientをクリックします。
create client 1
Client IDを入力し、Nextをクリックします。
create client 2
Clinet authenticationをOnにし、Nextをクリックします。
create client 3

認証後にリダイレクトされるurlを入力し、Saveをクリックします。
valid redirect

認証プロキシをデプロイする

Traefikに届いたリクエストをKeycloakに連携する認証プロキシをデプロイします。
今回は https://github.com/thomseddon/traefik-forward-auth を用います。

kubectl apply -f traefik-forward-auth.yaml
traefik-forward-auth.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: traefik-forward-auth
  labels:
    app: traefik-forward-auth
  namespace: test
spec:
  replicas: 3
  selector:
    matchLabels:
      app: traefik-forward-auth
  template:
    metadata:
      labels:
        app: traefik-forward-auth
    spec:
      containers:
        - name: traefik-forward-auth
          image: thomseddon/traefik-forward-auth
          livenessProbe:
            failureThreshold: 3
            tcpSocket:
              port: 4181
            initialDelaySeconds: 10
            periodSeconds: 10
          resources:
            limits:
              cpu: '0.1'
              memory: '10Mi'
          ports:
            - name: http
              containerPort: 4181
          env:
            - name: DEFAULT_PROVIDER
              value: oidc
            - name: PROVIDERS_OIDC_CLIENT_SECRET
              value: xxxxxx
            - name: PROVIDERS_OIDC_ISSUER_URL
              value: http://<KEYCLOAK_URL>/realms/myrealm
            - name: PROVIDERS_OIDC_CLIENT_ID
              value: myclient
            - name: SECRET
              value: xxxxxx
            - name: INSECURE_COOKIE
              value: "true"
---
apiVersion: v1
kind: Service
metadata:
  name: traefik-forward-auth
  namespace: test
spec:
  type: ClusterIP
  selector:
    app: traefik-forward-auth
  ports:
    - name: http
      port: 4181
      targetPort: 4181
      protocol: TCP

環境変数にて設定しているパラメータは以下になります。

パラメータ名 説明
DEFAULT_PROVIDER 認証プロバイダーの種類を指定します。ここではOIDCを使用しています。
PROVIDERS_OIDC_CLIENT_SECRET Keycloakのクライアントシークレットを指定します。(今回はvalueにべた書きしていますがsecretで指定する方がbetterです。)
PROVIDERS_OIDC_ISSUER_URL 先ほど作成したKeycloakの発行者URLを指定します。
PROVIDERS_OIDC_CLIENT_ID KeycloakのクライアントIDを指定します。
SECRET 認証プロキシがcookieの生成/検証に用いるシークレットの値を指定します。
INSECURE_COOKIE クッキーのSecure設定を指定します。今回はhttpでやり取りしたためtrueに設定しました。

client secretの値はclient detailsから確認できます。
client detail

ingressを作成する

apiおよび認証プロキシを公開するためのingressを作成します。この時、forwardAuth middlewareを設定することで、apiへのリクエスト時にkeycloakによる認証をはさむことができます。

kubectl apply -f ingress.yaml
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-api
  namespace: test
  annotations:
    ingress.kubernetes.io/ssl-redirect: "false"
    traefik.ingress.kubernetes.io/router.middlewares: "test-api-auth@kubernetescrd,test-strip-prefix-api@kubernetescrd"
spec:
  ingressClassName: traefik
  rules:
  - http:
      paths:
      - path: /api/
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: traefik-forward-auth
            port:
              number: 4181
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: strip-prefix-api
  namespace: test
spec:
  stripPrefix:
    forceSlash: false
    prefixes:
      - /api/
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: api-auth
  namespace: test
spec:
  forwardAuth:
    address: http://traefik-forward-auth.test.svc.cluster.local:4181
    trustForwardHeader: true
    authResponseHeaders:
      - X-Forwarded-User

以上により、ブラウザからリソースへアクセスすると、keycloakのログイン画面にリダイレクトし、ログインに成功するとリソースのレスポンスが返却されるようになります。

Discussion