Security Primitives in K8s
기본적인 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가 주로 나옴
kube-apiserver : 모든 요청과 통제를 담당하는 컴포넌트. 따라서 이 컴포넌트의 보안이 제일 중요함
- 누가 접근할 수 있는가?
- 무엇을 어디까지 통제할 수 있게 할 것인가?
가 핵심.
Who can Access의 경우... Authentication Mechanism 기반 동작. 여러 방법이 있음.
- username / password
- username + token
- Certificates
- External Auth provider ex) LDAP
- Service Account
What they can Do는 Authorization 기반으로 동작한다.
- Rule-based Access Control (RBAC) : 사용자를 특정 권한이 있는 group 단위로 묶어서 처리하는 방식
- Attribute based Access Control (ABAC)
- Node Authorization
- Webhook
- 등등...
클러스터 간 이루어지는 통신 - kube-apiserver와 etcd 클러스터, kube-apiserver와 controller manager / worker node에 있는 kubelet과 kube-apiserver 간 통신 등등 - 은 TLS Encryption based로 이루어지고 있다.
- 각각의 컴포넌트가 통신하기 위한 Certificate를 어떻게 생성하고 관리하는지... 깊게 다룰 예정.
클러스터 내 애플리케이션 간 통신은?
- 기본적으로는 pod와 다른 pod는 제한없이 통신할 수 있다.
- Network Policy를 설정해서 pod 간 통신을 제한할 수 있음.
Authentication
클러스터에서 사용자에게 필요한 권한은 대략 다음과 같은 것들이 있다.
- 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.
이들이 정상적으로 사용할 수 있도록
- Secure Cluster by communication btwn internal component
- Securing Management Access to the cluster through Authorization / Authentication
Application End User -> 애플리케이션 레벨에서 처리 가능하므로 논의에서 제외
- k8s는 사용자 (user) 를 직접 관리하는 형태가 아니다. 대부분 외부 소스에 의존해서 user를 정의하는데
- file system with user & details
- certificate
- 3rd party Identity Service (LDAP 같은)
- 따라서, kubectl create user 같은 동작은 실행될 수 없다.
- ServiceAccount는 k8s에서 관리하는 리소스 중 하나. 따라서 CRUD가 가능하다.
User
- 기본적으로 kube-apiserver에서 관리함. kubectl을 사용하거나 api에 직접 접근하거나..
- apiserver는 요청을 수행하기 전에 Authentication을 수행한다.
Authentication 방법은 크게 네 가지.
- Static Password file
- Static Token file
- Certificates
- Identity Service (LDAP)
File의 경우
- 강의의 예시 : Password, userName, userId가 각각 csv column으로 있는 값.
- --basic-auth-file=user-details.csv 옵션을 kube-apiservice.service 에 추가하는 식
- 옵션을 적용하려면 service restart가 필요하다.
- kubeadm을 사용할 경우 kube-apiserver가 정의된 pod yaml 파일에서 옵션을 변경해야 한다. 파일이 변경되면 자동으로 kube-apiserver가 재시작된다.
- user 정보를 kube-apiserver에서 curl로 직접 호출할 수도 있음.
물론 이렇게 암호화 없이 평문으로 저장하는 것은 권장사항이 아님. 1.19 이후 deprecated됐다.
- 만약 static file을 사용한다면, kubeadm으로 세팅할 때 volume mount를 붙이는 것도 생각해볼만 하다.
TLS Basics
- Certificate: 두 사용자 간 transaction에서 데이터는 암호화되었고, 서버는 호출한 곳의 신원을 믿을 수 있다는 걸 증명하는 장치.
- 데이터를 전송할 때 plain text 대신 encrypted 값을 전달한다.
- Symmetric Encryption : 암호화와 복호화에 동일한 key를 사용함. key를 클라이언트와 서버가 서로 전송하면서 사용하다가 탈취당할 경우 보안 이슈가 있다.
- Asymmetric Encryption : 암호화와 복호화에 사용되는 Key가 서로 다른 경우. private key - public lock으로 비유할 수 있다.
간단한 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로 접근하게 만들 수 있다.
asymmetric encryption의 동작과정
- 서버에서 openssl로 private key / public key pair를 생성한다.
- 클라이언트가 서버에 https로 요청하면, 서버는 public key를 포함해서 클라이언트에 전달한다.
- 해커가 예컨대 이 값을 탈취했다고 가정한다.
- 사용자 (보통 이 경우 브라우저)는 자신의 symmetric key를 서버가 제공한 public key를 토대로 암호화한 뒤, 요청을 서버로 전달한다.
- 예컨대 이 값도 해커가 탈취했다고 가정한다.
- 서버는 private key를 가지고 있으므로, 자신의 public key를 decrypt한 뒤 클라이언트가 보낸 symmetric key를 사용할 수 있다.
- 해커는 서버의 public key, 클라이언트가 public key로 암호화한 요청을 가지고 있지만, 해독할 방벙이 없다.
- 클라이언트와 서버는 보관한 symmetric key로 암호화한 정보를 보안 걱정 없이 교환할 수 있다. 탈취해도 해커가 해독할 방법이 없기 때문.
물론, 해커가 가짜 페이지를 만들어서 symmetric key를 제공하도록 유도할 수도 있다.
- 그래서 보통 서버가 public key를 보낼 때, 자신의 존재를 증명할 수 있는 certificate를 첨부한다.
- 해당 certificate를 누가 발급했는지 -> 존재 증명에 사용함
- = who signed / issued this?
- 혼자 생성한 경우 = self-signed certificate. Not Safe.
- 보통 이런 종류의 validation은 브라우저에서 체크함
위와 같은 방식으로 Trusted Authority에게 인증서를 인가받을 수 있다.
- openssl 로 인증서 생성하고 검증 요청을 보냄
- 업체에서 검증
- 검증 후 verified. (가짜 certificate의 경우 여기서 not verified.)
인증서 발급업체는 스스로를 self-signed한 인증서를 가지고 있고, 인증에 사용하는 private key / public key (lock) 가 있음.
- 브라우저는 인증된 업체들의 기본 public key를 가지고 있다. validate 가능함.
- private service에서 필요할 경우 private CA를 활용한다.
- public key : *.crt / *.pem 형태의 확장자
- private key : *.key, *-key.pem 형태의 확장자
TLS in Kubernetes
public / private key를 사용해서 server의 connectivity 관리... = Serving Certificate.
k8s에서의 TLS 통신은 크게 두 가지가 있디.
- 노드와 노드, pod과 pod 사이의 통신 (service to service 통신)
- 외부 admin 사용자의 interaction with kube-apiserver.
따라서 server / client 각각 certificate를 토대로 서로의 존재를 인증하며 통신한다.
Server Side
- kube-apiserver: 여러 클라이언트와 https로 통신하기 위한 certificate 필요.
- etcd server: cluster 관련 정보 저장
- kubelete servcer: worker node와 통신하기 위해 사용함.
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를 생성해 사용할 수도 있다.
따라서, 각 컴포넌트별로 certificate가 필요하다. 꽤 많이 필요함. 따라서 이 certificate를 인가하고 관리할 CA의 존재가 필요하다.
- k8s에서는 최소 하나 이상의 CA가 있는 것을 권장하고 있다. 둘 이상을 사용할 경우, etcd cluster를 별도의 CA로 관리하는 편.
- 강의에서는 단일 CA를 전제로 진행. CA 고유의 key pair (certification / private key)
TLS in K8s - Certification creation
CA Certificate 세팅
- ca.key를 생성하는 명령어
openssl genrsa -out ca.key 2048
- 생성한 key값을 토대로 signing request 생성
openssl req -new -key ca.key -subj "/CN=KUBERNETES-CA" -out ca.csr
- signature 빼고 다 있는 certificate라고 보면 됨.
- kubernetes CA 목적으로 생성하므로 이름을 kubernetes-ca 로 지었다.
- sign it.
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
Generate Client Certificate.
- 생성방식은 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는 패스워드에 대응됨. 평문으로 생성하는 것보다 보안상 안전하다는 차이만 있을 뿐
admin user를 위한 crt과 key를 생성한 상태. 그렇다면 이걸 일반 사용자와 구분할 수 있는 기준은?
- -> adding group details for the user in the certificate.
- signing request에서 group 정보를 입력하는 걸로 생성 가능.
/O=system:master
옵션이 해당 기능을 의미함.
위 자료사진들처럼 group 이름을 지정하고, 해당 그룹별로 권한을 부여하는 식의 작업이 가능하다.
- 이렇게 만들어진 crt, key를 사용해서 kube-apiserver를 호출할 수 있다.
- curl로 직접 호출하거나 / kubeConfig 으로 certificate / key 파일을 정의해 두고 사용할 수 있음.
cf. 웹에서 통신할 때에는 클라이언트(브라우저) '서버의 응답을 검증할 목적' 으로 CA certificate를 검증한다고 했다.
- k8s에서도 마찬가지로 동작해야 하므로, 서버 / 클라이언트 관계없이 각 component는 CA의 root certificate를 보유하고 있다.
ETCD 서버
- multiple cluster를 사용하므로, 클러스터 간 통신에도 TLS 기반 암호화 통신이 필요함. -> Peer Certificate 생성.
- 위와 같은 명령어로 peer certificate 옵션을 클러스터에 넣어줄 수 있다.
- 색칠된 부분은 Root Certificate 옵션이 표기된 것. 해당 클러스터가 valid하다는 증거로 Root CA가 포함되어야 한다.
kube-apiserver
- k8s 내에서 가장 많이 쓰이는 컴포넌트. 따라서 이름 / alias 개수가 많은 편이 일반적이다.
- 해당 pod가 실행중인 ip주소 / kubernetes.default.svc.cluster.local 까지 다양한 방식의 호출에도 전부 응답해야 하므로
- 위에 서술된 이름 / ip주소로 오는 연결은 전부 apiserver에서 오는 거라고 인증한 것.
- 옵션을 보면, kube-apiserver가 가장 연결할 영역이 많으므로 ca 옵션값도 제일 많다.
- etcd에 사용할 ca 파일 / key
- kubelet 연결에 사용할 crt / key
- 클라이언트의 ca.pem과 apiserver에서 사용할 crt / key
Kubelet
- kubelet의 certificate에서 각 crt에서 확인할 수 있는 이름은 '노드 이름' 이다. 각 노드 이름으로 crt를 발급받는다.
- Root CA certificate를 설정하고, 각 kubelet 노드에서 사용할 crt / key를 kubelet-config.yaml에 저장해 사용한다.
kubelet의 경우 노드명으로 certificate를 생성하는데, kube-apiserver에서 authenticate 용도로 사용함.
- kube-apiserver는 노드 단위로 authenticate / permission을 부여하기 때문에 kubelet은 노드 단위로 certificate를 생성해야 한다.
- admin과 마찬가지로 권한 부여의 기준은 group. system:nodes 이름을 붙여줘야 한다.
View Certificate Details
누군가가 '클러스터의 TLS Certificate가 정상인지 확인해 달라' 라는 요청을 했다고 가정한다.
- 이 문제를 해결하기 위해서는 k8s 클러스터가 어떤 식으로 배포되었는지부터 알아야 함
- 직접 배포하는 hard way -> 직접 수정하면서 하나하나 만들어야 함
- kubeadm 같은 tool 사용 시 -> yaml 파일에 pod 형태로 생성된 걸 변경하면 됨.
1. kube-apiServer 확인.
가장 많은 crt가 연결되어 있으므로, 필요한 것을 확인할 가능성이 높다. 필요한 정보를 저장해둔다.
확인해야 할 점
- Subject : CN=kube-apiserver 로 이름 확인
- Alternative name : 이 인증서를 사용할 수 있는 도메인, ip주소 확인
- Not After : expire date
- Issuer : CA를 의미함. CN=kubernetes (itself)
- service에서 직접 Log 조회하기 :
journalctl -u etcd.service -l
. etcd service의 로그를 조회할 수 있다. - kubeadm으로 설정해서 pod로 떠 있을 경우 :
kubectl logs etcd-master
로 로그 조회 가능.
만약 etcd 서버나 kubectl을 관리하는 kube-apiserver가 다운되었을 경우... kubectl이 동작하지 않는다.
- 따라서 docker log로 직접 조회해야 한다.
docker ps -a
명령어로 컨테이너를 확인하고, 해당 컨테이너에서 로그를 체크해야 함
Certificate API
admin권한을 받은 파란 user 말고, 빨간 user의 경우...
- 처음에 접근권한이 없을 때에는 파란 user의 admin을 거쳐서 certificate를 확보한다.
- expire되고 나면 다시 파란 user의 도움을 받아 생성하는 절차를 반복한다.
여기서 파란 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 인 셈.
이전까지는 certificate request를 수동으로 직접 보냈지만, 사용자 수가 많아지면 이것도 자동화가 필요함.
- Create CertificateSigningRequest Object
- Request 확인
- 요청 승인
- Share Certificate back to User
- key 생성
- request 생성
- csr을 CertificateSigningRequest 객체로 변환하기 위해 csr.yaml 파일을 생성한다.
- 이 때, csr 본문에 들어 있는 값은 base64로 인코딩한 후 본문의 requests 필드에 넣는다.
kubectl get csr
명령어로 certificate request를 확인할 수 있다.- 승인은
kubectl approve
- 승인한 결과는 status.certificate에서 볼 수 있다.
- 해당 값은 base64로 인코딩된 값이기 때문에, base64 디코딩해서 원본을 확인할 수 있음.
- plain text로 변환한 certificate를 사용할 수 있다.
그러면, 이 많은 작업은 누가 담당하는가?
- Controller Manager가 담당한다. 내부 컴포넌트에 csr-approving, csr-signing이 있음.
- 내부를 확인해보면 root ca의 key, crt를 사용하는 걸 볼 수 있다.
KubeConfig
kube-apiserver에서 클라이언트가 자신을 증명하는 방법으로는 아래와 같이 두 가지 방법이 있다.
- curl로 --key, --cert, --cacert 옵션에 값을 입력하기.
kubectl get <resourceName> --server ... --client-key ... --client-certificate ... --certificate-authority ca.crt
kubectl 명령어에서 일일이 이걸 타이핑하는 게 귀찮기 때문에, kubeconfig라는 별도의 파일을 만들어서 관리하고 있다.
kubectl get pods --kubeconfig config
형태로 사용 가능함- 디폴트로는
$HOME/.kube/config
경로에서 config 값을 찾기 때문에 --kubeconfig 옵션을 넣지 않음.
kubeconfig 파일 구조
- cluster: 어떤 cluster에서 사용될 수 있는가
- user : 어떤 사용자들이 있는가
- context : cluster와 user를 매핑. 연결하는 역할 (which account user used to access with cluster)
kubeconfig의 특징은 '연결'이다. 새로운 사용자를 생성하거나 권한을 설정하는 게 아니라, 해당 cluster라는 환경에 user를 매핑하는 것.
- 어떤 cluster에 어떤 사용자가 접근할 것인지 결정하는 역할.
- kubeconfig의 context가 있다면, 매번 사용자가 certificate / server address를 가지고 통신할 필요가 없다.
- kubeconfig 형식에 맞게 필드 값을 입력하면 된다. cert / key값도 필요한 필드에 추가해준다.
- 이 방식으로, 여러 클러스터 + 여러 사용자 + 여러 context를 하나의 config 파일에 정의해서 사용할 수 있다.
- 매번 cert / key를 정의하거나 설정하지 않아도, kubectl에서 지정된 경로에 있는 kubeconfig 파일을 참조해서 접근권한을 얻어내기 때문.
kubectl은 어떤 context를 선택해야 하는지 어떻게 알고 있는가?
- current-context 필드를 사용함. 별다른 옵션이 없을 때 기본 context값이 무엇인지 결정한다.
- 만약 다른 context를 사용해야 하면
kubectl config use-context prod-user@production
을 명령어로 사용하는 식.
- 특정 namespace를 디폴트 옵션으로도 설정할 수 있다. contexts 필드에 namespace를 입력해두면, 해당 namespace를 기본으로 설정함.
- certificate 파일은 이왕이면 full path로 기록하는 것이 좋고,
- path 대신 value 자체를 넣는 방법도 있다. 이 경우 base64로 인코딩된 값을 넣어야 한다.
'학습일지 > kubernetes' 카테고리의 다른 글
CKA 대비 kubernetes 스터디 - 7. Storage (0) | 2022.04.02 |
---|---|
CKA 대비 kubernetes 스터디 - 6. Security (2) (0) | 2022.03.30 |
CKA 대비 kubernetes 스터디 - 5. Cluster Maintenance (0) | 2022.03.14 |
CKA 대비 kubernetes 스터디 - 4. Application LifeCycle Management (0) | 2022.03.09 |
헷갈리니까 확실히 알고 쓰자! Docker의 Entrypoint, cmd와 k8s의 command, args 비교하기 (0) | 2022.03.05 |