공부하고 기록하는, 경제학과 출신 개발자의 노트

학습일지/kubernetes

CKA 대비 kubernetes 스터디 - 6. Security (1)

inspirit941 2022. 3. 25. 18:51
반응형

Security Primitives in K8s

스크린샷 2022-03-15 오전 6 53 24

기본적인 cluster의 security 옵션

  • access to these hosts must be secured.
  • root access disabled
  • password based Authentication 사용하지 않음
  • SSH key-based authentication 사용.
  • 기타 k8s가 올라가있는 VM / PM 자체의 Security.

시험에서는 k8s 내부 리소스에 관련된 Security가 주로 나옴

 

스크린샷 2022-03-15 오전 8 40 41

kube-apiserver : 모든 요청과 통제를 담당하는 컴포넌트. 따라서 이 컴포넌트의 보안이 제일 중요함

  • 누가 접근할 수 있는가?
  • 무엇을 어디까지 통제할 수 있게 할 것인가?

가 핵심.

스크린샷 2022-03-15 오전 9 06 57

Who can Access의 경우... Authentication Mechanism 기반 동작. 여러 방법이 있음.

  • username / password
  • username + token
  • Certificates
  • External Auth provider ex) LDAP
  • Service Account

 

스크린샷 2022-03-15 오전 9 10 28

What they can Do는 Authorization 기반으로 동작한다.

  • Rule-based Access Control (RBAC) : 사용자를 특정 권한이 있는 group 단위로 묶어서 처리하는 방식
  • Attribute based Access Control (ABAC)
  • Node Authorization
  • Webhook
  • 등등...

 

스크린샷 2022-03-15 오전 9 12 34

클러스터 간 이루어지는 통신 - kube-apiserver와 etcd 클러스터, kube-apiserver와 controller manager / worker node에 있는 kubelet과 kube-apiserver 간 통신 등등 - 은 TLS Encryption based로 이루어지고 있다.

  • 각각의 컴포넌트가 통신하기 위한 Certificate를 어떻게 생성하고 관리하는지... 깊게 다룰 예정.

 

스크린샷 2022-03-15 오전 9 14 56

클러스터 내 애플리케이션 간 통신은?

  • 기본적으로는 pod와 다른 pod는 제한없이 통신할 수 있다.
  • Network Policy를 설정해서 pod 간 통신을 제한할 수 있음.

Authentication

스크린샷 2022-03-15 오전 9 18 04

클러스터에서 사용자에게 필요한 권한은 대략 다음과 같은 것들이 있다.

  • Admin : access the cluster to perform Administrative Task
  • Developer : access to the cluster to test / deploy application
  • End User : access the Application deployed on the cluster.
  • 3rd Party Applcation : access the cluster for integration purpose.

이들이 정상적으로 사용할 수 있도록

  1. Secure Cluster by communication btwn internal component
  2. Securing Management Access to the cluster through Authorization / Authentication

Application End User -> 애플리케이션 레벨에서 처리 가능하므로 논의에서 제외

 

스크린샷 2022-03-15 오후 1 42 51

  • k8s는 사용자 (user) 를 직접 관리하는 형태가 아니다. 대부분 외부 소스에 의존해서 user를 정의하는데
    • file system with user & details
    • certificate
    • 3rd party Identity Service (LDAP 같은)
    • 따라서, kubectl create user 같은 동작은 실행될 수 없다.
  • ServiceAccount는 k8s에서 관리하는 리소스 중 하나. 따라서 CRUD가 가능하다.

 

스크린샷 2022-03-15 오후 1 50 06

User

  • 기본적으로 kube-apiserver에서 관리함. kubectl을 사용하거나 api에 직접 접근하거나..
  • apiserver는 요청을 수행하기 전에 Authentication을 수행한다.

 

스크린샷 2022-03-15 오후 1 55 02

Authentication 방법은 크게 네 가지.

  • Static Password file
  • Static Token file
  • Certificates
  • Identity Service (LDAP)

 

스크린샷 2022-03-16 오전 5 42 16

