Kubernetes Cluster OIDC 인증 설정하기
개요
일반적으로 kubectl
을 통해 클러스터에 접근할 때는 kube-apiserver
를 거쳐 인증이 이루어진다.
AWS나 GCP 같은 클라우드 환경에서는 이러한 인증 설정이 Cloud Provider에 의해 자동으로 구성되어 있어, 사용자가 별도로 설정할 필요가 없다.
반면, kubeadm
이나 k3s
를 사용해 직접 클러스터를 구성한 경우에는, 기본으로 제공되는 kubeconfig
파일을 통해 인증을 수행하게 된다.
이 kubeconfig
파일을 사용하면 클러스터 내 모든 리소스에 접근할 수 있으며, 개인이 테스트 목적으로 사용할 때는 큰 문제가 되지 않는다.
하지만 여러 사용자가 클러스터를 함께 사용하는 환경에서는 이러한 방식이 몇 가지 보안상 리스크를 초래할 수 있다.
가장 큰 문제는 기본 kubeconfig
파일이 클러스터 전체 관리자 권한을 갖는 경우가 많아, 실수로 중요한 리소스를 삭제하거나 설정을 변경할 수 있다는 점이다.
또한, 해당 kubeconfig
파일이 유출될 경우, 인증 절차 없이 누구나 클러스터에 접근할 수 있어 심각한 보안 사고로 이어질 수 있다.
추가로, 사용자의 식별이나 접근 권한을 세분화하기 어렵기 때문에, 누가 어떤 작업을 했는지 추적하기도 어렵다.
이러한 문제를 방지하기 위해서는 kube-apiserver
에 OIDC(OpenID Connect) 기반 인증을 연동해 사용자 단위의 인증 체계를 갖추는 것이 필요하다.
그리고 OIDC로 인증된 사용자에게 적절한 권한을 부여하려면 Kubernetes의 RBAC(Role-Based Access Control) 설정도 함께 적용해야 한다.
이번 글에서는 OIDC 인증을 Kubernetes에 연동하고, RBAC을 사용자가 속한 Group단위로 적용하는 방법에 대해 자세히 알아보자.
구성
- Kubernets: K3s
- OIDC Provider: Authentik(self-hosted)
- CLI(kubectl): code-server(with self-hosted Coder)
OAuth2/OpenID Provider 설정
Provider 생성을 진행하고 Issuer URL, Client ID 이 준비되면 끝
Provider 생성
Admin interface → Providers
- Client Type은 Confidential
생성이 완료된 Provider를 누르면 Application에 연결이 되어있지 않음 Application 생성 및 Assign 진행
Provider만 잘 연결해주면 된다.
Issuer URL 확인
Client ID 확인
추가로 Signing Key를 설정해야하는데 RS256 또는 RS512 인증서를 사용해야 한다.
kube-apiserver 설정
kubeadm으로 클러스터를 설정한 경우
/etc/kubernetes/manifests/kube-apiserver.yaml
파일 수정
spec:
containers:
- name: kube-apiserver
image: k8s.gcr.io/kube-apiserver:v1.23.0
command:
- kube-apiserver
- --oidc-issuer-url=<Issuer URL>
- --oidc-client-id=<Client ID>
- --oidc-client-secret=<Client Secret>
- --oidc-username-claim=email
- --oidc-groups-claim=groups
command 이외에 다른건 건드리지말자
--oidc-issuer-url=
Issuer URL--oidc-client-id=
Client ID--oidc-client-secret
Client Secret--oidc-username-claim
email 또는 preferred_username--oidc-groups
groups(그룹 기반 접근 제어)
K3s로 클러스터를 설치한 경우
Control Plane 노드에 아래 파일 수정(없으면 생성)/etc/rancher/k3s/config.yaml
kube-apiserver-arg:
- oidc-issuer-url=<Issuer URL>
- oidc-client-id=<Client ID>
- oidc-username-claim=email
- oidc-groups-claim=group
설정이 완료되면 k3s를 재시작
systemctl restart k3s
kubelogin 구성
아래 OIDC client를 사용하여 OIDC 인증을 진행
krew 설치
kubelogin은 krew를 통해 설치 진행(다른 방식으로도 설치가 가능)
(
set -x; cd "$(mktemp -d)" &&
OS="$(uname | tr '[:upper:]' '[:lower:]')" &&
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" &&
KREW="krew-${OS}_${ARCH}" &&
curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" &&
tar zxvf "${KREW}.tar.gz" &&
./"${KREW}" install krew
)
설치 확인
$ kubectl krew
krew is the kubectl plugin manager.
You can invoke krew through kubectl: "kubectl krew [command]..."
Usage:
kubectl krew [command]
Available Commands:
help Help about any command
index Manage custom plugin indexes
info Show information about an available plugin
install Install kubectl plugins
list List installed kubectl plugins
search Discover kubectl plugins
uninstall Uninstall plugins
update Update the local copy of the plugin index
upgrade Upgrade installed plugins to newer versions
version Show krew version and diagnostics
Flags:
-h, --help help for krew
-v, --v Level number for the log level verbosity
Use "kubectl krew [command] --help" for more information about a command.
kubelogin 설치
kubectl krew install oidc-login
kubelogin 설정
지금 실행할 kubectl 명령어는 기본으로 발급 받은 KUBECONFIG를 사용
$ kubectl oidc-login setup \
--oidc-issuer-url <Issuer URL> \
--oidc-client-id <Client ID> \
--oidc-extra-scope email,profile,openid \
--grant-type device-code \
--oidc-pkce-method S256
RS512의 경우 S512 사용
--oidc-extra-scope
SSO Provider에서 제공하는 scope를 지정하면 된다.
(Authentik의 경우 email,profile,openid 사용)--grant-type
device-code를 통해 code-server 내부에서 Authentik 인증을 가능하게 할 수 있음
(로컬 환경의 VSCode나 Terminal의 경우auto
로 설정)
해당 명령어를 실행하면 아래와 같이 새로운 창이 열리며 로그인이 진행됨
인증이 완료되고 다시 code-server로 돌아오면 아래와 같이 출력
kubectl oidc-login setup \
--oidc-issuer-url --- \
--oidc-client-id --- \
--oidc-extra-scope email,profile,openid \
--grant-type device-code \
--oidc-pkce-method S256
Authentication in progress...
## Authenticated with the OpenID Connect Provider
You got the token with the following claims:
```
{
"iss": "---",
"sub": "---",
"aud": "---",
"exp": 1745294042,
"iat": 1745293742,
"auth_time": 1745293742,
"acr": "goauthentik.io/providers/oauth2/default",
"email": "rolestack@gmail.com",
"email_verified": true,
"name": "Kyungmin Park",
"given_name": "Kyungmin Park",
"preferred_username": "rolestack",
"nickname": "rolestack",
"groups": [
"kubernetes-admin"
]
}
```
## Set up the kubeconfig
You can run the following command to set up the kubeconfig:
```
kubectl config set-credentials oidc \
--exec-api-version=client.authentication.k8s.io/v1 \
--exec-interactive-mode=Never \
--exec-command=kubectl \
--exec-arg=oidc-login \
--exec-arg=get-token \
--exec-arg="--oidc-issuer-url=something" \
--exec-arg="--oidc-client-id=something" \
--exec-arg="--oidc-extra-scope=email" \
--exec-arg="--oidc-extra-scope=profile" \
--exec-arg="--oidc-extra-scope=openid" \
--exec-arg="--oidc-pkce-method=S256" \
--exec-arg="--grant-type=device-code"
```
claim이 표시된 걸 보니 정상적으로 데이터가 불러와졌고 로그인한 User의 group 또한 확인이 된다.
이제 You can run the following command to set up the kubeconfig 아래 보이는 명령어를 복붙하면 기존 KUBECONFIG 파일 내부에 추가가 되고 설정은 끝
ClusterRoleBinding 설정
아래 파일을 배포
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kube-api-admin-binding
subjects:
- kind: Group
name: kubernetes-admin
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
subjects.kind
이번 예제는 그룹 기반으로 인증subjects.name
Authentik의kubernetes-admin
그룹을 사용roleRef.name
Kubernetes에 기본 생성된 'cluster-admin' ClusterRole 사용
기존 KUBECONFIG 수정
아래는 기존 KUBECONFIG 파일의 모습
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: something
server: https://something:somethine
name: default
contexts:
- context:
cluster: default
user: default
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
user:
client-certificate-data: something
client-key-data: something
kubelogin 설정 이후의 모습은 아래와 같음
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: something
server: https://something:somethine
name: default
contexts:
- context:
cluster: default
user: default
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
user:
client-certificate-data: something
client-key-data: something
- name: oidc
user:
exec:
apiVersion: client.authentication.k8s.io/v1
args:
- oidc-login
- get-token
- --oidc-issuer-url=something
- --oidc-client-id=something
- --oidc-extra-scope=email
- --oidc-extra-scope=profile
- --oidc-extra-scope=openid
- --oidc-pkce-method=S512
- --grant-type=device-code
command: kubectl
env: null
interactiveMode: Never
provideClusterInfo: false
여기서 아래 부분을 수정하고 사용자들에게 해당 config 파일을 배포해주면 끝
contextxs.user
default → oidcusers
default 삭제
(Authentik) device code flow 설정
device code flow 설정이 안되어있으면 device-code로 설정을 할 수 없음
Flows and Stages → Create
- Designation: Stage Configuration
- Authentication: Require authentication
System → Brands → authentik-default 수정