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

OAuth2/OpenID 선택
  • Client Type은 Confidential

생성이 완료된 Provider를 누르면 Application에 연결이 되어있지 않음 Application 생성 및 Assign 진행

Provider만 잘 연결해주면 된다.

Issuer URL 확인

Client ID 확인

추가로 Signing Key를 설정해야하는데 RS256 또는 RS512 인증서를 사용해야 한다.

System → Certificates

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(그룹 기반 접근 제어)
💡
해당 리소스는 static pod로 kubelet이 감시하고 있기에 파일 수정사항이 발생하면 자동으로 수정된 내용으로 배포하기에 별도로 재시작할 필요는 없음

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 인증을 진행

GitHub - int128/kubelogin: kubectl plugin for Kubernetes OpenID Connect authentication (kubectl oidc-login)
kubectl plugin for Kubernetes OpenID Connect authentication (kubectl oidc-login) - int128/kubelogin

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 → oidc
  • users default 삭제

(Authentik) device code flow 설정

device code flow 설정이 안되어있으면 device-code로 설정을 할 수 없음

Flows and Stages → Create

  • Designation: Stage Configuration
  • Authentication: Require authentication

System → Brands → authentik-default 수정

참고

Authenticating
This page provides an overview of authentication. Users in Kubernetes All Kubernetes clusters have two categories of users: service accounts managed by Kubernetes, and normal users. It is assumed that a cluster-independent service manages normal users in the following ways: an administrator distributing private keys a user store like Keystone or Google Accounts a file with a list of usernames and passwords In this regard, Kubernetes does not have objects which represent normal user accounts.