Advent Calendar 2020 全部オレシリーズ 8日目です。もう完走は諦めました。(再掲)
Nginx Ingress Controller と oauth2-proxy を組み合わせて簡単に SSO を導入するためのメモです。複数のサービスがあって、Nginx Ingress Controller を使ってて、どれも同じ SSO 設定で良いという場合に便利です。nginx の auth_request 設定を Nginx Ingress Controller がいい感じにやってくれます。
Nginx Ingress Controller のインストール
ドキュメントを見てお好みの方法でインストールしてください。
私は helm でインストールしました。
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update helm install my-release ingress-nginx/ingress-nginx
oauth2-proxy のインストール
Helm Chart はあるにはあるけど、もうアーカイブ状態なんですよね。でも使えます。ここでも使っています。
Keycloak で SSO する場合の例です、次の YAML を customize.yaml
として保存して helm に -f
で渡します。Keycloak のセットアップや Client ID の発行は別途行ってください。Keycloak 以外にも沢山の Provier に対応しています。便利です。
config: clientID: example-client clientSecret: 71d0785e-3aeb-4e9c-8790-7dc34699afc1 cookieSecret: bmljaHVjb0xvaHJpZTVnYWhyYWU0ZXY0cmFoMGRvbzZvb0RhaGNoZWVzYXJlNGFT extraArgs: provider: keycloak login-url: https://keycloak.example.com/auth/realms/example/protocol/openid-connect/auth redeem-url: https://keycloak.example.com/auth/realms/example/protocol/openid-connect/token validate-url: https://keycloak.example.com/auth/realms/example/protocol/openid-connect/userinfo scope: profile ingress: enabled: true path: /oauth2 hosts: - alertmanager.example.com - kiali.example.com - prometheus.example.com annotations: kubernetes.io/ingress.class: nginx
helm repo add stable https://charts.helm.sh/stable helm repo update helm install stable/oauth2-proxy -f customize.yaml
これで次のような Ingress が作成されています。この後出てきますが、各サービスでもそれぞれの Ingress を定義しますが、/oauth2
についてはそれとは別に定義する必要があるというのがここでの重要なポイントです。私はこれになかなか気付けずに時間がかかりました。
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx meta.helm.sh/release-name: oauth2-proxy meta.helm.sh/release-namespace: ingress-nginx labels: app: oauth2-proxy app.kubernetes.io/managed-by: Helm chart: oauth2-proxy-3.2.3 heritage: Helm release: oauth2-proxy name: oauth2-proxy namespace: ingress-nginx spec: rules: - host: alertmanager.example.com http: paths: - backend: serviceName: oauth2-proxy servicePort: 80 path: /oauth2 pathType: ImplementationSpecific - host: kiali.example.com http: paths: - backend: serviceName: oauth2-proxy servicePort: 80 path: /oauth2 pathType: ImplementationSpecific - host: prometheus.example.com http: paths: - backend: serviceName: oauth2-proxy servicePort: 80 path: /oauth2 pathType: ImplementationSpecific
各サービスの Ingress 設定
oauth2-proxy の設定に alertmanager.example.com, kiali.example.com, prometheus.example.com というのを入れてみました。
どれでも同じですが、alertmanager.example.com について設定するとしましょう。おそらく kube-prometheus-stack という helm chart で入れるでしょうから直接 Ingress の manifest を書くことはないでしょうが。
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx meta.helm.sh/release-name: kube-prometheus-stack meta.helm.sh/release-namespace: prometheus nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri nginx.ingress.kubernetes.io/auth-url: http://oauth2-proxy.ingress-nginx.svc.cluster.local/oauth2/auth name: kube-prometheus-stack-alertmanager namespace: prometheus spec: rules: - host: alertmanager.example.com http: paths: - backend: serviceName: kube-prometheus-stack-alertmanager servicePort: 9093 path: / pathType: ImplementationSpecific
ここで大事なのは nginx.ingress.kubernetes.io/auth-signin
と nginx.ingress.kubernetes.io/auth-url
という annotation です。
auth_request は nginx が受けたリクエストのヘッダーを一部いじるものの、ほぼそのまま oauth2-proxy に proxy します。そして proxy 先で cookie の値やらドメイン名、URIなどからログイン済みかどうか、アクセスが許可されているのかどうかを判断して、レスポンスを返します。それを受け取った nginx が本来の upstream に proxy したり認証ページへリダイレクトしたりします。
で、nginx.ingress.kubernetes.io/auth-url
に指定するのが認証のための proxy 先です。nginx からアクセスできれば良いため Kubernetes クラスタ内通信で良いので .svc.cluster.local のドメインで指定しています。
一方、nginx.ingress.kubernetes.io/auth-signin
はログインされていない場合のリダイレクト先として使われるため $host
を使って受け付けた Host ヘッダー (VirtualHost) のドメインが入るようにしてあります。
/oauth2/
配下へのアクセスまで auth_request の対象としてしまうとループしてしまうため、そうならないようにするのが先に少し触れた 同じドメインだけど Ingress が2ヵ所で設定されている理由です。ついつい次のように書いてしまいそうになりますが、これではループしてしまうのです。
spec: rules: - host: alertmanager.example.com http: paths: - backend: serviceName: kube-prometheus-stack-alertmanager servicePort: 9093 path: / - backend: serviceName: oauth2-proxy servicePort: 80 path: /oauth2
同じドメインを複数 Ingress に分けて定義しても Nginx Ingress Controller は同一ドメインは同じ VirtualHost にまとめてくれます。
Nginx Ingress Controller が生成する nginx.conf を見ると何をやっているのかがわかります。
ちなみに、oauth2-proxy はその名の通り、それ単体でも認証付きの proxy として動作します。