Dex, dex-k8s-authenticator ๋ฐ GitHub๋ฅผ ์ฌ์ฉํ์ฌ Kubernetes ํด๋ฌ์คํฐ์ ๋ํ ์ก์ธ์ค๋ฅผ ์์ฑํ๋ ํํ ๋ฆฌ์ผ์ ์ฌ๋ฌ๋ถ๊ป ์๊ฐํฉ๋๋ค.
๋ฌ์์์ด Kubernetes ์ฑํ
์ ๋ก์ปฌ ๋ฐ
์๊ฐ
์ฐ๋ฆฌ๋ Kubernetes๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋ฐ ๋ฐ QAํ์ ์ํ ๋์ ํ๊ฒฝ์ ๋ง๋ญ๋๋ค. ๊ทธ๋์ ์ฐ๋ฆฌ๋ ๊ทธ๋ค์๊ฒ ๋์๋ณด๋์ kubectl ๋ชจ๋์ ๋ํ ํด๋ฌ์คํฐ์ ๋ํ ์ก์ธ์ค ๊ถํ์ ๋ถ์ฌํ๋ ค๊ณ ํฉ๋๋ค. OpenShift์ ๋ฌ๋ฆฌ ๋ฐ๋๋ผ Kubernetes์๋ ๊ธฐ๋ณธ ์ธ์ฆ์ด ์์ผ๋ฏ๋ก ์ด๋ฅผ ์ํด ํ์ฌ ๋๊ตฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ด ๊ตฌ์ฑ์์๋ ๋ค์์ ์ฌ์ฉํฉ๋๋ค.
dex-k8s-์ธ์ฆ์โ โ kubectl ๊ตฌ์ฑ์ ์์ฑํ๊ธฐ ์ํ ์น ์ ํ๋ฆฌ์ผ์ด์ ๋ฑ์ค โ OpenID Connect ์ ๊ณต์- GitHub - ํ์ฌ์์ GitHub๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
Google OIDC๋ฅผ ์ด์ฉํ๋ ค๊ณ ํ์ผ๋ ์์ฝ๊ฒ๋
๊ทธ๋ ๋ค๋ฉด Kubernetes ์ธ์ฆ ํ๋ก์ธ์ค๋ ์๊ฐ์ ํํ์์ ์ด๋ป๊ฒ ์๋ํฉ๋๊น?
์น์ธ ์ ์ฐจ
์ข ๋ ์์ธํ ์ค๋ช ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ฌ์ฉ์๊ฐ dex-k8s-authenticator์ ๋ก๊ทธ์ธํฉ๋๋ค(
login.k8s.example.com
) - dex-k8s-authenticator๋ ์์ฒญ์ Dex(
dex.k8s.example.com
) - Dex๊ฐ GitHub ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋ฆฌ๋๋ ์ ๋ฉ๋๋ค.
- GitHub๋ ํ์ํ ์ธ์ฆ ์ ๋ณด๋ฅผ ์์ฑํ์ฌ Dex์ ๋ฐํํฉ๋๋ค.
- Dex๋ ์์ ๋ ์ ๋ณด๋ฅผ dex-k8s-authenticator์ ์ ๋ฌํฉ๋๋ค.
- ์ฌ์ฉ์๋ GitHub์์ OIDC ํ ํฐ์ ๋ฐ์ต๋๋ค.
- dex-k8s-authenticator๋ kubeconfig์ ํ ํฐ์ ์ถ๊ฐํฉ๋๋ค.
- kubectl์ ํ ํฐ์ KubeAPIServer์ ์ ๋ฌํฉ๋๋ค.
- KubeAPIServer๋ ์ ๋ฌ๋ ํ ํฐ์ ๊ธฐ๋ฐ์ผ๋ก kubectl์ ๋ํ ์ก์ธ์ค๋ฅผ ๋ฐํํฉ๋๋ค.
- ์ฌ์ฉ์๋ kubectl์์ ์ก์ธ์ค ๊ถํ์ ์ป์ต๋๋ค.
์ค๋น ์กฐ์น
๋ฌผ๋ก ์ด๋ฏธ Kubernetes ํด๋ฌ์คํฐ๊ฐ ์ค์น๋์ด ์์ต๋๋ค(k8s.example.com
), HELM๋ ์ฌ์ ์ค์น๋์ด ์ ๊ณต๋ฉ๋๋ค. GitHub(super-org)์๋ ์กฐ์ง์ด ์์ต๋๋ค.
HELM์ด ์์ผ๋ฉด ์ค์นํ์ธ์.
๋จผ์ GitHub๋ฅผ ์ค์ ํด์ผ ํฉ๋๋ค.
์กฐ์ง ์ค์ ํ์ด์ง๋ก ์ด๋ํฉ๋๋ค(https://github.com/organizations/super-org/settings/applications
) ์ ์ ํ๋ฆฌ์ผ์ด์
(์น์ธ๋ OAuth ์ฑ)์ ์์ฑํฉ๋๋ค.
GitHub์์ ์ ์ ํ๋ฆฌ์ผ์ด์
๋ง๋ค๊ธฐ
ํ์ํ URL๋ก ํ๋๋ฅผ ์ฑ์ฐ์ธ์. ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ํํ์ด์ง URL:
https://dex.k8s.example.com
- ์น์ธ ์ฝ๋ฐฑ URL:
https://dex.k8s.example.com/callback
๋งํฌ์ ์ฃผ์ํ์ธ์. ์ฌ๋์๋ฅผ ์์ง ์๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์์ฑ๋ ์์์ ๋ํ ์๋ต์ผ๋ก GitHub๋ ๋ค์์ ์์ฑํฉ๋๋ค. Client ID
ะธ Client secret
, ์์ ํ ์ฅ์์ ๋ณด๊ดํ๋ฉด ์ฐ๋ฆฌ์๊ฒ ์ ์ฉํ ๊ฒ์
๋๋ค(์:
Client ID: 1ab2c3d4e5f6g7h8
Client secret: 98z76y54x32w1
ํ์ ๋๋ฉ์ธ์ ๋ํ DNS ๋ ์ฝ๋ ์ค๋น login.k8s.example.com
ะธ dex.k8s.example.com
, ์์ ์ ์ํ SSL ์ธ์ฆ์๋ ์์ต๋๋ค.
SSL ์ธ์ฆ์๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
cat <<EOF | kubectl create -f -
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: cert-auth-dex
namespace: kube-system
spec:
secretName: cert-auth-dex
dnsNames:
- dex.k8s.example.com
acme:
config:
- http01:
ingressClass: nginx
domains:
- dex.k8s.example.com
issuerRef:
name: le-clusterissuer
kind: ClusterIssuer
---
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: cert-auth-login
namespace: kube-system
spec:
secretName: cert-auth-login
dnsNames:
- login.k8s.example.com
acme:
config:
- http01:
ingressClass: nginx
domains:
- login.k8s.example.com
issuerRef:
name: le-clusterissuer
kind: ClusterIssuer
EOF
kubectl describe certificates cert-auth-dex -n kube-system
kubectl describe certificates cert-auth-login -n kube-system
์ ๋ชฉ์ด ์๋ ClusterIssuer le-clusterissuer
์ด๋ฏธ ์กด์ฌํด์ผ ํ์ง๋ง, ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ HELM์ ์ฌ์ฉํ์ฌ ์์ฑํฉ๋๋ค.
helm install --namespace kube-system -n cert-manager stable/cert-manager
cat << EOF | kubectl create -f -
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: le-clusterissuer
namespace: kube-system
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: le-clusterissuer
http01: {}
EOF
KubeAPI์๋ฒ ๊ตฌ์ฑ
kubeAPIServer๊ฐ ์๋ํ๋ ค๋ฉด OIDC๋ฅผ ๊ตฌ์ฑํ๊ณ ํด๋ฌ์คํฐ๋ฅผ ์ ๋ฐ์ดํธํด์ผ ํฉ๋๋ค.
kops edit cluster
...
kubeAPIServer:
anonymousAuth: false
authorizationMode: RBAC
oidcClientID: dex-k8s-authenticator
oidcGroupsClaim: groups
oidcIssuerURL: https://dex.k8s.example.com/
oidcUsernameClaim: email
kops update cluster --yes
kops rolling-update cluster --yes
์ฐ๋ฆฌ๋ ์ฌ์ฉ
Dex ๊ตฌ์ฑ ๋ฐ dex-k8s-authenticator
Dex๊ฐ ์๋ํ๋ ค๋ฉด Kubernetes ๋ง์คํฐ๋ก๋ถํฐ ์ธ์ฆ์์ ํค๋ฅผ ๊ฐ์ ธ์์ผ ํฉ๋๋ค.
sudo cat /srv/kubernetes/ca.{crt,key}
-----BEGIN CERTIFICATE-----
AAAAAAAAAAABBBBBBBBBBCCCCCC
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
DDDDDDDDDDDEEEEEEEEEEFFFFFF
-----END RSA PRIVATE KEY-----
dex-k8s-authenticator ์ ์ฅ์๋ฅผ ๋ณต์ ํด ๋ณด๊ฒ ์ต๋๋ค.
git clone [email protected]:mintel/dex-k8s-authenticator.git
cd dex-k8s-authenticator/
๊ฐ ํ์ผ์ ์ฌ์ฉํ๋ฉด ์ฐ๋ฆฌ์ ๋ณ์๋ฅผ ์ ์ฐํ๊ฒ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
Dex์ ๊ตฌ์ฑ์ ์ค๋ช ํ๊ฒ ์ต๋๋ค.
cat << EOF > values-dex.yml
global:
deployEnv: prod
tls:
certificate: |-
-----BEGIN CERTIFICATE-----
AAAAAAAAAAABBBBBBBBBBCCCCCC
-----END CERTIFICATE-----
key: |-
-----BEGIN RSA PRIVATE KEY-----
DDDDDDDDDDDEEEEEEEEEEFFFFFF
-----END RSA PRIVATE KEY-----
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
path: /
hosts:
- dex.k8s.example.com
tls:
- secretName: cert-auth-dex
hosts:
- dex.k8s.example.com
serviceAccount:
create: true
name: dex-auth-sa
config: |
issuer: https://dex.k8s.example.com/
storage: # https://github.com/dexidp/dex/issues/798
type: sqlite3
config:
file: /var/dex.db
web:
http: 0.0.0.0:5556
frontend:
theme: "coreos"
issuer: "Example Co"
issuerUrl: "https://example.com"
logoUrl: https://example.com/images/logo-250x25.png
expiry:
signingKeys: "6h"
idTokens: "24h"
logger:
level: debug
format: json
oauth2:
responseTypes: ["code", "token", "id_token"]
skipApprovalScreen: true
connectors:
- type: github
id: github
name: GitHub
config:
clientID: $GITHUB_CLIENT_ID
clientSecret: $GITHUB_CLIENT_SECRET
redirectURI: https://dex.k8s.example.com/callback
orgs:
- name: super-org
teams:
- team-red
staticClients:
- id: dex-k8s-authenticator
name: dex-k8s-authenticator
secret: generatedLongRandomPhrase
redirectURIs:
- https://login.k8s.example.com/callback/
envSecrets:
GITHUB_CLIENT_ID: "1ab2c3d4e5f6g7h8"
GITHUB_CLIENT_SECRET: "98z76y54x32w1"
EOF
dex-k8s-authenticator์ ๊ฒฝ์ฐ:
cat << EOF > values-auth.yml
global:
deployEnv: prod
dexK8sAuthenticator:
clusters:
- name: k8s.example.com
short_description: "k8s cluster"
description: "Kubernetes cluster"
issuer: https://dex.k8s.example.com/
k8s_master_uri: https://api.k8s.example.com
client_id: dex-k8s-authenticator
client_secret: generatedLongRandomPhrase
redirect_uri: https://login.k8s.example.com/callback/
k8s_ca_pem: |
-----BEGIN CERTIFICATE-----
AAAAAAAAAAABBBBBBBBBBCCCCCC
-----END CERTIFICATE-----
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
path: /
hosts:
- login.k8s.example.com
tls:
- secretName: cert-auth-login
hosts:
- login.k8s.example.com
EOF
Dex ๋ฐ dex-k8s-authenticator๋ฅผ ์ค์นํฉ๋๋ค.
helm install -n dex --namespace kube-system --values values-dex.yml charts/dex
helm install -n dex-auth --namespace kube-system --values values-auth.yml charts/dex-k8s-authenticator
์๋น์ค์ ๊ธฐ๋ฅ์ ํ์ธํด ๋ณด๊ฒ ์ต๋๋ค(Dex๋ ์ฝ๋ 400์ ๋ฐํํด์ผ ํ๊ณ dex-k8s-authenticator๋ ์ฝ๋ 200์ ๋ฐํํด์ผ ํจ).
curl -sI https://dex.k8s.example.com/callback | head -1
HTTP/2 400
curl -sI https://login.k8s.example.com/ | head -1
HTTP/2 200
RBAC ๊ตฌ์ฑ
์ฐ๋ฆฌ์ ๊ฒฝ์ฐ์๋ ์ฝ๊ธฐ ์ ์ฉ ์ก์ธ์ค ๊ถํ์ผ๋ก ๊ทธ๋ฃน์ ๋ํ ClusterRole์ ์์ฑํฉ๋๋ค.
cat << EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-read-all
rules:
-
apiGroups:
- ""
- apps
- autoscaling
- batch
- extensions
- policy
- rbac.authorization.k8s.io
- storage.k8s.io
resources:
- componentstatuses
- configmaps
- cronjobs
- daemonsets
- deployments
- events
- endpoints
- horizontalpodautoscalers
- ingress
- ingresses
- jobs
- limitranges
- namespaces
- nodes
- pods
- pods/log
- pods/exec
- persistentvolumes
- persistentvolumeclaims
- resourcequotas
- replicasets
- replicationcontrollers
- serviceaccounts
- services
- statefulsets
- storageclasses
- clusterroles
- roles
verbs:
- get
- watch
- list
- nonResourceURLs: ["*"]
verbs:
- get
- watch
- list
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
EOF
ClusterRoleBinding์ ๋ํ ๊ตฌ์ฑ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: dex-cluster-auth
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-read-all
subjects:
kind: Group
name: "super-org:team-red"
EOF
์ด์ ํ ์คํธํ ์ค๋น๊ฐ ๋์์ต๋๋ค.
ํ ์คํธ
๋ก๊ทธ์ธ ํ์ด์ง(https://login.k8s.example.com
) GitHub ๊ณ์ ์ ์ฌ์ฉํ์ฌ ๋ก๊ทธ์ธํฉ๋๋ค.
๋ก๊ทธ์ธ ํ์ด์ง
๋ก๊ทธ์ธ ํ์ด์ง๊ฐ GitHub๋ก ๋ฆฌ๋๋ ์
๋์์ต๋๋ค.
์์ฑ๋ ์ง์นจ์ ๋ฐ๋ผ ์ก์ธ์ค ๊ถํ์ ์ป์ผ์ธ์.
์นํ์ด์ง์์ ๋ณต์ฌํ์ฌ ๋ถ์ฌ๋ฃ์ ํ kubectl์ ์ฌ์ฉํ์ฌ ํด๋ฌ์คํฐ ๋ฆฌ์์ค๋ฅผ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
kubectl get po
NAME READY STATUS RESTARTS AGE
mypod 1/1 Running 0 3d
kubectl delete po mypod
Error from server (Forbidden): pods "mypod" is forbidden: User "[email protected]" cannot delete pods in the namespace "default"
๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ ์กฐ์ง์ ๋ชจ๋ GitHub ์ฌ์ฉ์๋ ๋ฆฌ์์ค๋ฅผ ๋ณด๊ณ ํฌ๋์ ๋ก๊ทธ์ธํ ์ ์์ง๋ง ์ด๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ ๊ถํ์ ์์ต๋๋ค.
์ถ์ฒ : habr.com