File의 경우

  • 강의의 예시 : Password, userName, userId가 각각 csv column으로 있는 값.
  • --basic-auth-file=user-details.csv 옵션을 kube-apiservice.service 에 추가하는 식
  • 옵션을 적용하려면 service restart가 필요하다.

 

스크린샷 2022-03-16 오전 5 47 13스크린샷 2022-03-16 오전 5 48 09

  • kubeadm을 사용할 경우 kube-apiserver가 정의된 pod yaml 파일에서 옵션을 변경해야 한다. 파일이 변경되면 자동으로 kube-apiserver가 재시작된다.
  • user 정보를 kube-apiserver에서 curl로 직접 호출할 수도 있음.

스크린샷 2022-03-16 오전 6 26 03

물론 이렇게 암호화 없이 평문으로 저장하는 것은 권장사항이 아님. 1.19 이후 deprecated됐다.

  • 만약 static file을 사용한다면, kubeadm으로 세팅할 때 volume mount를 붙이는 것도 생각해볼만 하다.

TLS Basics

스크린샷 2022-03-16 오전 6 38 55

  • Certificate: 두 사용자 간 transaction에서 데이터는 암호화되었고, 서버는 호출한 곳의 신원을 믿을 수 있다는 걸 증명하는 장치.
    • 데이터를 전송할 때 plain text 대신 encrypted 값을 전달한다.
  • Symmetric Encryption : 암호화와 복호화에 동일한 key를 사용함. key를 클라이언트와 서버가 서로 전송하면서 사용하다가 탈취당할 경우 보안 이슈가 있다.
  • Asymmetric Encryption : 암호화와 복호화에 사용되는 Key가 서로 다른 경우. private key - public lock으로 비유할 수 있다.

 

스크린샷 2022-03-16 오전 7 21 37

 

스크린샷 2022-03-16 오전 7 29 34

간단한 asymmetric key pair 사용예시

  • 사용자는 ssh-keygen으로 private key / public lock을 생성한다.
  • private key로만 접근하고 싶은 서버의 .ssh/authorized_key 에 public lock에 해당하는 id_rsa.pub 을 등록한다.
  • ssh -i id_rsa user1@server1 형태로 접근 가능하며, 여러 서버에도 동일한 방식으로 lock을 걸고 private key로 접근하게 만들 수 있다.

 

스크린샷 2022-03-16 오전 7 39 23

asymmetric encryption의 동작과정

  • 서버에서 openssl로 private key / public key pair를 생성한다.
  • 클라이언트가 서버에 https로 요청하면, 서버는 public key를 포함해서 클라이언트에 전달한다.
    • 해커가 예컨대 이 값을 탈취했다고 가정한다.
  • 사용자 (보통 이 경우 브라우저)는 자신의 symmetric key를 서버가 제공한 public key를 토대로 암호화한 뒤, 요청을 서버로 전달한다.
    • 예컨대 이 값도 해커가 탈취했다고 가정한다.

 

스크린샷 2022-03-16 오전 7 46 49스크린샷 2022-03-16 오전 7 49 14

  • 서버는 private key를 가지고 있으므로, 자신의 public key를 decrypt한 뒤 클라이언트가 보낸 symmetric key를 사용할 수 있다.
  • 해커는 서버의 public key, 클라이언트가 public key로 암호화한 요청을 가지고 있지만, 해독할 방벙이 없다.
  • 클라이언트와 서버는 보관한 symmetric key로 암호화한 정보를 보안 걱정 없이 교환할 수 있다. 탈취해도 해커가 해독할 방법이 없기 때문.

물론, 해커가 가짜 페이지를 만들어서 symmetric key를 제공하도록 유도할 수도 있다.

 

스크린샷 2022-03-16 오전 8 49 48스크린샷 2022-03-16 오전 8 51 38

  • 그래서 보통 서버가 public key를 보낼 때, 자신의 존재를 증명할 수 있는 certificate를 첨부한다.
  • 해당 certificate를 누가 발급했는지 -> 존재 증명에 사용함
  • = who signed / issued this?
    • 혼자 생성한 경우 = self-signed certificate. Not Safe.
    • 보통 이런 종류의 validation은 브라우저에서 체크함

 

