쿠버네티스 인증방식에 대해서 알아보고, 쿠버네티스 클라이언트 라이브러리는 어떤방식으로 인증처리와 API 호출이 이루어지는지 확인해보자.

쿠버네티스 API server에 request 를 보내기 위해서는 인증 과정이 필요하다.
인증과정은 인증(authentication), 접근제어/인가(access control/authorization), 승인제어(admission control) 단계로 이루어진다.

쿠버네티스 사용자가 맞는지, 사용자가 이 작업을 수행해도 되는지, 이 요청이 적절한지를 확인하는 과정이다.
쿠버네티스 Authentication Strategies 은 클러스터 외부의 사용자에게 적용되는 인증방식과 파드 내부에서 실행되는 프로세스가 API에 접근할 때 사용하는 서비스 어카운트(ServiceAccount) 토큰을 이용한 인증으로 구분 해볼 수 있다.

서비스 어카운트(ServiceAccount) 토큰을 이용한 인증을 사용하기 위해서 확인한 내용을 정리했다.

쿠버네티스는 user account 와 service account를 구분한다.

Kubernetes distinguishes between the concept of a user account and a service account for a number of reasons:

  • User accounts are for humans. Service accounts are for processes, which run in pods.
  • User accounts are intended to be global. Names must be unique across all namespaces of a cluster, future user resource will not be namespaced. Service accounts are namespaced.
  • Typically, a cluster’s User accounts might be synced from a corporate database, where new user account creation requires special privileges and is tied to complex business processes. Service account creation is intended to be more lightweight, allowing cluster users to create service accounts for specific tasks (i.e. principle of least privilege).
  • Auditing considerations for humans and service accounts may differ.
  • A config bundle for a complex system may include definition of various service accounts for components of that system. Because service accounts can be created ad-hoc and have namespaced names, such config is portable.

https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/#user-accounts-versus-service-accounts

쿠버네티스는 사용자를 API로 직접 관리하지 않는다. 일반적으로 외부 사용자 ID관리 시스템으로 정의하고, 기존 시스템(AD, LDAP, …)을 활용할 수 있는 연결성만 제공한다.

인가모드 (authorization-mode)

쿠버네티스가 지원하는 인가모드는 AlwaysAllow, AlwaysDeny, ABAC, RBAC, Webhook, Node가 있다.

  • --authorization-mode=ABAC Attribute-Based Access Control (ABAC) mode allows you to configure policies using local files.
  • --authorization-mode=RBAC Role-based access control (RBAC) mode allows you to create and store policies using the Kubernetes API.
  • --authorization-mode=Webhook WebHook is an HTTP callback mode that allows you to manage authorization using a remote REST endpoint.
  • --authorization-mode=Node Node authorization is a special-purpose authorization mode that specifically authorizes API requests made by kubelets.
  • --authorization-mode=AlwaysDeny This flag blocks all requests. Use this flag only for testing.
  • --authorization-mode=AlwaysAllow This flag allows all requests. Use this flag only if you do not require authorization for your API requests

AlwaysDeny는 테스트 환경에만 적합하다. AlwaysAllow 모드는 API 요청에 대한 인증이 필요하지 않은 경우에만 사용한다.
쿠버네티스에서 가장 효과적인 모듈은 RBAC(Role Base Access Control) 이라고 한다.

kube-apiserver manifest 를 보면 authorization-mode를 확인할 수 있다.

1
2
3
4
5
6
7
> cat /etc/kubernetes/manifests/kube-apiserver.yaml
...
spec:
containers:
...
- --authorization-mode=Node,RBAC
...

일반적으로 사용하는 API 클라이언트 kubectl 의 API서버 요청 방식을 확인해보자.

1
2
3
4
5
6
7
8
[root@k8s-master ~]# kubectl -v=7 get po pod-1
.. 31065 loader.go:359] Config loaded from file: /root/.kube/config
.. 31065 round_trippers.go:416] GET https://172.16.10.20:6443/api/v1/namespaces/default/pods/pod-1
.. 31065 round_trippers.go:423] Request Headers:
.. 31065 round_trippers.go:426] Accept: application/json;as=Table;v=v1beta1;g=meta.k8s.io, application/json
.. 31065 round_trippers.go:426] User-Agent: kubectl/v1.15.5 (linux/amd64) kubernetes/20c265f
.. 31065 round_trippers.go:441] Response Status: 200 OK in 8 milliseconds
...
  1. 쿠버네티스 컨피그 파일 로드

    Config loaded from file: /root/.kube/config

    클러스터에 엑세스 하려면 클러스터의 위치정보를 알아야 하고, 클러스터에 접속하기 위한 인증정보를 가져야 한다.

    참고 https://kubernetes.io/ko/docs/tasks/access-application-cluster/access-cluster/

    ❯ kubectl config view

  1. 쿠버네티스 API 호출

    https://172.16.10.20:6443/api/v1/namespaces/default/pods/pod-1


