ネイティブな認証を持たないサービスに認証を設けるため自宅k8sにIdPの一つであるAuthentikを導入した話


きっかけ

この記事MonitoRSSという、DiscordへRSS通知を行うbotを導入した。

しかし、MonitoRSSをそのままInternet上へ公開してしまうと誰でも管理コンソールに誰でもアクセスできてしまうため、制限をかけたいと思った。

調べたところ、Authentikならサービス自体がSSO連携機能を持たなくてもForward Proxyを使うことで簡単にログイン画面を設けることが出来ると知ったので、Authentikを導入した。

この手のIdPで一番に候補が上がるのはKeycloakだと思うが、こちらは認証のリクエストを中継、遮断する仕組みを持たないので、同じことを実現するためにoauth2-proxyなどと連携することが必須

Authentik導入

とりあえずHelm経由でdeploy

PVC設定等は適宜読み替えて

values.yaml
global:
  image:
    repository: ghcr.io/goauthentik/server
    tag: "2026.2.1"
    pullPolicy: Always

authentik:
  secret_key: "xxx" # openssl rand -base64 64
  # 初回起動時のデフォルトユーザーの設定
  bootstrap_password: "hoge"
  bootstrap_email: "hoge@hoge.com"
  bootstrap_token: "xxx"
  error_reporting:
      enabled: false
  postgresql:
      password: "xxx"

  email:
      host: "fuga@fuga.com"
      port: 587
      username: "no-reply@fuga.com"
      password: "xxx"
      use_tls: true
      use_ssl: false
      timeout: 30
      from: "no-reply <no-reply@fuga.com>"

  # 自身のK8sクラスターを操作するための権限設定
  serviceAccount:
    create: true
    name: authentik

  # RBACを有効にしてWorkerに権限を与える
  rbac:
    create: true

  # Outpostが自動でK8sにデプロイされるようにするデフォルト設定
  outposts:
    defaults:
      authentik_host: "http://authentik-server.authentik.svc.cluster.local"
      authentik_host_browser: "https://authentik.4nm1tsu.com"
  env:
    - name: AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS
      value: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
    - name: AUTHENTIK_COOKIE_DOMAIN
      value: ".4nm1tsu.com"
    - name: AUTHENTIK_COOKIE_SAMESITE
      value: "Lax"
    - name: AUTHENTIK_COOKIE_SECURE
      value: "true"
    - name: AUTHENTIK_AUTHENTICATION__GLOBAL__TRUSTED_PROXY_CIDRS # 本来は絞ったほうが良い
      value: "0.0.0.0/0,::/0"
    - name: SSL_CERT_FILE
      value: /etc/ssl/certs/ca-certificates.crt

  volumes:
      - name: custom-ca
        configMap:
            name: my-custom-cert
  volumeMounts:
      - name: custom-ca
        mountPath: /etc/ssl/certs/ca-certificates.crt
        subPath: ca-certificates.crt
        readOnly: true

server:
  ingress:
    enabled: false
  extraVolumes:
    - name: shm
      emptyDir:
        medium: Memory
  extraVolumeMounts:
    - name: shm
      mountPath: /dev/shm

postgresql:
  enabled: true
  volumePermissions:
    enabled: true
  primary:
    persistence:
      enabled: true
      existingClaim: pvc-authentik-postgres # 自環境ではpostgres用にNFSを利用
    podSecurityContext:
      fsGroup: 1001
    containerSecurityContext:
      runAsUser: 1001
  auth:
    username: authentik
    database: authentik
    password: "xxx"

redis:
  enabled: false

確認(初回起動時はハイライトした3つのPodのみが立ち上がっているはず)

$ kubectl get pods -n authentik
NAME                                     READY   STATUS    RESTARTS      AGE
ak-outpost-alertmanager-6c4cf5d7-542gb   1/1     Running   2 (5d ago)    15d
ak-outpost-monitorss-845b6dc86-wbkzx     1/1     Running   1 (12d ago)   15d
ak-outpost-prometheus-c56bb6784-crdnf    1/1     Running   2 (12d ago)   15d
ak-outpost-radicale-79586585d4-m7r6z     1/1     Running   0             7d
authentik-postgresql-0                   1/1     Running   2 (3h ago)    15d
authentik-server-76dc98c748-sp7qc        1/1     Running   0             5m49s
authentik-worker-77f5fcc9c9-4lq5m        1/1     Running   0             5m49s

Ingress設定

helmでのinstall時にserver.ingress.enabled=falseにした場合はIngressは個別に設定

ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-auth
  namespace: authentik
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-issuer
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - authentik.4nm1tsu.com
      secretName: letsencrypt-cert-auth
  rules:
    - host: authentik.4nm1tsu.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: authentik-server
                port:
                  number: 80

初回アクセス

https://{設定したドメイン}/if/flow/initial-setup/にアクセスすると初回ログインができる。(スクショ撮り忘れた)