스크린샷 2022-03-16 오전 10 09 54

위와 같은 방식으로 Trusted Authority에게 인증서를 인가받을 수 있다.

  • openssl 로 인증서 생성하고 검증 요청을 보냄
  • 업체에서 검증
  • 검증 후 verified. (가짜 certificate의 경우 여기서 not verified.)

인증서 발급업체는 스스로를 self-signed한 인증서를 가지고 있고, 인증에 사용하는 private key / public key (lock) 가 있음.

  • 브라우저는 인증된 업체들의 기본 public key를 가지고 있다. validate 가능함.
  • private service에서 필요할 경우 private CA를 활용한다.

스크린샷 2022-03-16 오전 10 35 29

  • public key : *.crt / *.pem 형태의 확장자
  • private key : *.key, *-key.pem 형태의 확장자

TLS in Kubernetes

스크린샷 2022-03-16 오후 12 33 13

public / private key를 사용해서 server의 connectivity 관리... = Serving Certificate.

 

스크린샷 2022-03-16 오후 3 28 39

k8s에서의 TLS 통신은 크게 두 가지가 있디.

  • 노드와 노드, pod과 pod 사이의 통신 (service to service 통신)
  • 외부 admin 사용자의 interaction with kube-apiserver.

따라서 server / client 각각 certificate를 토대로 서로의 존재를 인증하며 통신한다.

 

스크린샷 2022-03-16 오후 9 26 52

Server Side

  • kube-apiserver: 여러 클라이언트와 https로 통신하기 위한 certificate 필요.
  • etcd server: cluster 관련 정보 저장
  • kubelete servcer: worker node와 통신하기 위해 사용함.

 

스크린샷 2022-03-16 오후 9 32 49

Client Side

  • kube-apiserver와 통신하는 클라이언트
    • admin User (사용자). kubectl 형태로 명령어를 요청함
    • kube-scheduler. worker node에 제대로 Pod scheduling할 수 있도록
    • kube controller manager
    • kube-proxy
  • etcd, kubelet과 통신하는 클라이언트 자격으로서의 kube-apiserver.
    • 필요할 경우, 이들과 통신하기 위한 목적으로 kube-apiserver에서 별개의 certificate를 생성해 사용할 수도 있다.

 

스크린샷 2022-03-16 오후 9 36 51

따라서, 각 컴포넌트별로 certificate가 필요하다. 꽤 많이 필요함. 따라서 이 certificate를 인가하고 관리할 CA의 존재가 필요하다.

  • k8s에서는 최소 하나 이상의 CA가 있는 것을 권장하고 있다. 둘 이상을 사용할 경우, etcd cluster를 별도의 CA로 관리하는 편.
  • 강의에서는 단일 CA를 전제로 진행. CA 고유의 key pair (certification / private key)

TLS in K8s - Certification creation

 

스크린샷 2022-03-16 오후 10 45 56

CA Certificate 세팅

  1. ca.key를 생성하는 명령어 openssl genrsa -out ca.key 2048
  2. 생성한 key값을 토대로 signing request 생성 openssl req -new -key ca.key -subj "/CN=KUBERNETES-CA" -out ca.csr
    • signature 빼고 다 있는 certificate라고 보면 됨.
    • kubernetes CA 목적으로 생성하므로 이름을 kubernetes-ca 로 지었다.
  3. sign it. openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt

Generate Client Certificate.

 

스크린샷 2022-03-16 오후 10 48 29

  • 생성방식은 CA에서 처음 key / csr 생성한 것과 비슷하다.
    • certificate request 명령어에서 정의하는 이름 (위 예시의 경우 kube-admin) -> 요청을 받은 쪽에서 authenticate하기 위한 핵심정보. audit log 등에서 계속 확인하게 될 이름이므로 이름에서 유추 가능하도록 관련있는 이름으로 생성해야 한다.
  • 마지막 signing에서 자기 자신의 key 대신 ca.crt와 ca.key를 사용하는 것이 차이점.
    • openssl x509 -req -in admin.csr -CA ca.crt -CAkey ca.key -out admin.crt

