kubernetes CKA study (18) - Security Primitives, Authentication, TLS Basics, Certificate Creation

이동명·2023년 12월 26일
0

kubernetes CKA study

목록 보기
18/37
post-thumbnail
post-custom-banner

Security Primitives

쿠버네티스의 원시적인 보안에 대해 살펴보자.

클러스터 자체를 형성하는 호스트부터 시작한다.
이런 호스트에 대한 모든 접근은 보안되어야 한다.
비밀번호 기반의 인증은 불가능해야 하고 SSH 키 기반의 인증만 가능해야 한다.

쿠버네티스 모든 작전의 중심에는 kube-api server가 있다.
kubectl 명령어나 API에 직접 접근함으로써 kube-api server와 상호작용할 수 있다.
그것을 통해 클러스터에서 거의 모든 작업을 수행할 수 있다. 이것이 1차 방어선이다.

kube-api server 자체에 대한 접근을 제어하는 것이다.
두 가지 유형에 대해 결정을 내려야 한다. 인증과 인가 개념이라고 이해하면 좋다.

  • 누가 클러스터에 접근할 수 있을까?

  • 그들이 무엇을 할 수 있을까?

누가 kube-api server에 접근할 수 있는지는 인증(authentication) 메커니즘에 의해 정의된다. kube-api server에 인증할 수 있는 다양한 방법이 있다.

그들이 무엇을 할 수 있는지는 권한 부여(authorization) 메커니즘에 의해 정의된다.

클러스터의 구성 요소 간의 모든 통신은 kubelet과 kube-proxy와 같이 작업자 노드에서 실행되는 건 TLS 암호화로 보안된다.

Authentication

쿠버네티스 클러스터는 다중 노드, 다양한 구성요소로 구성되어 있다.

  • 관리자 -> 관리 업무를 수행하기 위해 클러스터에 접근한다.

  • 개발자 -> 앱을 테스트/배포하기 위해 클러스터에 접근한다.

  • 최종 사용자 -> 클러스터에 배포된 응용 프로그램에 접근한다.

  • 타사 플그램 -> 통합 용도를 위해 클러스터에 접근한다.

최종 사용자의 보안은 응용 프로그램 자체에 의해 내부적으로 관리된다. 그러니 이 논의에서 제외한다.

쿠버네티스는 사용자 계정을 직접 관리하지 않는다. 그래서 사용자 세부 정보가 담긴 파일이나 인증서 또는 타사 ID 서비스와 같은 외부 소스에 의존한다.
그래서 쿠버네티스 클러스터에선 사용자를 생성할 수 없고 사용자 리스트도 볼 수 없다.

하지만 서비스 계정의 경우 쿠버네티스가 관리할 수 있다.
쿠버네티스 API를 이용해 서비스 계정을 생성하고 관리할 수 있으며 서비스 계정에 대한 독점적인 섹션도 있다.

모든 사용자의 접근은 kube-api server에 의해 관리된다.
kubectl 툴을 통해 클러스터에 접근하든 API를 직접 사용하든 상관없다.
모든 요청은 kube-api server로 간다. kube-api server는 요청을 처리하기 전에 먼저 인증을 한다.

고정 암호 파일, 고정 토큰 파일, 인증서, 타사 인증 프로토콜 등 다양한 인증 메커니즘이 있다.

고정 암호 파일의 경우, csv 파일에 사용자 목록과 암호를 만들 수 있다. 그리고 이것을 사용자 정보의 소스로 사용한다.
파일 이름을 kube-api server의 옵션으로 지정한 다음 kube-api server를 재시작해야 한다.

만약 클러스터를 kubeadm 도구를 사용해 설정했다면 kube-api server 파드 정의 파일을 수정해야 한다.

또는 사용자 및 암호를 '-u' 옵션을 통해 지정할 수 있다.

정적 토큰 파일의 경우, 옵션만 암호 파일과 다르게 설정해주면 된다.

고정 파일에 사용자 이름, 암호, 토큰을 저장하는 이 인증 메커니즘은 불안정하기 때문에 권장하지 않는다.

TLS Basics

인증서는 거래 도중 상호 신뢰를 보장하기 위해 사용된다.
가령, 사용자가 웹 서버에 접근하려고 할 때 TLS 인증서는 사용자와 서버 사이의 통신이 암호화되도록 한다.

대칭키 암호화(Symmetric Encryption)

  • 데이터를 암호화하고 해독하는 데 같은 키를 사용한다.

  • 키를 수신기와 교환해야 하기 때문에 해커가 키에 접근해 데이터를 해독할 위험이 있다.