ServiceAccount 토큰을 이용한 인증

일반적으로 ServiceAccount는 User가 아닌 파드(어플리케이션)가 API를 호출하기 위한 권한을 부여하기 위해서 사용한다.
ServiceAccounts는 모든 파드 리소스에 대한 네임스페이스 사용자 계정으로 생각할 수 있다.

파드(어플리케이션)가 API를 호출하기 위한 구조 설계해보기

serviceaccount-role-binding


  • Pod 의 경우 클러스터 전체에 대한 권한관리가 필요하기 때문에 ClusterRole을 생성해서 권한에 대한 정의를 하고, ServiceAccount와 함께 ClusterRoleBinding을 생성해서 바인딩 해주었다.

    • Role은 네임스페이스 단위, ClusterRole은 클러스터 전체에 대한 권한을 관리한다.
  • ServiceAccount를 정의하고, Pod 생성 시 spec에 지정 했다

    1
    2
    3
    4
      template:
    ...
    spec:
    serviceAccountName: 서비스어카운트명
    • 지정한 서비스어카운트의 인증정보(토큰)가 파드 생성 시 위치하게 된다.

      kube-system에 의해 파드는 서비스 어카운트와 연계되며 해당 서비스 어카운트의 인증정보(토큰)은 파드 내 각 컨테이너의 파일시스템 트리의 /var/run/secrets/kubernetes.io/serviceaccount/token에 위치한다.

      파드에서 API 액세스

    • Pod에 ServiceAccount가 정의되어 있지 않으면 Service Account Admission Controller에 의해 default ServiceAccount가 기본으로 설정된다.

      • Pod의 상세정보를 확인 해보면..

        1
        2
        3
        4
        5
        6
        ❯ kubectl describe pod/pod-1 -n default
        Name: pod-1
        Namespace: default
        ...
        Mounts:
        /var/run/secrets/kubernetes.io/serviceaccount from default-token-sln9r (ro)

참고

  • Namespace마다 default ServiceAccount가 생성된다.

    1
    2
    3
    ❯ kubectl get serviceaccounts -A
    NAMESPACE NAME SECRETS AGE
    default default 1 4d
  • 서비스 어카운트 개수 만큼 <ServiceAccount명>-token-xxxxx 으로 자동 생성된다.

    1
    2
    3
    ❯ kubectl get secrets -A
    NAMESPACE NAME
    default default-token-sln9r

보안관점에서는 쿠버네티스 API 접근을 파드에 제공하는 것에 대한 부적절한 시나리오가 많이 있다.

Kubernetes Client 라이브러리를 사용했을 때 인증 방식

쿠버네티스에서 지원하는 Python 기반의 라이브러리를 사용했을 때 어떤 방식으로 인증이 되고, API 서버에 호출까지 이루어지는지 확인해 보자.

관련 포스팅 : Docker Client와 Kubernetes Client 역할을 하는 API 서버를 구축할 수 있을까?

load_incluster_config

1
2
3
4
5
6
7
8
9
10
11
12
13
configuration = config.load_incluster_config()
...
def load_incluster_config():
"""
Use the service account kubernetes gives to pods to connect to kubernetes
cluster. It's intended for clients that expect to be running inside a pod
running on kubernetes. It will raise an exception if called from a process
not running in a kubernetes environment."""
InClusterConfigLoader(token_filename=SERVICE_TOKEN_FILENAME,
cert_filename=SERVICE_CERT_FILENAME).load_and_set()
...
SERVICE_TOKEN_FILENAME = "/var/run/secrets/kubernetes.io/serviceaccount/token"
SERVICE_CERT_FILENAME = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"

파드 내 각 컨테이너의 파일시스템 트리의 /var/run/secrets/kubernetes.io/serviceaccount/token에 위치한 토큰을 이용하여 인증한다.

load_kube_config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
config.load_kube_config()
...
def load_kube_config(config_file=None, context=None,
client_configuration=None,
persist_config=True):
"""Loads authentication and cluster information from kube-config file
and stores them in kubernetes.client.configuration.
"""

if config_file is None:
config_file = KUBE_CONFIG_DEFAULT_LOCATION

loader = _get_kube_config_loader_for_yaml_file(
config_file, active_context=context,
persist_config=persist_config)


...
KUBE_CONFIG_DEFAULT_LOCATION = os.environ.get('KUBECONFIG', '~/.kube/config')

kube-config 파일에서 인증 및 클러스터 정보를 로드해서 사용하는 방식

매니징 쿠버네티스, 쿠버네티스를 활용한 클라우드 네이티브 데브옵스, 쿠버네티스 공식 문서 를 보면서 참고하고 있다.