쿠버네티스는 다양한 주체가 클러스터와 상호작용한다. 사람이 kubectl 명령어를 실행하거나 Pod 가 쿠버네티스 API 를 호출하여 kube-apiserver 를 거쳐 리소스를 생성, 조회, 수정, 삭제할 수 있다. 때문에 kube-apiserver 에서 모든 Authentication 이 이루어진다. 요청 주체를 크게 User 와 ServiceAccount 로 구분한다. 쿠버네티스는 내부적으로 User 리소스를 저장하지 않는다. 대신 Certificates 나 외부 Identity Service 인증 시스템과 연동하여 사용자를 확인한다. kubectl 명령어를 실행하는 User 는 보통 certificate 이나 IdP 인증 정보를 가진 kubeconfig 파일을 사용하여 kube-apiserver 에 인증한다. Pod 의 경우 지정된 ServiceAccount 의 토큰을 자동으로 마운트하여 인증한다.
Good to know
kube-apiserver 는 요청을 Authenticate 하기 위해 Static Password File, Static Token File 도 활용할 수 있다.
apiVersion: certificates.k8s.io/v1beta1kind: CertificateSigningRequestmetadata: name: meatsbyspec: groups: - system:authenticated usages: - digital signature - key encipherment - server auth request: <certificate-goes-here>
kubectl get csrkubectl certificate approve meatsbykubectl get csr meatsby -o yamlecho "<certificate>" | base64 --decode
K8s 는 Admin 의 Certificate 작업을 대신해주기 위한 API 를 제공한다. Controller Manager 가 Certificate 관련 작업을 모두 처리한다.
kubeconfig
# ~/.kube/config (기본 위치)apiVersion: v1kind: Configcurrent-context: my-kube-admin@my-kube-playground # 현재 사용 중인 접속 설정clusters: # kube-apiserver 주소 및 인증서 정보- name: my-kube-playground cluster: certificate-authority: ca.crt server: https:///my-kube-playground:6443contexts: # 어느 사용자와 클러스터를 조합해서 사용할 지 정의- name: my-kube-admin@my-kube-playground context: cluster: my-kube-playground user: my-kube-admin namespace: financeusers: # 인증서 또는 토큰으로 이루어진 사용자 정보- name: my-kube-admin user: client-certificate: admin.crt client-key: admin.key
kubectl config view # 현재 사용 중인 kubeconfig 확인kubectl config view --kubeconfig=my-custom-configkubectl config use-context prod-user@productionkubectl config set-context $(kubectl config current-context) --namespace=dev
kubectl config 명령어를 통해 kubectl 작업 위치를 특정 namespace 로 이동시킬 수도 있다.
Good to know
# curl 로 kube-apiserver 와 통신curl https://my-kube-playground:6443/api/v1/pods \ --key admin.key --cert admin.crt --cacert ca.crt# kubectl 로 kube-apiserver 와 통신kubectl get pods --server my-kube-playground:6443 --client-key admin.key --client-certificate admin.crt --certificate-authority ca.crt# kubeconfig 설정과 kubectl 로 kube-apiserver 와 통신kubectl get pods --kubeconfig config
curl 또는 kubectl 로 kube-apiserver 와 통신할 때 사실 위와 같이 인증 관련 옵션들을 지정해줘야 하는데 이를 간편하게 kubeconfig 로 설정해줄 수 있다. $HOME/.kube/config 경로를 기본값으로 사용하기 때문에 여태껏 제외하고 사용 가능했던 것이다.
Service Accounts
default ServiceAccount
k get saNAME SECRETS AGEdefault 1 1dk describe sa defaultName: defaultNamespace: default...k describe pod my-podName: my-podNamespace: defaultPriority: 0Service Account: default...
ServiceAccount 는 Pod 가 kube-apiserver 에 인증할 수 있도록 자격 증명을 제공하는 namespace 범위 리소스다. 기본적으로 각 namespace 마다 default ServiceAccount 가 자동으로 생성된다. Pod 가 이 ServiceAccount 를 사용하려면, ServiceAccount Token 이 필요하다. namespace 에 Pod 가 생성될 때 마다 생성된 ServiceAccount 와 Token 이 자동으로 볼륨에 마운팅된다.
ServiceAccount
kubectl create serviceaccount dashboard-sa
apiVersion: v1kind: ServiceAccountmetadata: name: dashboard-sa namespace: defaultautomountServiceAccountToken: false # Token 자동 마운트 여부 제어
kubectl 또는 YAML 파일로 작성하여 생성할 수 있다.
Pod 에 ServiceAccount 연결하기
apiVersion: v1kind: Podmetadata: name: my-kubernetes-dashboardspec: containers: - name: my-kubernetes-dashboard image: my-kubernetes-dashboard serviceAccountName: dashboard-sa # Pod 가 사용할 ServiceAccount 지정 automountServiceAccountToken: false # Token 자동 마운트 여부 제어
Pod 가 ServiceAccount 를 사용하도록 연결하는 과정에서 ServiceAccount Token 이 Pod 내부 /var/run/secrets/kubernetes.io/serviceaccount/token 경로에 자동으로 마운트되어 kube-apiserver 와 통신할 수 있다. 별도로 지정하지 않는 경우, default ServiceAccount 가 자동 할당된다. 즉, 명시하지 않아도 기본 SA 를 사용하게 된다. 자동으로 ServiceAccount Token 이 자동으로 마운트하지 않도록 spec.automountServiceAccountToken 을 설정할 수 있다.
ServiceAccount Token
ServiceAccount Token 은 JWT 형식으로 발급된다. ServiceAccount 가 TokenRequestAPI 로 부터 Token 을 받아오는 방식으로 작동한다. Token 안에는 ServiceAccount 이름, namespace, 발급 시각, 만료 시각 등의 정보가 담겨 있다. Pod 내부의 Application 이 이 Token 을 HTTP 요청의 Authorization 헤더에 담아 kube-apiserver 로 보내면, kube-apiserver 는 해당 Token 이 유효한지 검사하고, RBAC 규칙에 따라 권한을 부여한다. ServiceAccount Token 의 종류는 아래와 같다.
1. TokenRequest API 기반 (권장)
짧게 쓰고 사라지는 임시 토큰 (기본 유효기간: 1시간)
만료되면 자동으로 새 토큰 발급, 보안에 유리
Pod 삭제 시 토큰도 함께 소멸
최신 쿠버네티스에서 기본값으로 사용
2. 수동 Secret 방식 (비권장)
kubernetes.io/service-account-token 타입의 Secret 으로 생성
만료되지 않는 영구 토큰, 보안에 취약
유출될 경우 kube-apiserver 에 무기한 접근 가능
3. 바인딩 토큰
토큰 안에 특정 Pod, Node, Secret 정보가 들어있음
해당 리소스에 묶여 있어서 다른 곳에서 사용하면 인증 실패
TokenReview API 로 유효성 확인 가능
Authorization
K8s 에 대한 작업을 위해 curl 이나 kubectl 로 요청을 보내면 kube-apiserver 에서 제공하는 API 에서 요청을 처리하게 된다. 이 때 K8s Object 에 대한 작업들을 API Group 으로 나뉘게 되는데, /apis 엔드포인트 기준으로 아래와 같은 API Group 이 존재한다.
/apps/v1/deployments
/apps/v1/replicasets
/apps/v1/statefulsets
/extensions
/networking.k8s.io
/storage.k8s.io
/authentication.k8s.io
/certificates.k8s.io
K8s 는 위와 같은 다양한 Resource 에 대한 작업의 권한을 위해 아래와 같은 방법을 사용한다.
Node Authorization
kubelet 의 경우 Certificate 에 명시된 system:node:node01 이라는 이름을 통해 Node Authorization 방식으로 kube-apiserver 와 통신할 수 있다.
ABAC, Attribute-Based Access Controls
각 유저마다 Policy 를 적용해서 허용 가능한 요청들을 지정할 수 있다.
RBAC, Role-Based Access Controls
Policy 를 Role 로 생성해 유저들이 Role 을 기반으로 요청할 수 있도록 한다.
kube-apiserver 를 실행할 때 --authorization-mode 옵션을 통해 적용할 Authorization Mechanism 을 지정해줄 수 있다. 위와 같이 설정해 줄 경우, Node Authorization 을 시도하고 실패하면 RBAC, 그리고 Webhook 순으로 권한을 확인한다.
RBAC, Role-Based Access Controls
Role
apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata: name: developerrules:- apiGroups: [""] # "" indicates the core API group resources: ["pods"] verbs: ["get", "update", "create"] resourceNames: ["blue", "orange"]- apiGroups: [""] resources: ["ConfigMap"] verbs: ["create"]
Role 이 생성되는 namespace 내에서 무엇을 어떻게 할 수 있을지 정의한다. namespace 를 지정해주지 않을 경우 default namespace 로 설정된다.
RoleBinding
apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: devuser-developer-bindingsubjects:- kind: User name: dev-user # "name" is case sensitive apiGroup: rbac.authorization.k8s.io- kind: ServiceAccount name: dev-sa # "name" is case sensitive apiGroup: rbac.authorization.k8s.ioroleRef: kind: Role name: developer apiGroup: rbac.authorization.k8s.io
RoleBinding 을 통해 해당 namespace 의 Role 을 특정 사용자에 연결하여 RBAC 을 적용할 수 있다.
kubectl get roleskubectl get rolebindingskubectl describe role developerkubectl describe rolebinding devuser-developer-binding
Role 과 RoleBinding 모두 K8s Object 이기 때문에 위 명령어들로 조회가 가능하다.
K8s 에서 Pod Definition File 로 Private Registry 를 이용하려면 Image 의 전체경로와 Private Registry 에 로그인하기 위한 Secret 를 연동해줘야 한다.
Security Contexts
Docker Security
Docker Container 는 기본적으로 호스트의 Process 로써 실행되고 Linux namespace 를 통해 격리된다.
docker run --user=1000 ubuntu sleep 3600
Docker Container 는 기본적으로 root user 로 실행되기 때문에 Container 를 실행할 때 --user 옵션을 통해 root user 권한을 제한할 수 있다.
docker run ubuntu
Docker Container 는 mac_admin, broadcast, net_admin, sys_admin 등 호스트에 영향을 줄 수 있는 Capability 들이 제한된다. 모든 Capability 는 /usr/include/linux/capability.h 에서 확인할 수 있다.
docker run --cap-add MAC_ADMIN ubuntudocker run --cap-drop KILL ubuntudocker run --privillege ubuntu
K8s Pod 에서도 마찬가지로 user 의 권한을 securityContext 를 통해 제어할 수 있다. Container 레벨에 선언된 securityContext 는 해당 Container 의 권한을 제어하고, Pod 레벨에 선언된 securityContext 는 Pod 내 모든 Container 의 권한을 제어한다.