비대칭키 암호화(Asymmetric Encryption)

  • 한 쌍의 키와 개인키, 공용키를 사용한다.
  • 개인키는 비공개되어있고 개인키로 데이터를 해독할 수 있다.
  • 공용키는 공개되어있고 다른 사람과 공유할 수 있다. 공용키로 데이터를 암호화할 수 있다.

앞서, 대칭키의 문제점은 데이터를 암호화하는 데 사용된 키가 암호화된 데이터 네트워크를 통해 서버로 전송되기 때문에 해커가 키를 입수해 데이터를 해독할 위험이 있다는 점이다.

그래서 대칭키를 옮기기 위해 비대칭키 암호화를 사용한다. 서버에 공용과 개인 키 쌍을 생성하는 것이다.

  • openssl 명령어를 이용해 개인키와 공용키 쌍을 생성한다.

  • 사용자가 https를 이용해 웹서버에 처음 접근하면 서버에서 공개 키를 받는다. 해커가 모든 네트워크를 엿보고 있으니 해커도 개인키와 공용키의 사본을 받았다고 가정하자.

  • 그럼 사용자의 브라우저가 서버가 제공한 공용키를 이용해 대칭키를 암호화한다.

  • 그리고 사용자는 공용키로 암호화된 대칭키를 서버로 보낸다. 해커도 사본을 받는다.

  • 서버는 개인 키로 메시지를 해독하고 대칭키를 회수한다. 해커에겐 암호를 해독할 개인키가 없고, 공개키만 갖고 있기 때문에 메시지에서 대칭키를 되찾을 수 없다.

  • 이제 클라이언트와 서버는 대칭키로 데이터를 암호화해서 서로에게 보낼 수 있다. 상대방은 암호화된 데이터를 대칭키를 통해 해독할 수 있다.

하지만 해커가 서버인척 악의적으로 비슷한 서버를 만들 수도 있다.
따라서, 서버에서 나온 합법적인 키인지 확인이 필요하다.
서버가 키를 보낼 때 키 대신 키를 가진 인증서를 보낸다.

하지만 이런 인증서는 누구나 만들 수 있다.
그래서, 인증서를 생성했다면 직접 '서명'해야한다.
브라우저는 서버에서 받은 인증서가 합법적인지 유효성을 확인하고 고정된 인증서라면 우리에게 경고를 준다.

그러면 웹 브라우저가 신뢰할만한 합법적인 웹 서버 인증서는 어떻게 만들어질까?
그래서 CA(Certificate Authority)가 나선다.

CA는 우리를 위해 인증서에 서명하고 유효성을 확인해주는 잘 알려진 기관이다.

먼저, 생성한 키와 우리의 웹사이트 도메인 이름을 이용해서 CSR(Certificate Signing Request) 파일을 생성한다. (openssl 명령어 사용) CSR 파일은 인증서 서명 요청으로, CA로 보내져 서명을 받아야 한다. 인증서 관계자가 상세 사항을 확인하고 일단 확인되면 인증서에 서명해서 다시 보내준다.

해커도 같은 방법으로 인증서에 서명을 받으려 하면 인증서 유효성 검사 단계에서 실패할 것이다.
그가 호스팅하는 웹사이트엔 유효한 인증서가 없기 때문에 회사가 인증서를 거부할 것이기 때문이다.

그러면 합법적인 CA가 서명했다는 것을 어떻게 알 수 있을까?

CA들은 개인키와 공용키 쌍을 갖고 있다. CA가 인증서에 서명할 때 개인키를 사용한다. 모든 CA의 공개키는 브라우저에 기본으로 제공되기 때문에 브라우저는 CA의 공개키를 이용해 CA가 직접 서명한 인증서임을 확인한다. -> 일반적인 개인키-공용키와 반대로 공용키가 암호 해독에 사용된다.

요약해보자.
메시지를 암호화하려면 공용키와 개인키로 비대칭 암호화를 해야 한다.

서버는 먼저 CA에 CSR(인증서 서명 요청)을 보낸다. CA는 개인키로 CSR에 서명한다. 모든 사용자는 CA의 공용키를 갖고 있다.
서명된 인증서는 서버로 다시 보내진다. 서버는 서명된 인증서로 웹 응용 프로그램을 구성한다.
사용자가 웹 응용 프로그램에 접근할 때마다 서버는 먼저 인증서(공개키)를 보낸다.
사용자, 정확히는 사용자의 브라우저가 인증서를 읽고 서버의 공개 키를 유효성 검사하고 회수하기 위해 CA의 공용키를 사용한다.
그런 다음 대칭키를 생성해 모든 통신에 사용하려고 한다. 대칭키는 서버의 공개키로 암호화되어 서버로 전송된다.
서버는 개인키로 메시지를 해독하고 대칭키를 회수한다.
대칭키는 앞으로 통신을 위해 사용된다.

