🔒

【Kubernetes】ingress-nginxとOAuth2-ProxyでIdP連携を行う

2024/03/29に公開

ingress-nginxにIdp連携機能を追加する。

OAuth2-Proxyを使ってingress-nginxとIdPを連携させる。今回IdPにはMicrosoft Entra IDを使用する。
※ ingress-nginxとcert-managerは既に導入済みの前提とする。

  • IdP連携用サイト: oauth.example.com
  • Webアプリサイト: app1.example.com, app2.example.com

OAuth2-Proxyの記事を検索すると、IdP連携したいWebアプリサイトを直接Entra IDにアプリ登録する記事が多く見つかる。ところが、その方式ではWebアプリサイトの数だけEntra IDへアプリ登録する必要があるため、サイトが増える度にEntra IDの作業が必要になり、運用コストが高くなってしまう。そこで今回はOAuth2-ProxyをIdP連携用サイトとしてIngressで独立公開して、それ1つだけをEntra IDにアプリ登録、IdP連携用サイトの認可が降りたらWebアプリサイトもまとめて認可するという運用コストが低めの実装法を調べて上手く実装できたので、自身の備忘と便利な方法があるよという紹介を兼ねてまとめておく。とはいえ、一からOAuth2とは?とかを説明していると記事の長さが大変なことになってしまうので、ある程度の基礎知識は持っている前提の記事になっているのはご了承いただきたい。

実際の通信の流れは、WebアプリサイトにアクセスするとIdP連携用サイトへリダイレクト、IdP連携用サイトから更にIdPに飛び、そこで正しく認可されたらIdP連携サイト、Webアプリサイトの順に再びリダイレクトされて戻ってくるような流れになる。Cookieを共有する関係上、IdP連携用サイトとWebアプリサイトは例のように同一サブドメイン上に存在する必要がある認識(認識に誤りがあったら教えてください)。

Microsoft Entra IDでアプリの登録を行う。

  • Microsoft Entra IDにアクセスする。
  • 新規登録ボタンを押す。
  • 画像のサンプル通りに入力する。
    • リダイレクトURLには、/oauth2/callbackというパスを付けること。
  • クライアントシークレットを作成する。
    • 最長でも有効期限2年までのようなので失効に注意。

Microsoft Entra IDのアプリ情報をKubernetesに登録する。

  • 下記のコマンドでSecretを登録する。
    • 一部伏せているが、概要証明書とシークレットページの当該文字列を入力。
kubectl create ns oauth2-proxy
kubectl create secret generic oauth2-proxy -n oauth2-proxy \
  --from-literal=client-id=5c7XXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX \
  --from-literal=client-secret=ttD****************** \
  --from-literal=cookie-secret=$(openssl rand -base64 32 | head -c 32 | base64) \
  --from-literal=azure-tenant=5dcXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

OAuth2-ProxyをHelmでインストールする。

values.yamlを用意する。

  • whitelist-domaincookie-domainは先頭に.を入れてサブドメインを許容させる。
  • oidc-issuer-urlはパス部に自分のテナントIDを埋め込む必要あり。
  • cert-manager.ioでLet's Encryptなど正規の証明書を取得する。
  • proxy-buffer-size8kにしないとEntra IDのヘッダが大きすぎて502エラーになる。
config:
  existingSecret: oauth2-proxy
  extraArgs:
    whitelist-domain: .example.com
    cookie-domain: .example.com
    provider: azure
    oidc-issuer-url: https://login.microsoftonline.com/5dcXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/v2.0

ingress:
  enabled: true
  path: /
  hosts:
  - oauth.example.com
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-issuer"
    nginx.ingress.kubernetes.io/proxy-buffer-size: "8k"
  tls:
  - secretName: oauth2-proxy-tls
    hosts:
    - oauth.example.com

helm installを行う。

helm repo add oauth2-proxy https://oauth2-proxy.github.io/manifests
helm install oauth2-proxy oauth2-proxy/oauth2-proxy -n oauth2-proxy --values values.yaml

Webアプリドメイン側のIngressにAnnotationを追加する。

app1.example.comやapp2.example.comなどのIngressのAnnotationに下記の2行を挿入する。
oauth.example.comの部分のみ実際のドメインに修正する。

annotations:
  nginx.ingress.kubernetes.io/auth-url: "https://oauth.example.com/oauth2/auth"
  nginx.ingress.kubernetes.io/auth-signin: "https://oauth.example.com/oauth2/start?rd=https%3A%2F%2F$host$escaped_request_uri"

これでWebアプリサイトにアクセスした際、Cookieを持っていないリクエストは、OAuth2-Proxyへリダイレクトされ、更にMicrosoft Entra IDのログインページへリダイレクトされる。そこで正しく認可を受けれた場合、OAuth2-Proxyへ再びリダイレクトで戻されて、更にリダイレクトで元のWebアプリサイトに戻されて、正しく閲覧ができるという流れでIdPと連携することができるようになる。

最後に。

最近は、Microsoft Entra IDなどIdPと連携して何やかんやが多いが、OAuth2-Proxyを使うと簡単に似たことが実現できる。仕事でも頻繁に言葉は出てくるものの、実際自分で手を動かして設定したのは今回が初めてだったので無事実装できてよかった。運用コスト低めのこだわり構成の方法を調べて手間取ったので実装までには合計で丸3〜4日くらいはかかったが、いざ出来てしまうと難易度的には大したことない印象。途中Authleiaなんかも試してたが結局1番簡単そうなOAuth2-Proxy+Entra IDを選定。Kubernetes上で動かすPrometheusなどユーザ認証・認可が付いてないものもざらにあるので、個別にIngressでBASIC認証などをかけている人もいると思うが、今回のようにIdP連携すればBASIC認証なんかよりはるかにセキュリティ的にも安心感があり、かつ簡単にID管理できるので是非おすすめしたい。何よりこれでVPN無しに直接インターネットにシステム管理用のURLを公開できて、なんちゃってゼロトラスト感も出せるというのがよい。

Discussion