일반적인 사용자 생성 과정과 유사하다. certificate가 userId 생성하는 것과 비슷하고, key는 패스워드에 대응됨. 평문으로 생성하는 것보다 보안상 안전하다는 차이만 있을 뿐

 

스크린샷 2022-03-17 오전 10 13 38

admin user를 위한 crt과 key를 생성한 상태. 그렇다면 이걸 일반 사용자와 구분할 수 있는 기준은?

  • -> adding group details for the user in the certificate.
  • signing request에서 group 정보를 입력하는 걸로 생성 가능. /O=system:master 옵션이 해당 기능을 의미함.

 

스크린샷 2022-03-17 오전 10 15 49

 

스크린샷 2022-03-17 오전 10 15 43

위 자료사진들처럼 group 이름을 지정하고, 해당 그룹별로 권한을 부여하는 식의 작업이 가능하다.

 

스크린샷 2022-03-17 오전 10 50 24

  • 이렇게 만들어진 crt, key를 사용해서 kube-apiserver를 호출할 수 있다.
  • curl로 직접 호출하거나 / kubeConfig 으로 certificate / key 파일을 정의해 두고 사용할 수 있음.

 

스크린샷 2022-03-17 오전 10 53 42

cf. 웹에서 통신할 때에는 클라이언트(브라우저) '서버의 응답을 검증할 목적' 으로 CA certificate를 검증한다고 했다.

  • k8s에서도 마찬가지로 동작해야 하므로, 서버 / 클라이언트 관계없이 각 component는 CA의 root certificate를 보유하고 있다.

ETCD 서버

스크린샷 2022-03-17 오후 12 06 59

  • multiple cluster를 사용하므로, 클러스터 간 통신에도 TLS 기반 암호화 통신이 필요함. -> Peer Certificate 생성.

 

스크린샷 2022-03-17 오후 1 19 13

  • 위와 같은 명령어로 peer certificate 옵션을 클러스터에 넣어줄 수 있다.
  • 색칠된 부분은 Root Certificate 옵션이 표기된 것. 해당 클러스터가 valid하다는 증거로 Root CA가 포함되어야 한다.

kube-apiserver

스크린샷 2022-03-17 오후 1 39 09스크린샷 2022-03-17 오후 1 44 11

  • k8s 내에서 가장 많이 쓰이는 컴포넌트. 따라서 이름 / alias 개수가 많은 편이 일반적이다.
    • 해당 pod가 실행중인 ip주소 / kubernetes.default.svc.cluster.local 까지 다양한 방식의 호출에도 전부 응답해야 하므로
    • 위에 서술된 이름 / ip주소로 오는 연결은 전부 apiserver에서 오는 거라고 인증한 것.

스크린샷 2022-03-17 오후 1 45 18

  • 옵션을 보면, kube-apiserver가 가장 연결할 영역이 많으므로 ca 옵션값도 제일 많다.
    • etcd에 사용할 ca 파일 / key
    • kubelet 연결에 사용할 crt / key
    • 클라이언트의 ca.pem과 apiserver에서 사용할 crt / key

 

Kubelet

스크린샷 2022-03-17 오후 1 49 42

  • kubelet의 certificate에서 각 crt에서 확인할 수 있는 이름은 '노드 이름' 이다. 각 노드 이름으로 crt를 발급받는다.
  • Root CA certificate를 설정하고, 각 kubelet 노드에서 사용할 crt / key를 kubelet-config.yaml에 저장해 사용한다.

 

스크린샷 2022-03-17 오후 5 17 06

