[CKS] 1-4. Service Accounts
K8s 애플리케이션의 API 접근, 서비스 어카운트 활용 방법과 자동화된 토큰 관리로 클러스터 상호작용의 보안과 효율성을 동시에 높입니다.
개요
Service Accounts 인증, 인가, 역할 기반 접근 제어 등 다른 접근 제어 방식과 연결되어있지만, 시험을 위해선 서비스 어카운트 자체를 k8s에서 사용하는 방법을 학습해야합니다.
Account의 종류
k8s에서는 두 가지 유형의 계정이 존재합니다.
- User Account
- 사용자가 사용하는 계정
- 클러스터에 접근하여 관리 작업을 수행하거나, 개발자가 클러스터에 접근하여 애플리케이션을 배포합니다.
- 사용자가 사용하는 계정
- Service Account
- 머신이 사용하는 계정
- 애플리케이션이 상호작용하기 위해 사용하는 계정
- 프로메테우스같이 모니터링 애플리케이션의 경우 Metric 지표를 가져오기 위해 사용
- 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에 마운트 됩니다.
- 토큰이 대상 및 시간 제한을 가지므로 무기한 유효 토큰과 관련된 문제를 해결했습니다.
- 새로운 Pod가 생성될 때 Service Account token에 의존하지 않습니다.
정리하면 다음과 같습니다.
- 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