관리자가 SSH 보안 키 쌍을 생성한다. 웹 서버는 HTTPS로 웹사이트를 보호할 키 쌍을 생성한다. 인증서 기관은 자체 관리자를 생성해 인증서에 서명한다.
하지만 최종 사용자는 단일 대칭키만 생성한다.

클라이언트는 서버의 유효성을 확인할 수 있지만 서버는 클라이언트인지 확실히 알 수 없다.
클라이언트가 진짜인지 확인하기 위해 서버는 클라이언트에게 인증서를 요청할 수 있다.
그래서 클라이언트는 한 쌍의 키와 유효한 CA로부터 서명된 인증서를 생성해야 한다. 그리고 클라이언트는 인증서를 서버로 보낸다.

이 전체 인프라는 PKI(Public Key Infrastructure)라 알려져 있다.

마지막으로 한 가지만 확실히 해두자.
공개키와 개인키는 연관이 있거나 짝을 이루는 키이다. 데이터 암호화와 해독은 하나의 키로 할 수 없다.
따라서 데이터를 암호화할 때는 신중해야 한다. 개인 키로 데이터를 암호화하면 공개 키를 가진 사람이 누구든 암호를 풀고 메시지를 읽을 수 있다.

공용키가 있는 인증서는 보통 .crt나 .pem 확장자를 갖는다.
개인키는 보통 .key나 -key.pem 확장자를 갖는다. 즉, 단어나 확장자에 'key'가 들어가는 것은 개인키이다.

TLS in Kubernetes - Certificate Creation

클러스터를 위한 인증서를 생성하기 위해 EASYRSA, OPENSSL, CFSSL 같은 다양한 도구들을 이용할 수 있다. 이번 강의에서는 OpenSSL 도구를 사용해 인증서를 생성한다.

인증서는 개인키 소유자의 공개키에 인증기관의 개인키로 전자서명한 데이터이다.

1단계. CA 구축

먼저 openssl genrsa 명령을 이용해 개인키(ca.key)를 생성한다.
그런 다음 openssl req 명령을 이용해 인증서서명요청(ca.csr)를 생성한다. 인증서 서명 요청에서 CN(Common Name) 필드에 이름을 지정한다.
마지막으로 openssl x509 명령을 이용해 인증서에 서명한다.

이것은 CA 자체에 대한 거라 첫 단계에서 생성된 개인키를 이용해 CA가 자체 서명했다.
다른 모든 인증서에서는 CA 키 쌍을 사용해서 서명할 것이다.

CA는 이제 개인키와 인증서 파일이 있다.

2단계. 클라이언트 인증서 생성

관리자의 클라이언트 인증서 생성 과정을 살펴보자.
먼저 openssl genrsa 명령을 이용해 개인키(admin.key)를 생성한다.
그런 다음 open req 명령을 이용해 인증서서명요청(admin.csr)을 생성해 관리자의 이름을 지정한다.
마지막으로 openssl x509를 사용해서 서명된 인증서를 생성한다. 이때 CA 인증서와 CA 개인키를 지정해야 한다. CA 개인키로 인증서에 서명한다.
이로써, 클러스터 내에 유효한 인증서(admin.crt)가 생성된다.

인증서와 개인키를 생성하는 이 과정은 새 사용자에 대한 사용자 계정을 만드는 것과 유사하다.
인증서는 유효한 사용자 ID이고 키는 암호와 같다. 인증서와 개인키는 단순한 사용자 이름과 암호보다 보안이 훨씬 더 철저하다.

이 관리자를 위한 인증서를 다른 인증서와 구분하기 위해 그룹 세부 정보를 추가해야한다.
쿠버네티스에서 관리 권한을 가진 system:masters라는 그룹이 있다. 즉, 인증서 서명 요청에서 반드시 'O'필드를 통해 그룹 세부 정보를 명시해야 한다.

클라이언트 인증서를 생성하는 과정은 모두 동일하다.

kube-scheduler는 시스템 구성 요소로 쿠버네티스 제어판의 일부이다.
그래서 이름 앞에 키워드 'SYSTEM'을 붙여야 한다.

kube-controller-manager도 시스템 구성 요소라서 이름 앞에 'SYSTEM'을 붙여야 한다.

위의 과정을 통해 다음과 같은 클라이언트 인증서를 생성할 수 있다.

  • kube-api server와 통신하기 위한 admin의 인증서와 개인키
  • kube-api server와 통신하기 위한 kube-scheduler의 인증서와 개인키
  • kube-api server와 통신하기 위한 kube-controller-manager의 인증서와 개인키
  • kube-api server와 통신하기 위한 kube-proxy의 인증서와 개인키