kubelet의 경우 노드명으로 certificate를 생성하는데, kube-apiserver에서 authenticate 용도로 사용함.

  • kube-apiserver는 노드 단위로 authenticate / permission을 부여하기 때문에 kubelet은 노드 단위로 certificate를 생성해야 한다.
  • admin과 마찬가지로 권한 부여의 기준은 group. system:nodes 이름을 붙여줘야 한다.

View Certificate Details

스크린샷 2022-03-17 오후 5 24 12

누군가가 '클러스터의 TLS Certificate가 정상인지 확인해 달라' 라는 요청을 했다고 가정한다.

  • 이 문제를 해결하기 위해서는 k8s 클러스터가 어떤 식으로 배포되었는지부터 알아야 함
    • 직접 배포하는 hard way -> 직접 수정하면서 하나하나 만들어야 함
    • kubeadm 같은 tool 사용 시 -> yaml 파일에 pod 형태로 생성된 걸 변경하면 됨.

1. kube-apiServer 확인.

스크린샷 2022-03-17 오후 5 26 13

가장 많은 crt가 연결되어 있으므로, 필요한 것을 확인할 가능성이 높다. 필요한 정보를 저장해둔다.

 

스크린샷 2022-03-17 오후 5 51 39

확인해야 할 점

  • Subject : CN=kube-apiserver 로 이름 확인
  • Alternative name : 이 인증서를 사용할 수 있는 도메인, ip주소 확인
  • Not After : expire date
  • Issuer : CA를 의미함. CN=kubernetes (itself)

스크린샷 2022-03-17 오후 5 54 12

 

스크린샷 2022-03-17 오후 6 06 21스크린샷 2022-03-17 오후 6 08 55

  • service에서 직접 Log 조회하기 : journalctl -u etcd.service -l . etcd service의 로그를 조회할 수 있다.
  • kubeadm으로 설정해서 pod로 떠 있을 경우 : kubectl logs etcd-master 로 로그 조회 가능.

 

스크린샷 2022-03-17 오후 6 11 14스크린샷 2022-03-17 오후 6 11 31

만약 etcd 서버나 kubectl을 관리하는 kube-apiserver가 다운되었을 경우... kubectl이 동작하지 않는다.

  • 따라서 docker log로 직접 조회해야 한다.
  • docker ps -a 명령어로 컨테이너를 확인하고, 해당 컨테이너에서 로그를 체크해야 함

Certificate API

스크린샷 2022-03-17 오후 6 24 51

admin권한을 받은 파란 user 말고, 빨간 user의 경우...

  • 처음에 접근권한이 없을 때에는 파란 user의 admin을 거쳐서 certificate를 확보한다.
  • expire되고 나면 다시 파란 user의 도움을 받아 생성하는 절차를 반복한다.

스크린샷 2022-03-17 오후 7 01 46

여기서 파란 user는 root CA에 접근이 가능하며, root CA를 통해서 crt를 발급받을 수 있다.

  • 즉, root CA에 접근할 수 있는 누구라도 k8s 리소스에 접근가능한 crt를 발급할 수 있다는 뜻.
  • create user whatever they want / whatever privileges they want.

따라서 이 파일들은 safe environment / protected and stored 인 서버 한 대에만 존재한다.

  • kubeadm의 경우 master node가 이 역할을 담당한다. master node = CA Server 인 셈.

 

스크린샷 2022-03-17 오후 7 12 29

이전까지는 certificate request를 수동으로 직접 보냈지만, 사용자 수가 많아지면 이것도 자동화가 필요함.

  • Create CertificateSigningRequest Object
  • Request 확인
  • 요청 승인
  • Share Certificate back to User

 

스크린샷 2022-03-17 오후 7 22 03

  • key 생성
  • request 생성

 

스크린샷 2022-03-17 오후 7 23 31

  • csr을 CertificateSigningRequest 객체로 변환하기 위해 csr.yaml 파일을 생성한다.
  • 이 때, csr 본문에 들어 있는 값은 base64로 인코딩한 후 본문의 requests 필드에 넣는다.

스크린샷 2022-03-17 오후 7 30 23

  • kubectl get csr 명령어로 certificate request를 확인할 수 있다.
  • 승인은 kubectl approve

 

