はじめに
IDをLDAPで統合管理しているため、ユーザー認証はLDAPを利用して組織内のパスワードを統合したいと考えています。
とはいえ生のLDAPでBASIC認証をかける時代でもないので、OpenID Connectのサーバーを構築することにしました。
とりあえず、kubernetesを使っていることもあるので、余っているAPU2を使って https://github.com/dexidp/dex を動かしてみることにしました。
【2021/04/13 追記】dexの最新コードでは、go getではなく、git clone & make を利用する方法が公式ガイドに記述されていたので、その記法に合わせました。そのためDockerfileの内容は大幅に変更されています。
環境
テスト環境
- Ubuntu 20.04.2 (LTS) 64bit
- IP: 192.168.100.10
- go 1.17.5
- GOPATH="${HOME}/go"
Dockerコンテナ
- Alpineイメージをベースに利用 (3.13系列)
- Multistage Buildによってイメージサイズを圧縮する
公式ガイドと違うところ
公式ガイドは同一マシンで、サーバーとWebブラウザの両方を動作させることを前提としていますが、今回はDexサーバーは別マシンで稼動させます。
このため127.0.0.1で動く事を前提にしているサンプルではうまく動かないので、オプションの設定など違いをメモしていきます。
動作の概要
サンプルのクライアントプログラム(bin/example-app)には、次のようなURLを伝える必要があります。
- example-appが待ち受けるネットワークアドレス・ポート
- 認証を依頼するdexサーバーのURL(アドレス・ポート・パス)
- dexサーバーから認証後にRedirectしてもらう待ち受けURL(同上)
Building the dex binary
手順は公式サイトのGetting startedと同じです。
$ git clone https://github.com/dexidp/dex.git
$ cd dex
$ make build
$ make examples
$ ls bin/
無事に終ると、bin/dex や bin/example-app バイナリが配置されているはずです。
ここから先のConfiguration & Running Clientの方法は、公式ガイドのLDAPの項目に従っていきます。
Configuration
ドキュメントでは、examplesディレクトリの設定ファイルを指定しています。./bin/dex serve examples/config-ldap.yaml
ここでは元のファイルをコピーして編集することにします。
$ cp examples/ldap/config-ldap.yaml config-ldap.yaml
$ vi config-ldap.yaml
Running dex server
サーバー側を動かす前に、先ほどコピーして編集したconfig-ldap.yamlについて説明します。
変更部分のdiffは次のようになっています。
--- examples/config-ldap.yaml 2019-03-04 09:45:20.967690885 +0900
+++ config-ldap.yaml 2019-03-04 09:58:16.352010857 +0900
@@ -1,4 +1,4 @@
-issuer: http://127.0.0.1:5556/dex
+issuer: http://192.168.100.10:5556/dex
storage:
type: sqlite3
config:
@@ -11,36 +11,36 @@
name: OpenLDAP
id: ldap
config:
- host: localhost:10389
+ host: ldap.example.com:389
# No TLS for this setup.
insecureNoSSL: true
# This would normally be a read-only user.
- bindDN: cn=admin,dc=example,dc=org
- bindPW: admin
+ #bindDN: cn=admin,dc=example,dc=org
+ #bindPW: admin
- usernamePrompt: Email Address
+ usernamePrompt: LDAP-ID
userSearch:
@@ -48,6 +48,6 @@
staticClients:
- id: example-app
redirectURIs:
- - 'http://127.0.0.1:5555/callback'
+ - 'http://192.168.100.10:5555/callback'
name: 'Example App'
secret: ZXhhbXBsZS1hcHAtc2VjcmV0
変更箇所の概要
issuer
とredirectURIs
については、IPアドレスを変更しています。
host
の項目は別に準備しているLDAPサーバーについての情報に書き換えています。
これはTLS(ldaps,636)を使わず、接続にbindDNも必要としないので、insecureNoSSL
はtrueのまま、bindDNとbindPWはコメントアウトしています。
TLSを利用する場合には、host:行で636ポートを指定するなどし、insecureNoSSLはnoに設定します。
userSearchやgroupSearchのセクションは適宜修正しています。
この後、編集したファイルを指定してサービスを開始しています。
$ bin/dex serve config-ldap.yaml
Running a client
ドキュメントでは./bin/example-app
を実行しているだけ、最初に説明した3つの動きをさせるためにオプションを指定していきます。
$ ./bin/example-app --listen http://192.168.100.10:5555 \
--issuer http://192.168.100.10:5556/dex \
--redirect-uri http://192.168.100.10:5555/callback
- example-appが利用するアドレス・ポート番号
--listen http://192.168.100.10:5555
- 認証を依頼するdexサーバーのURL(アドレス・ポート・パス)
--issuer http://192.168.100.10:5556/dex
- 認証後にRedirectしてもらうため、dexサーバーに伝えるclient側の待ち受けURL(同上)
--redirect-uri http://192.168.100.10:5555/callback
同一ホストでdexサーバーとクライアントを利用している場合、issuerにlocalhostを指定することはできますが、Dockerコンテナの場合には、localhostと指定してもホストには接続しないため動かない点に注意してください。
動作について
Getting startedにあるように、bin/example-appコマンドに必要な引数を指定して起動します。
Webブラウザからhttp://192.168.100.10:5555/ にアクセスして表示された画面の入力欄にはまず何も入れずに"Login"ボタンを押します。
画面がhttp://192.168.100.10:5556/dex にリダイレクトされ、LDAPのID, Passwordを入れて認証されると、bin/example-appコマンドが準備している http://192.168.100.10:5555/callback に戻されます。
最初の画面にIDとか入れるのかなと思いましたが、何も入れなくて問題なく動きました。
これがそのまま他のアプリにも適用できるのかは、これから確認していく予定です。
example-appに表示される結果
認証が無事に終わり、http://192.168.100.10:5555/callback など指定したURLに戻されると次のような結果が画面に出力されます。
ID Token:
eyJhbGciOiJSUzI1NiIsImtpZCI6IjkxOWUzNTFmMGZhMTZhYjA4ZTEzNWQ3ZjYxNGE3ZTM4MTI1NDg3OWIifQ.eyJpc3MiOiJodHRwczovL29wbTAwaC51LWFpenUuYWMuanAvZGV4Iiwic3ViIjoiQ2pWMWFXUTllV0Z6ZFMxaFltVXNiM1U5VUdWdmNHeGxMRzkxUFZCeWIzaDVMR1JqUFhVdFlXbDZkU3hrWXoxaFl5eGtZejFxY0JJRWJHUmhjQSIsImF1ZCI6ImV4YW1wbGUtYXBwIiwiZXhwIjoxNTU4NjczNTgzLCJpYXQiOjE1NTg1ODcxODMsImF0X2hhc2giOiI1dllGMkxZOUZGMkdZckVpTnBOeVFnIiwiZW1haWwiOiJ5YXN1LWFiZUB1LWFpjnUuYWMuanAiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6Illhc3VoaXJvIEFiZSJ9.pRPgtewj7y42EWlVcv9OhyJmmO5969x2lb6IHRJTDFHvgVhCDFNO9_jZC2hLcHeLPId5BXeZtcNY-GCDxS89IxsjSKYG8cRdYOIHvBN-jB8DAtJYQxr225pU1SUybOdh9-0u3DeC0iPnUEwoLvyMStl-D3TuwMgsjgTWUWrfUthxnoricltixaITHjl0EpQmzxdZHmNuTRlTwQFh_zgw1NO4u6E-s7IAHvTnNeeDsx2yTR4RSwabc-GJ4HZ5OL_s6kAlloKTKAL6szTt-aMfo8B4hkVX8VjTCtyPClbdxOnO7KCAsfHqEJb691LBUQ8BBmHZjTJFKmOZ8cp7B1lyeQ
Access Token:
k7w3vkjm34e4rqdwhhspgzb5g
Claims:
{
"iss": "http://192.168.100.10:5556/dex",
"sub": "CjV1aWQ9eWFzdS1hYmUsb3U9UGVvcGtlLG91PVByb3h5LGRjPXUtYWl6dSxkYz1hYyxkYz1qcBIEbGRhcA",
"aud": "example-app",
"exp": 1558673583,
"iat": 1558587183,
"at_hash": "5vYF2LY9FF2GYrEiNpNyQg",
"email": "yasu@yasundial.org",
"email_verified": true,
"name": "Yasuhiro ABE"
}
Refresh Token:
Chlsb3RydnNmaTJneWk3eDJ0Z2tpbDc0cDJuDhlsdmZqemZjbnF1Y3lycTIzeXhyamZ4Nmh4
Kubernetesへのデプロイメント
自前のk8sの環境で動かしたので簡単なメモを残します。
ただし、ドメイン依存な箇所は適宜修正しているので、不足分は補う必要があります。
Docker(Dockerhub)関連の設定ファイル
現在は次のようなAlpine用のDockerfileを利用していますが、コンテナのサイズは約90MBと少し大きいです。
自前のアイコンを準備しているので、あらかじめ images/logo.png にファイルを配置していますが、以下のDockerfileではコメントアウトしています。
FROM golang:alpine3.13 as dex
RUN apk --no-cache add git make gcc libc-dev
RUN mkdir /work
WORKDIR /work
RUN git clone https://github.com/dexidp/dex.git
WORKDIR /work/dex
# COPY image/logo.png web/themes/dark/logo.png
# COPY image/logo.png web/themes/light/logo.png
RUN make build
RUN make examples
FROM alpine:3.13
RUN apk update && apk add --no-cache bash ca-certificates
RUN mkdir -p /dex/bin
COPY --from=dex /work/dex/bin/. /dex/bin/.
WORKDIR /dex
COPY run.sh /run.sh
RUN chmod +x /run.sh
RUN mkdir /config
EXPOSE 5556
ENV DEX_CONFIG_TEMPLPATH="/config/config-ldap.yaml.templ"
ENV DEX_ISSUER="http://127.0.0.1:5556/dex "
ENV DEX_APP01_REDIRECTURI="http://example.app:5555/callback"
RUN mkdir /data
VOLUME ["/config", "/data"]
ENTRYPOINT ["/run.sh"]
run.shファイル
実際に利用しているファイルとは少し違いますが、次のような構成のスクリプトからサーバープロセスを起動しています。
# !/bin/bash -x
CONFIG_FILEPATH="${CONFIG_FILEPATH:-/config/config-ldap.yaml}"
cat "${CONFIG_FILEPATH}"
bin/dex serve "${CONFIG_FILEPATH}"
Dockerコンテナのビルド
Dockerfileとrun.shファイルを配置したら、次のような要領でコンテナを作成します。
$ sudo docker build . --tag dex-server
Kubectl用の設定ファイル
01-configmap.yamlには実際に利用する/config/config-ldap.yamlファイルの内容を記載してください。
---
apiVersion: v1
kind: ConfigMap
metadata:
name: dex-conf
namespace: dex
data:
config-ldap.yaml: |
issuer: ...
...
---
apiVersion: v1
kind: Service
metadata:
namespace: dex
name: issuer
spec:
type: LoadBalancer
loadBalancerIP: "192.168.100.35"
ports:
- port: 5556
protocol: TCP
selector:
app: issuer
ここではPVCを確保するために、Rook/Cephを利用しています。
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: dex
name: issuer
labels:
app: issuer
spec:
replicas: 1
selector:
matchLabels:
app: issuer
strategy:
type: Recreate
template:
metadata:
labels:
app: issuer
spec:
imagePullSecrets:
- name: dockerhubreg
containers:
- name: issuer
image: .../dexidp-dex:0.1
ports:
- containerPort: 5556
name: issuer
volumeMounts:
- name: config
mountPath: /config
- name: dex-data
mountPath: /data
volumes:
- name: config
configMap:
name: dex-conf
items:
- key: config-ldap.yaml
path: config-ldap.yaml
- name: dex-data
persistentVolumeClaim:
claimName: dex-data-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dex-data-pvc
namespace: dex
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: rook-ceph-block
resources:
requests:
storage: 2Gi
image:行や、secret/dockerhubreg はあらかじめ編集・作成しておくようにしてください。
以上