어그리게이션 레이어 구성하기
어그리게이션 레이어 구성하기
어그리게이션 레이어를 구성하면 쿠버네티스 apiserver를 핵심 쿠버네티스 API가 아닌 추가 API로 확장할 수 있어요.
출처: 문서
본문
시작하기 전에
환경에서 어그리게이션 레이어가 동작하도록 프록시와 확장 apiserver 사이의 상호 TLS 인증을 지원하려면 몇 가지 설정 요구 사항이 있어요. 쿠버네티스와 kube-apiserver는 CA가 여러 개이므로, 프록시가 쿠버네티스 일반 CA 같은 다른 CA가 아니라 어그리게이션 레이어 CA로 서명되었는지 확인하세요.
서로 다른 클라이언트 유형에 같은 CA를 재사용하면 클러스터 기능에 부정적인 영향을 줄 수 있어요. 자세한 내용은 CA 재사용과 충돌을 참고하세요.
인증 흐름
CRD(Custom Resource Definition)와 달리 Aggregation API는 표준 쿠버네티스 apiserver 외에 또 다른 서버, 즉 확장 apiserver를 포함해요. 쿠버네티스 apiserver는 여러분의 확장 apiserver와 통신해야 하고, 확장 apiserver는 쿠버네티스 apiserver와 통신해야 합니다. 이 통신을 안전하게 하기 위해 쿠버네티스 apiserver는 x509 인증서를 사용해 확장 apiserver에 자신을 인증해요.
이 절에서는 인증·인가 흐름이 어떻게 동작하는지, 그리고 어떻게 구성하는지 설명합니다.
개괄적인 흐름은 다음과 같아요:
- 쿠버네티스 apiserver: 요청 사용자를 인증하고 요청된 API 경로에 대한 권한을 인가한다.
- 쿠버네티스 apiserver: 요청을 확장 apiserver로 프록시한다.
- 확장 apiserver: 쿠버네티스 apiserver의 요청을 인증한다.
- 확장 apiserver: 원래 사용자의 요청을 인가한다.
- 확장 apiserver: 실행한다.
이 절의 나머지에서는 이 단계들을 자세히 설명해요. 흐름은 다음 다이어그램에서 볼 수 있습니다.

