はじめに
認証マイクロサービスというのを実際に動かしてみて、その雰囲気を試してみました。
以前にもbuzzfeed/ssoをつかった内容の記事を書きましたが、今回は別のツールを使ってやってみます。
※この記事はZ Labの業務の一環として作成しました
oauth2-proxyとは
oauth2-proxyは汎用的な認証プロキシです。OAuth2に準拠した外部の認可システムを利用して認証を行い、認証が成功した場合にのみバックエンドに通信を許すという動作をします。
以前はbitlyが開発していたのですが、メンテされなくなり、その後紆余曲折あってoauth2-proxyという独立したorgのもとで現在も開発が進められているようです。
dexとは
さまざまな認証の仕組みとやりとりをして、OpenID Connectとして扱うことができる認証サービスです。
こちらも元々CoreOSが開発していましたが、今はdexidpという独立したorgで開発が行われています。
minikubeでクラスタの準備を行う
この実験はMac OS上で実施しているのですが、minikubeでクラスタを作る際には、もろもろもの事情からhyperkitを使用するモードを利用します。(minikube tunnel
を使った際にClusterIPがLBのIPと同じものになる動作が今回は必要なのです)
$ minikube start --driver=hyperkit
ingress addonを利用します
$ minikube addons enable ingress
ターミナルをもう一つ開いてminikube tunnelを実行しておきます
$ minikube tunnel
oauth2-proxyのインストール
インストールはhelmを使って実施します。
$ helm repo add oauth2-proxy https://oauth2-proxy.github.io/manifests
$ helm install oauth2-proxy oauth2-proxy/oauth2-proxy
この後、設定値を修正していきます。
そのために、現在の設定値を一度yamlに書き出します。
$ helm show values oauth2-proxy/oauth2-proxy > values.yaml
今後修正を反映するためにはvalues.yamlを編集したのちに以下を実行します。
$ helm upgrade oauth2-proxy oauth2-proxy/oauth2-proxy -f values.yaml
http-dumpのインストール
バックエンドとしてはなんでもよかったのですが、リクエストの中身がみられるhttp-dumpを利用します。
$ kubectl create deployment http-dump --image daime/http-dump
$ kubectl expose deploy http-dump --port 8080 --type=LoadBalancer
oauth2-proxy を使ってhttp-dumpに認証をかける
認証プロバイダとしてはGitHubを使います。
GitHubのWebUIでApplicationを作成し、ClientIDやClientSecretを取得しておきます。
(この記事などを参考にしてみると良いです https://yurakawa.hatenablog.jp/entry/2018/06/04/002033 )
Authorization Callback URLとしてはhttps://[minikubeのIP]/oauth2/callback
を指定します。
これはIngress経由でoauth2-proxyにアクセスするためのURLです。
oauth2_proxyの設定としては
- clientID, clientSecret
- upstreamを
http://http-dump:8080
- これはKubernetesのクラスタ内DNSを利用したURLです
- redirect-urlをGitHubに登録したものと同じ
https://[minikubeのIP]/oauth2/callback
- ingressを有効にしhostを
""
に設定(Helm Chartの都合上この設定をしないとおかしなIngressリソースが作成されました)
diff(環境固有の値があるので参考程度のものです)
11c11
< clientID: "XXXXXXX"
---
> clientID: "ないしょ"
13c13
< clientSecret: "XXXXXXXX"
---
> clientSecret: "ないしょ"
32c32
< upstreams = [ "file:///dev/null" ]
---
> upstreams = [ "http://http-dump:8080" ]
65c65,67
< extraArgs: {}
---
> extraArgs:
> provider: github
> redirect-url: https://192.168.64.9/oauth2/callback
117c119
< enabled: false
---
> enabled: true
123c125,126
< # hosts:
---
> hosts:
> - ""
ここまで設定すると、ブラウザからhttps://[minikubeのip]/
にアクセスすることで、GitHubの認証を許可した場合のみhttp-dumpにアクセスできるような構成が出来上がりました。
(今回はhttp-dumpにtype=LoadBalancerも登録しているので、そちらからアクセスすれば認証を迂回して直接アクセスすることもできます)
http-dumpではリクエストヘッダなども表示されます。X-Forwared-EmailなどをみるとGitHubの認証で用いられたメールアドレスなども知ることができます。
現段階での動作を図にするとこんな感じです。
oauth2-proxyをプロキシとして使うのをやめて Nginxのauth_requestを使う
Nginxには認証されていない場合は認証サービスにアクセスするというauth_requestの機能が備わっており、 Nginx Ingress Controllerでは、Ingressリソースの Annotationに少し設定を書くことで、この機能を利用することができます。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: http-dump
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
spec:
rules:
- http:
paths:
- path: /test
pathType: Prefix
backend:
service:
name: http-dump
port:
number: 8080
このようにIngressリソースに少し設定を加えることで、認証していないとアクセスができない設定ができます。
この設定を反映した上で、ブラウザからhttps://[minikubeのip]/test
にアクセスすると、認証を経由した上でhttp-dumpにアクセスできました。
ここまでの動作を図で書くとこんな感じです。
dexのインストール
ここまでで、oauth2_proxyを使った認証プロキシの動作を確認できました。
次はさらに認証にdexを使うようにしてみましょう。
dexのリポジトリのexampleにあるマニフェストを少し編集してminikubeで作ったKubernetesクラスタにデプロイします。
変更点は以下です
- replicaを3から1に
- issuerを
https://[dexのExternal IP]:5556
- (ここで指定するIPがクラスタ内でもラップトップからも同じであることが求められます、minikubeをhyperkitで動かしているのはこのためです)
- redirectURIを
https://[dexのExternal IP]:5556/callback
にする - staticClientsに以下を追加
+ - id: oauth2-proxy
+ redirectURIs:
+ - 'https://[minikubeのIP == Ingress Controller == oauth2_proxy]/oauth2/callback'
+ name: 'oauth2-proxy'
+ secret: proxy
- Service typeをLoadBalancerに変更
diff(環境固有の値があるので参考程度のものです)
@@ -12,7 +12,7 @@ metadata:
name: dex
namespace: dex
spec:
- replicas: 3
+ replicas: 1
selector:
matchLabels:
app: dex
@@ -72,7 +72,7 @@ metadata:
namespace: dex
data:
config.yaml: |
- issuer: https://dex.example.com:32000
+ issuer: https://10.97.15.76:5556
storage:
type: kubernetes
config:
@@ -88,12 +88,18 @@ data:
config:
clientID: $GITHUB_CLIENT_ID
clientSecret: $GITHUB_CLIENT_SECRET
- redirectURI: https://dex.example.com:32000/callback
+ redirectURI: https://10.97.15.76:5556/callback
org: kubernetes
oauth2:
skipApprovalScreen: true
staticClients:
+ - id: oauth2-proxy
+ redirectURIs:
+ - 'https://192.168.64.9/oauth2/callback'
+ name: 'oauth2-proxy'
+ secret: proxy
+
- id: example-app
redirectURIs:
- 'http://127.0.0.1:5555/callback'
@@ -114,7 +120,7 @@ metadata:
name: dex
namespace: dex
spec:
- type: NodePort
+ type: LoadBalancer
ports:
- name: dex
port: 5556
dexの起動に必要なsecretなどを用意します。
$ cd dex/examples/k8s
$ ./gencert.sh
$ kubectl -n dex create secret tls dex.example.com.tls --cert=ssl/cert.pem --key=ssl/key.pem
$ kubectl -n dex create secret \
generic github-client \
--from-literal=client-id=$GITHUB_CLIENT_ID \
--from-literal=client-secret=$GITHUB_CLIENT_SECRET
dexとoauth2-proxyの連携
oauth2-proxyの設定で認証プロバイダとしてdexを利用するようにします。
- provider: oidc
- client-id: oauth2-proxy # staticClientsに設定したもの
- client-secret: proxy
- redirect-url: https://[minikubeのIP]/oauth2/callback # dexを使わない時と同じ
- set-authorization-header: true # せっかくOIDCなので設定する
- oidc-issuer-url: https://[dexのExternal IP]:5556
- ssl-insecure-skip-verify: true # dexのTLS証明書が検証できないのでskip
diff(環境固有の値があるので参考程度のものです)
11c11
< clientID: "XXXXXXX"
---
> clientID: "oauth2-proxy"
13c13
< clientSecret: "XXXXXXXX"
---
> clientSecret: "proxy"
32c32
< upstreams = [ "file:///dev/null" ]
---
> upstreams = [ "http://http-dump:8080" ]
65c65,70
< extraArgs: {}
---
> extraArgs:
> provider: oidc
> redirect-url: https://192.168.64.9/oauth2/callback
> oidc-issuer-url: https://10.97.15.76:5556
> set-authorization-header: true
> ssl-insecure-skip-verify: true
117c122
< enabled: false
---
> enabled: true
123c128,129
< # hosts:
---
> hosts:
> - ""
ここまで設定すると、認証のためにdexにアクセスし、さらにそこからGitHubにアクセスし、認証が完了したらdex、そしてoauth2_proxyまで戻ってきて、最終的にhttp-dumpにアクセスできるようになりました。
ingressに追加でnginx.ingress.kubernetes.io/auth-response-headers: Authorization
というアノテーションを追加することでバックエンドにAuthorizationヘッダーを送ることも可能です。
この状態を図で表すとこのようになります。
まとめ
oauth2-proxyとdexを使って、Kubernetes上で簡単に認証つきのWebサービスを作成する方法を検証してみました。
類似ソフトウェア
社内でこの内容を紹介した際に、いくつか類似のソフトウェアを教わったのでここに書いておきます。