생성한 클라이언트 인증서는 kube-api server와의 REST API 통신에서 사용할 수 있다. 옵션을 통해 인증서와 키, ca를 명시한다.
다른 방법은 이 모든 매개변수를 kubeconfig 구성 파일에 명시하는 것이다. 구성 파일에 통신할 서버의 목적지 정보와 사용할 인증서 등을 지정해야 한다.

쿠버네티스에서도 구성 요소끼리 서로 확인하려면 CA의 루트 인증서 복사본이 필요하다. 서버나 클라이언트가 인증서를 갖고 구성할 때마다 CA 루트 인증서도 지정해야 한다.
아래 사진에서 쿠버네티스의 모든 구성 요소가 CA의 루트 인증서 복사본을 갖고 있는 것을 확인할 수 있다.

3단계. 서버 인증서 생성

ETCD 서버의 인증서 생성 과정을 살펴보자.
인증서를 생성하는 과정은 이전과 동일하다.
ETCD 서버는 고가용성 환경에서 다중 서버에 걸쳐 클러스터로 배포될 수 있다. 이 경우, 클러스터 내 다른 멤버들 간의 통신을 안전하게 하려면 추가 피어 인증서를 생성해야 한다.

키와 인증 파일 옵션, 피어 인증서, CA 루트 인증서 등을 지정할 수 있다.

kube-api server도 동일한 인증서 생성과정을 거친다.
클러스터 내의 모든 작업은 kube-api를 거친다. 클러스터 내 움직이는 모든 것을 kube-api server가 안다.
kube-api server가 kubernetes이다. kube-api server는 kubernetes, kubernetes.default, kubernetes.default.svc, kubernetes.default.svc.cluster.local 등으로 언급된다. 일부 장소에선 단순히 IP 주소로 언급되기도 한다.

kube-api server를 실행하는 호스트의 IP 주소나 그걸 실행하는 파드의 모든 이름은 반드시 kube api server를 위해 생성된 인증서에 존재해야 한다.
그래야만 kube-api server를 이런 이름으로 참조하는 이들이 유효한 연결을 설정할 수 있다.

kube-api server의 키를 생성하기 위해 아까와 같은 openssl genrsa 명령어를 사용한다.
인증서서명요청(csr)에서 kube-api server 이름을 지정한다.

하지만 kube-api server의 다른 이름은 어떻게 명시할까?

kube-api server의 다른 이름을 지정하기 위해 openssl.cnf 파일을 생성하고 대체 이름을 지정한다. 이 구성 파일을 인증서서명요청의 옵션으로 지정한다.

마지막으로 CA 인증서와 ca 개인키를 이용해 인증서에 서명한다.

ETCD와 kubelet 서버와 통신할 때 클라이언트로서 kube-api server가 필요하다. 이때 kube-api server의 클라이언트 인증서를 고려해야 한다.

앞에서 생성된 인증서의 위치는 kube-api server의 서비스 구성 파일로 전달된다.
첫째, CA 파일이 전달되어야 한다. 모든 구성 요소가 클라이언트를 확인하기 위해 CA 인증서를 필요로 하기 때문이다.
둘째, kube-api server의 인증서를 TLS 인증 옵션으로 제공해야 한다.
그런 다음 etcd server와 통신하기 위해 kube-api server에서 사용되는 클라이언트 인증서를 지정해 etcd server에 ca 파일로 다시 연결한다.
마지막으로 kubelet server와 통신하기 위해 kube-api server에서 사용되는 클라이언트 인증서를 지정해 kubelet server에 ca 파일로 다시 연결한다.

다음으로 kubelet server이다.
kubelet 서버는 HTTPS API 서버로 각 노드에서 실행되며 노드 관리를 책임진다.
kube-api server가 노드를 모니터하기 위해 kubelet과 통신하는 것이다. 또한 kube-api server는 kubelet 서버와 통신을 통해 그 노드에 어떤 파드가 스케줄될지에 대한 정보도 보낸다.

클러스터의 각 노드에 대해 인증서와 개인키 쌍이 필요하다.
각 노드에 대한 인증서와 개인키의 이름은 노드의 이름을 따서 짓는다.
인증서가 생성되면 kubeletConfiguration 정의 파일을 사용한다.
클러스터의 각 노드에서 kubeletConfigutaion을 생성해야 한다.

kube-api server과 어떤 노드가 인증하는지를 알아야 하고 올바른 사용 권한을 부야해야 한다.
따라서 노드는 형식에 올바른 이름을 갖춰야 한다. 노드는 시스템 구성요소이기 때문에 인증서의 이름은 'system:node:노드명' 형식을 따른다.

profile
Web Developer
post-custom-banner

0개의 댓글