인증 흐름을 정리하면 다음과 같아요.
- 사용자는 인식된 자격 증명(예: OIDC 또는 클라이언트 인증서)으로 Kube API 서버에 요청을 보낸다.
- Kube API 서버는 구성된 인증 방법(예: OIDC 또는 클라이언트 인증서)으로 들어오는 요청을 인증한다.
- Kube API 서버는 구성된 인가 방법(예: RBAC)으로 요청된 URL을 인가한다.
- 어그리게이터는
--proxy-client-cert-file/--proxy-client-key-file클라이언트 인증서·키로 채널을 보호하며 어그리게이션된 API 서버에 연결을 연다. - 어그리게이터는 1단계의 사용자 정보를 다음 플래그가 정의하는 http 헤더로 어그리게이션된 API 서버에 보낸다:
--requestheader-username-headers,--requestheader-group-headers,--requestheader-extra-headers-prefix. - 어그리게이션된 apiserver는 인증 프록시 인증 방법으로 들어오는 요청을 인증한다: 요청이 인식된 인증 프록시 클라이언트 인증서를 가졌는지 검증하고, 들어오는 요청의 http 헤더에서 사용자 정보를 가져온다.
기본적으로 이 구성 정보는 kube-apiserver가 발행하는 kube-system 네임스페이스의 configmap에서 가져오며, kube-apiserver에 제공된
--requestheader-...플래그의 정보(사용할 CA 번들, 허용할 인증 프록시 클라이언트 인증서 이름, 사용할 http 헤더 이름 등)를 담고 있다. - 어그리게이션된 apiserver는 kube-apiserver에 SubjectAccessReview 호출을 해 들어오는 요청을 인가한다.
- 변경 요청의 경우 어그리게이션된 apiserver는 어드미션 검사를 실행한다. 기본적으로 네임스페이스 라이프사이클 어드미션 플러그인이 네임스페이스 리소스가 kube-apiserver에 존재하는 네임스페이스에서 생성되도록 보장한다.
쿠버네티스 Apiserver 인증과 인가
확장 apiserver가 서비스하는 API 경로로의 요청은 모든 API 요청과 같은 방식으로 시작돼요. 즉 쿠버네티스 apiserver와의 통신으로 시작됩니다. 이 경로는 확장 apiserver가 쿠버네티스 apiserver에 이미 등록해 두었어요.
사용자는 쿠버네티스 apiserver와 통신하며 그 경로에 대한 접근을 요청해요. 쿠버네티스 apiserver는 쿠버네티스 apiserver에 구성된 표준 인증·인가를 사용해 사용자를 인증하고 특정 경로에 대한 접근을 인가합니다.
쿠버네티스 클러스터에 인증하는 방법의 개요는 "클러스터에 인증하기"를, 쿠버네티스 클러스터 리소스 접근 인가 개요는 "인가 개요"를 참고하세요.
이 시점까지는 모두 표준 쿠버네티스 API 요청·인증·인가예요.
이제 쿠버네티스 apiserver는 요청을 확장 apiserver로 보낼 준비가 되었어요.
쿠버네티스 Apiserver가 요청을 프록시
쿠버네티스 apiserver는 이제 요청을 처리하도록 등록된 확장 apiserver로 요청을 보내거나 프록시해요. 그러려면 몇 가지를 알아야 합니다:
- 쿠버네티스 apiserver가 확장 apiserver에 어떻게 인증해야 하며, 네트워크로 오는 요청이 유효한 쿠버네티스 apiserver에서 온 것임을 확장 apiserver에 어떻게 알려줄까?
- 쿠버네티스 apiserver가 원래 요청이 인증된 사용자 이름과 그룹을 확장 apiserver에 어떻게 알려줄까?
이 두 가지를 제공하려면 여러 플래그로 쿠버네티스 apiserver를 구성해야 해요.
쿠버네티스 Apiserver 클라이언트 인증
쿠버네티스 apiserver는 TLS로 확장 apiserver에 연결하고, 클라이언트 인증서로 자신을 인증해요. 시작 시 다음 플래그를 사용해 쿠버네티스 apiserver에 다음을 제공해야 합니다:
--proxy-client-key-file로 개인 키 파일--proxy-client-cert-file로 서명된 클라이언트 인증서 파일--requestheader-client-ca-file로 클라이언트 인증서 파일에 서명한 CA의 인증서--requestheader-allowed-names로 서명된 클라이언트 인증서의 유효한 Common Name(CN) 값
쿠버네티스 apiserver는 --proxy-client-*-file이 가리키는 파일을 사용해 확장 apiserver에 인증해요. 규격을 준수하는 확장 apiserver가 요청을 유효하다고 간주하려면 다음 조건이 충족되어야 합니다:
- 연결이
--requestheader-client-ca-file에 있는 CA가 서명한 클라이언트 인증서로 이뤄져야 한다. - 연결이
--requestheader-allowed-names에 나열된 것 중 하나인 CN을 가진 클라이언트 인증서로 이뤄져야 한다.
이 옵션을 --requestheader-allowed-names=""처럼 비워 둘 수 있어요. 이러면 어떤 CN도 허용된다는 것을 확장 apiserver에 알려줍니다.
이 옵션들로 시작하면 쿠버네티스 apiserver는:
- 이들을 사용해 확장 apiserver에 인증한다.
kube-system네임스페이스에extension-apiserver-authentication이라는 configmap을 만들어 CA 인증서와 허용된 CN을 넣는다. 확장 apiserver는 이들을 가져와 요청을 검증할 수 있다.
같은 클라이언트 인증서가 쿠버네티스 apiserver에 의해 모든 확장 apiserver에 대해 인증에 사용된다는 점을 유의하세요. 확장 apiserver마다 클라이언트 인증서를 만들지 않고, 쿠버네티스 apiserver로 인증하는 단일 인증서를 만들어 모든 확장 apiserver 요청에 재사용합니다.
원래 요청의 사용자 이름과 그룹
쿠버네티스 apiserver가 요청을 확장 apiserver로 프록시할 때, 원래 요청이 성공적으로 인증된 사용자 이름과 그룹을 확장 apiserver에 알려줘요. 이 정보를 프록시 요청의 http 헤더로 제공합니다. 사용할 헤더 이름을 쿠버네티스 apiserver에 알려줘야 해요.
- 사용자 이름을 저장할 헤더는
--requestheader-username-headers - 그룹을 저장할 헤더는
--requestheader-group-headers - 모든 추가 헤더에 붙일 접두사는
--requestheader-extra-headers-prefix
이 헤더 이름도 extension-apiserver-authentication configmap에 들어가서, 확장 apiserver가 가져와 사용할 수 있어요.
확장 Apiserver가 요청을 인증
확장 apiserver는 쿠버네티스 apiserver에서 프록시된 요청을 받으면, 그 요청이 실제로 유효한 인증 프록시(쿠버네티스 apiserver가 수행하는 역할)에서 왔는지 검증해야 해요. 확장 apiserver는 다음을 통해 검증합니다:
- 위에서 설명한 대로
kube-system의 configmap에서 다음을 가져온다: 클라이언트 CA 인증서, 허용된 이름(CN) 목록, 사용자 이름·그룹·추가 정보용 헤더 이름. - TLS 연결이 다음을 충족하는 클라이언트 인증서로 인증되었는지 확인한다: 가져온 CA 인증서와 일치하는 CA가 서명한 것, 목록이 비어 있지 않으면 허용된 CN 목록에 있는 CN을 가진 것(비어 있으면 모든 CN 허용). 적절한 헤더에서 사용자 이름과 그룹을 추출한다.
위 검사가 통과하면 요청은 합법적인 인증 프록시(여기서는 쿠버네티스 apiserver)에서 온 유효한 프록시 요청입니다.
위 제공은 확장 apiserver 구현의 책임이라는 점을 유의하세요. 많은 구현이 k8s.io/apiserver/ 패키지를 활용해 기본적으로 제공하고, 다른 구현은 명령줄 옵션으로 재정의할 수 있는 옵션을 제공할 수 있어요.
configmap을 가져올 권한을 얻으려면 확장 apiserver에 적절한 역할이 필요해요. kube-system 네임스페이스에 할당할 수 있는 extension-apiserver-authentication-reader라는 기본 역할이 있습니다.
확장 Apiserver가 요청을 인가
이제 확장 apiserver는 헤더에서 가져온 사용자·그룹이 주어진 요청을 실행할 권한이 있는지 검증할 수 있어요. 이를 위해 쿠버네티스 apiserver에 표준 SubjectAccessReview 요청을 보냅니다.
확장 apiserver가 스스로 쿠버네티스 apiserver에 SubjectAccessReview 요청을 제출할 권한을 가지려면 올바른 권한이 필요해요. 쿠버네티스는 적절한 권한을 가진 system:auth-delegator라는 기본 ClusterRole을 포함하며, 이를 확장 apiserver의 서비스 어카운트에 부여할 수 있어요.
확장 Apiserver가 실행
SubjectAccessReview가 통과하면 확장 apiserver가 요청을 실행해요.
쿠버네티스 Apiserver 플래그 활성화하기
다음 kube-apiserver 플래그로 어그리게이션 레이어를 활성화해요. 이미 제공자가 처리했을 수도 있습니다.
--requestheader-client-ca-file=<path to aggregator CA cert>
--requestheader-allowed-names=front-proxy-client
--requestheader-extra-headers-prefix=X-Remote-Extra-
--requestheader-group-headers=X-Remote-Group
--requestheader-username-headers=X-Remote-User
--proxy-client-cert-file=<path to aggregator proxy cert>
--proxy-client-key-file=<path to aggregator proxy key>
CA 재사용과 충돌
쿠버네티스 apiserver에는 두 가지 클라이언트 CA 옵션이 있어요:
--client-ca-file--requestheader-client-ca-file
각각은 독립적으로 동작하며, 올바르게 사용하지 않으면 서로 충돌할 수 있어요.
--client-ca-file: 쿠버네티스 apiserver에 요청이 도착하면, 이 옵션이 활성화돼 있다면 apiserver는 요청의 인증서를 확인한다. 인증서가--client-ca-file이 참조하는 파일의 CA 인증서 중 하나로 서명되었다면 요청은 합법적인 요청으로 취급되고, 사용자는 common nameCN=의 값, 그룹은 조직O=가 된다. TLS 인증 문서를 참고하세요.--requestheader-client-ca-file: 쿠버네티스 apiserver에 요청이 도착하면, 이 옵션이 활성화돼 있다면 apiserver는 요청의 인증서를 확인한다. 인증서가--requestheader-client-ca-file이 참조하는 파일의 CA 인증서 중 하나로 서명되었다면 요청은 잠재적으로 합법적인 요청으로 취급된다. 쿠버네티스 apiserver는 common nameCN=이--requestheader-allowed-names가 제공한 목록의 이름 중 하나인지 확인한다. 이름이 허용되면 승인되고, 그렇지 않으면 승인되지 않는다.
둘 다 --client-ca-file과 --requestheader-client-ca-file이 제공되면, 요청은 먼저 --requestheader-client-ca-file CA를 확인하고 그다음 --client-ca-file을 확인해요. 보통 각 옵션에 루트 CA나 중간 CA 중 서로 다른 CA가 사용됩니다. 일반 클라이언트 요청은 --client-ca-file과 대조하고, 어그리게이션 요청은 --requestheader-client-ca-file과 대조해요. 하지만 둘 다 같은 CA를 사용하면, 보통 --client-ca-file로 통과하던 클라이언트 요청이 실패할 수 있어요. 왜냐하면 CA가 --requestheader-client-ca-file의 CA와 일치하지만 common name CN=이 --requestheader-allowed-names의 허용 가능한 common name 중 하나와 일치하지 않기 때문입니다. 이로 인해 kubelet과 다른 컨트롤 플레인 구성 요소뿐 아니라 최종 사용자도 쿠버네티스 apiserver에 인증하지 못할 수 있어요.
이런 이유로 컨트롤 플레인 구성 요소와 최종 사용자를 인가하는 --client-ca-file 옵션과, 어그리게이션 apiserver 요청을 인가하는 --requestheader-client-ca-file 옵션에 서로 다른 CA 인증서를 사용하세요.
위험과 CA 사용을 보호하는 메커니즘을 이해하지 않는 한, 다른 컨텍스트에서 사용되는 CA를 재사용하지 마세요.
API 서버를 실행하는 호스트에서 kube-proxy를 실행하지 않는다면, 시스템이 다음 kube-apiserver 플래그로 활성화되어 있는지 확인해야 해요:
--enable-aggregator-routing=true
APIService 오브젝트 등록하기
어떤 클라이언트 요청이 확장 apiserver로 프록시될지 동적으로 구성할 수 있어요. 다음은 등록 예시입니다:
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: <name of the registration object>
spec:
group: <API group name this extension apiserver hosts>
version: <API version this extension apiserver hosts>
groupPriorityMinimum: <priority this APIService for this group, see API documentation>
versionPriority: <prioritizes ordering of this version within a group, see API documentation>
service:
namespace: <namespace of the extension apiserver service>
name: <name of the extension apiserver service>
caBundle: <pem encoded ca cert that signs the server cert used by the webhook>
APIService 오브젝트의 이름은 유효한 경로 세그먼트 이름이어야 해요.
확장 apiserver에 연결하기
쿠버네티스 apiserver가 요청을 확장 apiserver로 보내야 한다고 판단하면 어떻게 연결할지 알아야 해요.
service 항목은 확장 apiserver의 service에 대한 참조예요. service 네임스페이스와 이름은 필수이고, 포트는 선택 사항이며 기본값은 443입니다.
포트 "1234"로 호출되도록, 그리고 커스텀 CA 번들로 ServerName my-service-name.my-service-namespace.svc에 대해 TLS 연결을 검증하도록 구성된 확장 apiserver의 예시는 다음과 같아요:
apiVersion: apiregistration.k8s.io/v1
kind: APIService
...
spec:
...
service:
namespace: my-service-namespace
name: my-service-name
port: 1234
caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
...
더 알아보기 (Learn more)
- 어그리게이션 레이어와 함께 동작하도록 확장 api-server 설정하기.
- 높은 수준의 개요는 어그리게이션 레이어로 쿠버네티스 API 확장하기를 참고.
- Custom Resource Definitions로 쿠버네티스 API 확장하는 법 배우기.