kubernetes api는 요청을 처리하기전에 다음의 단계를 거쳐 접근제어를 한다.
간단하게 이야기하면 (1)누구인지 확인하고, (2)접근권한이 있는지 확인하고, (3)현재 상황에서 요청한 작업을 허용할 것인지 판단하는 과정을 거치는 것이다. 3단계 과정중 인증(authentication)과 인가(authorization)은 일반적인 개념이고 kubernetes에서도 일반적으로 사용되는 X.509를 사용하여 사용자를 인증하고 인증된 사용자의 권한을 내부적으로 RBAC(role base access control)이나 ABAC(attrubute based access control)으로 정의해 둠으로써 요청에 대한 인가를 사용하고 있다. 이는 인증과 인가에서 매우 일반적인 내용으로 이들에 대한 설명은 다른 글의 내용들을 참조하자. 이 글에서는 kubernetes에서 접근제어를 위해 고도화된 기능으로 제공하는 Admission control에 대해 정리한다.
Admission control은 인증과 인가를 거친 요청에 대해 더 고도화된 판단을 통해 최종적으로 접근여부를 결정하기 위해 사용하는 단계이다. 아래 그림은 kubernetes api가 요청을 받아서 etcd에 기록하기까지 거치는 과정을 나타낸 것이다. 요청을 받으면 인증과 인가과정을 거친 후, 조정(Mutating admission), 객체의 정합성 체크, 유효성체크(Validating admission)의 단계를 거쳐 etcd에 기록하는데, 2단계의 admission이 있는 것에 주목하자. 이곳에 웹훅을 통해 원하는 기능을 추가할 수 있다.
kubernetes에서는 admission에 사용할 수 있는 다양한 플러그인을 제공하며 일반적인 예는 다음과 같다.
제공하는 전체 플러그인은 다음 링크를 통해 확인가능하다. (https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#what-does-each-admission-controller-do)
현재 나의 클러스터에서 어떤 플러그인을 사용하고 있는지 확인하는 방법은 다음과 같다.
siim@m1:~$ ps -ef | grep kube-apiserver
root 3219116 3218875 15 May03 ? 3-03:19:45 kube-apiserver --advertise-address=192.168.105.101 ... --enable-admission-plugins=NodeRestriction --enable-aggregator-routing=False ...
임의의 kubernetes-api가 동작하는 서버에서 실행한 예로 결과값에서 -enable-admission-plugins=NodeRestriction 가 지정되어 있는 것을 확인할 수 있다. 이에 대한 설명은 공식 페이지(https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction)에서 찾아볼 수 있으며 간단하게 kubelet이 노드에 지정된 내용을 삭제하거나 변경하지 못하도록 강제하는 기능을 하는 것이다. 같은 방식으로 자신이 사용하는 플러그인을 확인하고 상세내용까지 알수 있을 것이다.
이것에 대한 지정은 api서버를 띄우는 곳이 지정되어 있을 것이고 일반적인 경우라면 아래와 같이 ‘/etc/kubernetes/manifests/kube-apiserver.yaml’ 파일에 정의되어 있을 것이다. 수정이 필요하다면 ‘--enable-admission-plugins’ 부분에 필요한 플러그인을 넣어주면 된다. 상황에따라 적용이 안될수도 있으니 kube-apiserver.yaml 파일을 해당디렉토리에서 뺐다가 다시 넣어주면 더 확실하다. 이때 모든 api서버에 동일하게 적용해줘야 한다는 것에 유의하자.
siim@m1:~$ sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.168.105.101:6443
creationTimestamp: null
labels:
component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=192.168.105.101
...
- --enable-admission-plugins=NodeRestriction
- --enable-aggregator-routing=False
- --enable-bootstrap-token-auth=true
...
앞에서 확인한 플러그인뿐 아니라 API서버에 기본적으로 내포하고 있는 플러그인들이 존재하며 이는 kube-apiserver 바이너리의 도움말을 통해 구체적인 리스트를 확인할 수 있다.
siim@adm:~$ sudo docker run --rm -it k8s.gcr.io/kube-apiserver:v1.23.6 kube-apiserver -h | grep enable-admission-plugins --enable-admission-plugins strings admission plugins that should be enabled in addition to default enabled ones (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, PodSecurity, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota). Comma-delimited list of admission plugins: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyServiceExternalIPs, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodSecurity, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. The order of plugins in this flag does not matter.