StructuredAuthenticationConfigurationとは
この記事は v1.29でのalphaリリース時点の情報を参考にしています。
将来のリリースではAPIや挙動が変更になる可能性があります。
K8sにおける認証に関する設定をフラグベースから設定ファイルで指定できるようにする機能(フィーチャーゲート)です。設定フラグが機能要求にともなって増えていく問題を解消することがモチベーションだったようです。設定ファイルでの指定にともなってCEL式での制御やバリデーションができる機能も追加されています。
e.g.
claimMappings:
username:
expression: 'claims.username + ":external-user"'
groups:
expression: 'claims.roles.split(",")'
この機能はOIDC(JWT)認証の設定のみ可能です。(KEPを見ても他の認証設定は対象外と記載されています)
AuthenticationConfiguration
設定ファイルはAuthenticationConfiguration
の仕様で記述します。
今回、動作確認ではOIDCのOP(OpenID Provider)にはDexをデプロイしE-mail + Passwordによる認証を利用したため、それにより得られるID Tokenのclaimに合わせて設定しました。
apiVersion: apiserver.config.k8s.io/v1alpha1
kind: AuthenticationConfiguration
jwt:
- issuer:
url: https://dex.dex.svc.cluster.local:5556
audiences:
- example-app
certificateAuthority: | # 今回は証明書の準備で生成したCA証明書
-----BEGIN CERTIFICATE-----
MIIBfDCCASKgAwIBAgIUB00+pEjrHI4Cyw1Cs15ybcT+U98wCgYIKoZIzj0EAwIw
HDELMAkGA1UEBhMCSlAxDTALBgNVBAsTBFRlc3QwHhcNMjMxMjI2MDEzNjAwWhcN
MjgxMjI0MDEzNjAwWjAcMQswCQYDVQQGEwJKUDENMAsGA1UECxMEVGVzdDBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABBwzZGKDn6I4mryeGPCKHrjt1R1gGeNKPW+/
v5ACkqBPuSxhBBnu0SzbMFAk9MoKNqCNt0VmXtIteU0skYFcICSjQjBAMA4GA1Ud
DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRgbWLYqlw7Ru2y
PIUo6m3zYMIgMjAKBggqhkjOPQQDAgNIADBFAiBF0e5NlNWOBU2euhV3zO4COQPz
NQvFcxRRMEMQRr+qIgIhAPOw9O6fy9Wfs9sk0juSfNuKAHMdISjkh9EzTxMqwXRS
-----END CERTIFICATE-----
claimMappings:
username:
claim: 'name'
prefix: ''
uid:
claim: 'sub'
上記の設定はkube-apiserverの--authentication-config
フラグにファイルを指定することで反映できます。v1.29
時点ではあわせてStructuredAuthenticationConfiguration
フィーチャーゲートを有効にする必要があります。
設定ファイルは自動リロードに対応(または対応予定)しているようです。
今回、K8sクラスタはkindで作成したものを利用しました。kindによる設定ファイルの指定や起動方法などはkindを使ったk8sクラスタの準備を参照してください。
動作確認
-
Dexの準備に従って作成したK8sクラスタにDexをデプロイ
-
ID Tokenを取得するためのアプリケーションをビルド
> git clone https://github.com/dexidp/dex.git
> cd dex/examples-example-app
> GOOS=linux GOARCH=amd64 go build -o example-app
> cp example-app /path/to/workdir/.
- 動作確認用アプリケーションをデプロイ
コンテナイメージ作成の例
FROM debian:12.4
COPY example-app .
COPY ca.pem .
ENTRYPOINT ["./example-app"]
CMD ["--issuer" "https://dex.dex.svc.cluster.local:5556" "--issuer-root-ca" "/etc/ssl/certs/ca-certificates.crt" ]
> docker build -t hiyosi/example-app -f Dockerfile .
> docker push hiyosi/example-app
K8sマニフェスト
apiVersion: v1
kind: Pod
metadata:
name: example-app
spec:
containers:
- name: example-app
image: hiyosi/example-app
imagePullPolicy: Always
ports:
- containerPort: 5555
> kubectl apply -f app.yaml
> kubectl port-forward ${EXAMPLE_APP} 5555:5555
- 認証
Dexの認証画面 にアクセスしE-mail + Passwordでログインします。
(認証情報はdexの設定ファイル参照)
認証に成功すると動作確認用アプリケーション(http://127.0.0.1:5555/callback)にコールバックされてID TokenやClaim情報が表示されます。
- kubeconfigの設定
取得したID Tokenを使って~/.kube/config
で以下のような設定を追加します (一部抜粋)。
contexts:
- context:
cluster: kind-kind
user: dex-idp
name: kind-oidc
users:
- name: dex-idp
user:
auth-provider:
config:
client-id: example-app
id-token: ${ID_TOKEN} # Dexで認証に成功すると得られるID Token
idp-certificate-authority: /tmp/ca.pem # 証明書の準備で生成したCA証明書
idp-issuer-url: https://dex.dex.svc.cluster.local:5556
name: oidc
- 動作確認用のRBACの設定
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: admin
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
> kubectl apply -f rbac.yaml
- 動作確認
> kubectl --context kind-oidc get pods
NAME READY STATUS RESTARTS AGE
example-app 1/1 Running 0 19m
> kubectl --context kind-oidc get node
Error from server (Forbidden): nodes is forbidden: User "admin" cannot list resource "nodes" in API group "" at the cluster scope
権限を付与したリリースは想定通り操作でき、それ以外のリソースは操作できないことが確認できました。
その他準備など
kindを使ったk8sクラスタの準備
※ 動作確認目的だけのため、File sharingやPort mappingなど、動作確認用に少々強引な設定を入れています。
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: ClusterConfiguration
apiServer:
extraArgs:
authentication-config: /tmp/auth/auth.yaml
extraVolumes:
- name: "auth-config"
hostPath: /tmp/docker
mountPath: /tmp/auth
extraMounts: # ローカルのファイルをDocker for MacのFile sharingを使って渡す
- hostPath: /tmp/docker
containerPath: /tmp/docker
extraPortMappings: # Dexでの認証画面にローカルからアクセスするため
- containerPort: 32000
hostPort: 32000
- role: worker
featureGates:
"StructuredAuthenticationConfiguration": true
> kind create cluster --image kindest/node:v1.29.0 --config kind.yaml
Dexの準備
https://dexidp.io/docs/kubernetes/ を参考にデプロイしました。
証明書は上記の手順に従わず 証明書の準備 の項目の手順で作成したものを使いました。
また認証はemail + passwordのみを利用するため、Dexの設定ファイルからGitHubを使った認証等の設定は省きました。
dex.yamlの差分
diff --git a/examples/k8s/dex.yaml b/examples/k8s/dex.yaml
index c8d83944..be351080 100644
--- a/examples/k8s/dex.yaml
+++ b/examples/k8s/dex.yaml
@@ -37,18 +37,6 @@ spec:
- name: tls
mountPath: /etc/dex/tls
- env:
- - name: GITHUB_CLIENT_ID
- valueFrom:
- secretKeyRef:
- name: github-client
- key: client-id
- - name: GITHUB_CLIENT_SECRET
- valueFrom:
- secretKeyRef:
- name: github-client
- key: client-secret
-
readinessProbe:
httpGet:
path: /healthz
@@ -72,7 +60,7 @@ metadata:
namespace: dex
data:
config.yaml: |
- issuer: https://dex.example.com:32000
+ issuer: https://dex.dex.svc.cluster.local:5556
storage:
type: kubernetes
config:
@@ -82,14 +70,6 @@ data:
tlsCert: /etc/dex/tls/tls.crt
tlsKey: /etc/dex/tls/tls.key
connectors:
- - type: github
- id: github
- name: GitHub
- config:
- clientID: $GITHUB_CLIENT_ID
- clientSecret: $GITHUB_CLIENT_SECRET
- redirectURI: https://dex.example.com:32000/callback
- org: kubernetes
oauth2:
skipApprovalScreen: true
diff --git a/examples/k8s/gencert.sh b/examples/k8s/gencert.sh
index 77435857..2ac373fd 100755
--- a/examples/k8s/gencert.sh
+++ b/examples/k8s/gencert.sh
@@ -16,6 +16,7 @@ subjectAltName = @alt_names
[alt_names]
DNS.1 = dex.example.com
+DNS.2 = dex.dex.svc.cluster.local
EOF
openssl genrsa -out ssl/ca-key.pem 2048
</div></details>
kubectl create ns dex
kubectl -n dex create secret tls dex.example.com.tls --cert=server.pem --key=server-key.pem
kubectl apply -f dex.yaml
#### /etc/hosts
$DEX_SVC_IP dex.dex.svc.cluster.local
### 証明書の準備
(色々と試している中で証明書は下記の手順で作成しましたが、 結果的に[Dexの準備](#Dexの準備)の参考URLの方法でも問題なかったかもしれません)
ca.json
```json
{
"hosts": [
"ca.example.com"
],
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "JP",
"OU": "Test"
}
]
}
> cfssl gencert -initca ca.json | cfssljson -bare ca
config.json
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"server": {
"usages": [
"signing",
"digital signing",
"key encipherment",
"server auth"
],
"expiry": "8760h"
},
"client": {
"usages": [
"signing",
"digital signature",
"key encipherment",
"client auth"
],
"expiry": "8760h"
}
}
}
}
server.json
{
"hosts": [
"dex.example.com",
"dex.dex.svc.cluster.local"
],
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [{
"C": "JP",
"L": "Tokyo",
"OU": "Test"
}]
}
> cfssl gencert -ca ca.pem -ca-key ca-key.pem -config config.json -profile=server server.json | cfssljson -bare server
> openssl verify -CAfile ca.pem server.pem
server.pem: OK