デフォルトadminでログインすると、ユーザ画面にアクセスできる。右上の管理者インターフェースから諸々の設定を行うことが出来る。 すでに色々なアプリを統合してしまった後なので画面がごちゃごちゃしているが、初回アクセス時は何もない

なぜかiosだけauthentikのログイン画面がうまく動かない問題

iOSでauthentikに遷移すると、一向にログイン画面が出てこない問題が発生した。

原因はiOSバージョンが古い(18.3.1)ことだった。

最新のiOSにアップデートすることで解決。

実際にSSO設定を行う

当初の目的だったMonitoRSSにSSOログインを導入してみたいと思う。

Ingress設定

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: monitorss-ingress
  namespace: monitorss
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: letsencrypt-issuer

    # Authentikのoutpostを指定
    nginx.ingress.kubernetes.io/auth-url: "http://ak-outpost-monitorss.authentik.svc.cluster.local:9000/outpost.goauthentik.io/auth/nginx"
    # 未認証だった場合リダイレクトするログイン画面のURL
    nginx.ingress.kubernetes.io/auth-signin: "https://monitorss.4nm1tsu.com/outpost.goauthentik.io/start?rd=$scheme://$host$request_uri"
    # 認証成功後、Authentikから返されたユーザー情報をHTTPヘッダーとしてアプリケーションに引き渡す設定
    nginx.ingress.kubernetes.io/auth-response-headers: "Set-Cookie,X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid"

    # 元のURI情報をヘッダーに含める
    nginx.ingress.kubernetes.io/proxy-add-original-uri-header: "true"

spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - monitorss.4nm1tsu.com
      secretName: monitorss-tls
  rules:
    - host: monitorss.4nm1tsu.com
      http:
        paths:
          # --- アプリ本体 ---
          - path: /
            pathType: Prefix
            backend:
              service:
                name: monitorss-monolith
                port:
                  number: 8000
          # --- 認証システム専用パス ---
          - path: /outpost.goauthentik.io
            pathType: Prefix
            backend:
              service:
                name: ak-bridge-service
                port:
                  number: 9000
---
apiVersion: v1
kind: Service
metadata:
  name: ak-bridge-service
  namespace: monitorss
spec:
  type: ExternalName
  externalName: ak-outpost-monitorss.authentik.svc.cluster.local

設定は上記の通り。

Ingressは同一の名前空間のサービスしかバックエンドに指定できないので、authentik namespaceのoutpostを指定するためのエイリアスとして、ak-bridge-serviceを作成している。

Authentik側設定

Authentikの管理者インターフェースから、以下の3つをそれぞれ作成する。

  • Provider: 認証の方法(Forward Auth/OIDC等)を定義するもの。
  • Application: MonitoRSSというアプリをauthentikに認識させるもの。
  • Outpost: 実際にIngressの門番として働くPod。

Provider

「認可フロー」はdefault-provider-authorization-implicit-consentを選択。データ共有に関するユーザーの同意が必要な場合、explicitの方を選択する

今回のケースではフォワード認証(単一アプリ)を選択。

「外部ホスト」はhttps://monitorss.4nm1tsu.comと記載。これはForward Authを行う対象アプリのURL。

Application

ここでは表示に利用するアプリ名を指定。(slugは他のサービスから指定する時の名前になるので注意)

「プロバイダー」の欄には先ほど作成したプロバイダーを指定する。

アプリアイコンの指定とかもここで出来る。

Outpost

Forward Authの場合、「タイプ」はプロキシを選択。

「統合」は、outpostのPodをどこにデプロイするかを選択する。

「アプリ」ははじめに作成したMonitoRSS用のプロバイダーを選択。

MonitoRSS実際にアクセス

https://monitorss.4nm1tsu.comにアクセスすると、以前まではいきなりアプリのコンソール画面が表示されていたが、 Authentik設定後は、以下のようなログイン画面が表示されるようになった。

デフォルトだと全ユーザアクセス可能だが、Authentik上でポリシーやグループを設定することで、特定のユーザのみアプリにアクセス可能にすることができる。

追加設定

パスワードを忘れた際のパスワードリセットフローを設定する。

前提として、メール送信設定を有効化しておく必要がある。

Authentik公式ドキュメントから、サンプルのリカバリーフローのファイルをダウンロードして、 Authentik管理コンソールの"フロー及びステージ" > “フロー"からインポートする。

Authentik管理コンソールの"システム”>“ブランド"から、新規ブランドを作成し、“デフォルトフロー” > “リカバリーフロー"に先程インポートしたdefault-recovery-flowを設定すると、

Authentikログイン画面のパスワードを忘れた場合、というリンクがアクティベートされる。

おわりに

Authentikを利用することで、ログイン画面を持たないアプリに簡単にログイン画面を設けることができた。