스크린샷 2022-03-17 오후 7 31 23

  • 승인한 결과는 status.certificate에서 볼 수 있다.
  • 해당 값은 base64로 인코딩된 값이기 때문에, base64 디코딩해서 원본을 확인할 수 있음.
  • plain text로 변환한 certificate를 사용할 수 있다.

그러면, 이 많은 작업은 누가 담당하는가?

스크린샷 2022-03-17 오후 7 33 23

  • Controller Manager가 담당한다. 내부 컴포넌트에 csr-approving, csr-signing이 있음.
  • 내부를 확인해보면 root ca의 key, crt를 사용하는 걸 볼 수 있다.

 

스크린샷 2022-03-17 오후 7 34 23

KubeConfig

스크린샷 2022-03-17 오후 7 53 18

kube-apiserver에서 클라이언트가 자신을 증명하는 방법으로는 아래와 같이 두 가지 방법이 있다.

  • curl로 --key, --cert, --cacert 옵션에 값을 입력하기.
  • kubectl get <resourceName> --server ... --client-key ... --client-certificate ... --certificate-authority ca.crt

 

스크린샷 2022-03-17 오후 7 53 58

kubectl 명령어에서 일일이 이걸 타이핑하는 게 귀찮기 때문에, kubeconfig라는 별도의 파일을 만들어서 관리하고 있다.

  • kubectl get pods --kubeconfig config 형태로 사용 가능함
  • 디폴트로는 $HOME/.kube/config 경로에서 config 값을 찾기 때문에 --kubeconfig 옵션을 넣지 않음.

kubeconfig 파일 구조

 

스크린샷 2022-03-17 오후 8 11 58

  1. cluster: 어떤 cluster에서 사용될 수 있는가
  2. user : 어떤 사용자들이 있는가
  3. context : cluster와 user를 매핑. 연결하는 역할 (which account user used to access with cluster)

 

스크린샷 2022-03-17 오후 8 15 32

kubeconfig의 특징은 '연결'이다. 새로운 사용자를 생성하거나 권한을 설정하는 게 아니라, 해당 cluster라는 환경에 user를 매핑하는 것.

  • 어떤 cluster에 어떤 사용자가 접근할 것인지 결정하는 역할.
  • kubeconfig의 context가 있다면, 매번 사용자가 certificate / server address를 가지고 통신할 필요가 없다.
  • kubeconfig 형식에 맞게 필드 값을 입력하면 된다. cert / key값도 필요한 필드에 추가해준다.

 

스크린샷 2022-03-17 오후 8 15 41

  • 이 방식으로, 여러 클러스터 + 여러 사용자 + 여러 context를 하나의 config 파일에 정의해서 사용할 수 있다.
  • 매번 cert / key를 정의하거나 설정하지 않아도, kubectl에서 지정된 경로에 있는 kubeconfig 파일을 참조해서 접근권한을 얻어내기 때문.

kubectl은 어떤 context를 선택해야 하는지 어떻게 알고 있는가?

스크린샷 2022-03-17 오후 8 19 19

  • current-context 필드를 사용함. 별다른 옵션이 없을 때 기본 context값이 무엇인지 결정한다.

 

스크린샷 2022-03-17 오후 8 19 43

  • 만약 다른 context를 사용해야 하면 kubectl config use-context prod-user@production 을 명령어로 사용하는 식.

 

스크린샷 2022-03-17 오후 8 22 26

  • 특정 namespace를 디폴트 옵션으로도 설정할 수 있다. contexts 필드에 namespace를 입력해두면, 해당 namespace를 기본으로 설정함.

 

스크린샷 2022-03-17 오후 8 23 47

  • certificate 파일은 이왕이면 full path로 기록하는 것이 좋고,
  • path 대신 value 자체를 넣는 방법도 있다. 이 경우 base64로 인코딩된 값을 넣어야 한다.

스크린샷 2022-03-17 오후 8 24 32

반응형