[CKS] 1-4. Service Accounts

K8s 애플리케이션의 API 접근, 서비스 어카운트 활용 방법과 자동화된 토큰 관리로 클러스터 상호작용의 보안과 효율성을 동시에 높입니다.

[CKS] 1-4. Service Accounts
Photo by Shubham Dhage / Unsplash

개요

Service Accounts 인증, 인가, 역할 기반 접근 제어 등 다른 접근 제어 방식과 연결되어있지만, 시험을 위해선 서비스 어카운트 자체를 k8s에서 사용하는 방법을 학습해야합니다.

Account의 종류

k8s에서는 두 가지 유형의 계정이 존재합니다.

  1. User Account
    1. 사용자가 사용하는 계정
      1. 클러스터에 접근하여 관리 작업을 수행하거나, 개발자가 클러스터에 접근하여 애플리케이션을 배포합니다.
  2. Service Account
    1. 머신이 사용하는 계정
      1. 애플리케이션이 상호작용하기 위해 사용하는 계정
        1. 프로메테우스같이 모니터링 애플리케이션의 경우 Metric 지표를 가져오기 위해 사용
        2. Jenkins 같이 클러스터에 애플리케이션을 배포하기 위해 사용

Service Account

Service Account는 생성될 때 Secret을 같이 생성합니다. 해당 토큰을 가지고 마찬가지로 bearer로 등록하여 요청을 수행할 수 있습니다.

kubectl create serviceaccount dashboard-sa

kubectl describe serviceaccount dashboard-sa
----------------------------------------------
Name:                dashboard-sa
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   dashboard-sa-token-kbbdm
Tokens:              dashboard-sa-token-kbbdm
Events:              <none>
kubectl describe secret dashboard-sa-token-kbbdm

----------------------------------------------
Name:         dashboard-sa-token-kbbdm
Namespace:    default
Labels:       <none>
Type:         kubernetes.io/service-account-token


Data
====
ca.crt:     1025 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6Ij...
curl https://192.168.56.70:6443/api -insecure \
  --header "Authorization: Bearer eyJhbgG..."
  • 서비스 계정 생성
  • RBAC 메커니즘을 통한 권한 부여
  • 토큰을 전달하여 서드파티 애플리케이션이 작업을 수행

서드파티 애플리케이션이 클러스터 자체에 호스팅되어있다면 서비스 계정 토큰을 내보내고 설정하는 과정이필요없습니다. Pod 내부에 서비스 토큰을 볼륨으로 마운트하여 자동으로 수행하게 만들 수 있습니다.

이렇게하면 토큰이 이미 Pod 내부에 배치되어 애플리케이션이 쉽게 읽을 수 있습니다.

또한 각 Namespace에는 고유한 default 계정이 존재합니다. 이후 namespace에 파드가 생성될 때마다 자동으로 토큰이 파드에 볼륨으로 마운트되어 연결됩니다. Volumes에 Secret을 포함하며 /var/run/secrets/kubernetes.io/serviceaccount 위치에 마운트됩니다.

해당 위치에서 사용될 토큰을 확인할 수 있습니다. 다만 매우 제한적으로 설정되어 있습니다.

apiVersion: v1
kind: Pod
metadata:
  name: my-kubernetes-dashboard
spec:
  containers:
    - name: my-kubernetes-dashboard
      image: my-kubernetes-dashboard
----------------------------------------------

Name:           my-kubernetes-dashboard
Namespace:      default
Annotations:    <none>
Status:         Running
IP:             10.244.0.15
Containers:
  my-kubernetes-dashboard:
    Image:      my-kubernetes-dashboard
Mounts:
  /var/run/secrets/kubernetes.io/serviceaccount from default-token-j4hkv (ro)
Volumes:
  default-token-j4hkv:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-j4hkv
    Optional:    false

커스텀 Service Account를 등록하려는 경우, 해당 Service Account의 이름을 지정하면 됩니다. 하지만 기억해야할 것은 Service Account는 Edit할 수 없고 반드시 삭제 후 생성해야합니다. Deployment의 경우 자동으로 새로운 Rollout을 트리거하기 때문에 Deployment를 통한 작업을 권장합니다.

1.22 / 1.24 Service Account Secret & Token 변경 사항

  • v1.22에서 Token Request API 도입
    • 새로운 Pod가 생성될 때 Service Account token에 의존하지 않습니다.
      • 자동으로 마운트 되지 않습니다.
    • 대신 수명을 가진 토큰이 Service Account admission controller의 token request api에 의해 생성됩니다.
    • 해당 토큰은 projected volume으로 pod에 마운트 됩니다.
    • 토큰이 대상 및 시간 제한을 가지므로 무기한 유효 토큰과 관련된 문제를 해결했습니다.

정리하면 다음과 같습니다.

  • Audience-bound
    • 토큰이 의도된 특정 수신자에게만 유효하도록 제한하는 방식
    • 토큰이 유출되어 공격자가 이 토큰을 Kubernetes API 서버(청중: kubernetes.default.svc)에 제시하려 해도, Kubernetes API 서버는 aud 필드가 같지 않다면 요청을 거부
  • Time-bound
  • Object-bound
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: default
spec:
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
        - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
          name: kube-api-access-6mtg8
          readOnly: true
  volumes:
    - name: kube-api-access-6mtg8

      projected:
        defaultMode: 420
        sources:
          - serviceAccountToken:
              expirationSeconds: 3607
              path: token

          - configMap:
              name: kube-root-ca.crt
              items:
                - key: ca.crt
                  path: ca.crt
          - downwardAPI:
              items:
                - fieldRef:
                    apiVersion: v1
                    fieldPath: metadata.namespace
  • v1.24에서 Service Account 생성 시 Secret, Token을 자동으로 생성하지 않습니다.
    • 서비스 계정에 토큰이 필요한 경우 kubectl create token 을 통해 서비스 계정의 이름을 입력
kubectl create token <서비스_어카운트_이름> -n <네임스페이스> [--audience <청중>] [--duration <유효기간>]
  • 이전처럼 만료되는 것을 원하지 않는다면 Secret으로 생성하여 annotations를 사용해야합니다.
    • Token Request API를 수행할 수 없는 경우에만 사용합니다.

Hands on

kubectl set serviceaccount deploy/web-dashboard dashboard-sa
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - mountPath: /var/run/secrets/tokens
      name: vault-token
  serviceAccountName: build-robot
  volumes:
  - name: vault-token
    projected:
      sources:
      - serviceAccountToken:
          path: vault-token
          expirationSeconds: 7200
          audience: vault