개요
Secure host
kube-apiserver는 Kubernetes의 중심에 있으며, kubectl을 통해 접근할 수도 있고 직접 apiserver에 접근할 수도 있다. (apiserver에 대한 액세스를 제어하는 것이 1차 방어선이라고 할 수 있겠다.)
Who can access?
이는 인증 메커니즘에 따라 달라진다. 유형은 아래와 같다.
- file - Username and passwords
- file - Username and tokens
- Certificates (인증서)
- 외부 인증 공급자 (ex. LDAP)
- Service account (컴퓨터가 생성)
What can they do?
인증 메커니즘으로 정의된다.
- RBAC (역할 기반 액세스 컨트롤)
- ABAC
- Node Authorization
- Certificates (인증서)
Cf. 워커 노드에서 실행되는 kubelet 이나 kube-proxy의 경우 TLS 암호화로 보안
Athentication(인증)
Service Account
쿠버네티스는 사용자 계정을 직접 관리하지 않기 때문에 세부 정보나 인증서가 포함된 파일, 서드파티 신원 서비스인 LDAP 등의 외부 소스를 통해서만 가능하다. ServiceAccount의 경우 쿠버네티스가 관리할 수 있다.
kubectl create serviceaccount [account-name]
kubectl get serviceaccount
Auth Mechanisms
`kubectl`을 선언하거나 curl 명령을 수행 등 어떤 방식으로 접근해도 이는 항상 kube-apiserver로 향한다.
kube-apiserver은 요청을 실행하기에 앞서 인증 과정을 거친다. 이 때 사용될 수 있는 인증 메커니즘은 암호 파일, 토큰 파일, 인증서, 서드파티 인증 프로토콜(LDAP, kerberos 등)이 있다.
cf. 파일 유형(암호 vs 토큰)
파일(암호)
csv 파일을 통해 pw, userName, userId(+ group을 명시에 유저마다 그룹에 배치시킬 수 있음)을 컬럼으로 가지도록 사용자 정보를 구성하는 경우 `kube-apiserver.service` 파일에 `--basic-auth-file` 옵션으로 해당 파일명을 명시해주어야 한다. (수정시 apiserver를 재시작해주어야 적용됨)
만약 kubeadm으로 클러스터를 구성한 경우 `kube-apiserver.yaml` 파일(staticPod로 주로 `/etc/kubernetes/mamifests/` 하위에 존재)을 수정(위의 옵션 추가)하면 kubeadm이 자동으로 apiserver를 재시작시킨다.
이 경우 아래와 같이 사용자 인증을 할 수 있다.
curl [파드 등의 경로] -u "[username]:[password]"
파일(토큰)
csv 파일을 통해 token, userName, userId(+ group)을 컬럼으로 가지도록 사용자 정보를 구성하는 경우 `kube-apiserver.service`에 `--token-auth-file` 옵션으로 해당 파일명을 명시해주어야 한다.
이 경우 아래와 같이 사용자 인증을 할 수 있다.
curl [파드드등의 경로] --header: "Authorization: Bearer [user-token]
TLS in kubernetes
요청을 보내는 쪽에서는 항상 인증서와 private key가 필요하다. 이는 양방향 통신을 하는 kube api server와 kubelet 사이에도 마찬가지이다.
- kube-apiserver에 요청을 보내는 사용자(관리자), kube-scheduler, control-manager, kube-proxy는 모두 한 쌍의 public key(crt, pem)와 private key를 지녀야 한다.
- kube-apiserver 역시 etcd나 워커노드의 kubelet과 통신하기 위해서 한 쌍의 public key와 private key를 지녀야 한다.
- 또한 etcd와 kubelet 역시 한 쌍의 public key와 private key를 지녀야 한다.
따라서 너무 많은 인증서들이 필요한데, 이는 한 쌍의 CA의 public key, private key로 대체 가능하다.
Certificate Creation
Cf. 아래 실습에서는 OpenSSL로 진행(private key → csr → crt)
1. CA의 개인 키(.key)와 루트 인증서(.crt) 생성
먼저, 클라이언트와 서버에서 요청을 보낼 때마다 서명하는 주체인 CA를 생성한다.
1) private key 생성
openssl genrsa -out [key-name].key 2048
2) (아직 서명되지 않은 상태의) 인증서 (서명 요청) 생성
openssl req -new -key [key-name].key -out [ca-name].csr
Cf. subj
csr 내에는 key 정보 외에도 Subject라는 정보가 들어가는데 이를 직접 입력하기 위해선 `-subj` 옵션을 부여할 수 있다. (아래에는 Common Name의 약어 CN값으로 `Kubernetes-CA` 부여)
openssl req -new -key [key-name].key -subj "/CN=Kubernetes-CA" -out [ca-name].csr
`CN` 과 같이 `-subj` 옵션에 들어갈 수 있는 사항들은 아래와 같다.
String X.500 AttributeType
------------------------------
CN commonName
L localityName
ST stateOrProvinceName
O organizationName
OU organizationalUnitName
C countryName
STREET streetAddress
DC domainComponent
UID userid
3) 인증서에 서명
openssl x509 -req -in [ca-name].csr -signkey [key-name].key -out [certificates-name].crt
Client의 개인 키(.key)와 루트 인증서(.crt) 생성
Cf. 이 과정은 CA의 인증을 받는 컴포넌트 인증서 생성시 모두 동일하다.
앞서 만든 CA의 인증서가 `ca.crt`, CA의 키가 `ca.key`라고 할 때 클라이언트 측의 키와 인증서는 아래와 같이 만들 수 있다. (이 때는 클라이언트의 개인 키가 아닌 CA 키 페어(인증서와 키)를 함께 사용해 클라이언트 인증서에 서명한다.)
openssl genrsa -out admin.key 2048
openssl req -new -key admin.key -subj "\CN=Kube-admin" -out admin.csr
openssl x509 -req -in admin.csr -CA=ca.crt -CAkey ca.key -out admin.crt
이 때, 이 인증서는 일반 사용자가 아닌 관리자를 위한 인증서로, 인증서에 유저 그룹에 대해 명시해야 한다. (쿠버네티스에는 관리 권한을 가진 system:master라는 그룹이 존재하므로, 이를 옵션으로 추가해준다.)
openssl x509 -req -in admin.csr \
-CA=ca.crt -CAkey=ca.key -subj "\CN=Kube-admin\O=system:masters" -out admin.crt
Cf. 위에서 만든 관리자 인증서를 통해서 Kubenetes API를 호출하는 경우 아래처럼 할 수 있다.
curl https://kube-apiserver:6443/api/v1/pods \
--key=admin.key -- cert=admin.crt \
--ca=ca.crt
하지만, API를 호출할 때마다 인증서를 제출하기는 번거로우므로 보통은 config 파일을 생성해 certificate을 관리한다.
apiVersion: v1
kind: Config
current-context: kubernetes
clusters:
- cluster:
name: kubernetes
certificate-authority: ca.crt
server: https://kube-apiserver:6443
users:
- user:
name: kubernetes-admin
client-certificate: admin.crt
client-key: admin.key
contexts:
- context:
name: kubernetes-admin@kubernetes
cluster: kubernetes
user: kubernetes-admin
ETCD server
ETCD는 보통 높은 가용성을 위해 클러스터의 여러 노드 상에 배치된다. 이 경우에는 peer key pair가 필요하다.
# etcd.yaml
# ca
-- cert-file=etcdserver.crt # root CA가 서명한 자신의 인증서
-- key-file=etcdserver.key # 자신의 private key
-- trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt # root CA crt file
# peer crt, key, ca
-- peer-cert-file=etcdpeer1.crt # peer crt
-- peer-key-file=/etc/kubernetes/pki/etcd/peer.key # peer key
-- peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt # root CA crt file
-- peer-client-cert-auth=true
kube-API Server
api server는 쿠버네티스 컴포넌트들중 가장 많이 불리우며 다양한 별칭을 가지고 있다.
kubernetes
kubernetes.default
kubernetes.default.svc
kubernetes.default.svc.cluster.local
[api server가 존재하는 노드 및 파드의 IP]
private key 생성
openssl genrsa -out apiserver.key 2048
인증서 서명 요청 생성
`openssl.cnf` 생성 후 `config` 옵션으로 전달
openssl req -new -key apiserver.key \
-subj="/CN=kube-apiserver" -out apiserver.csr -config openssl.cnf
Cf. openssl.cnf 파일 생성 (`alt_names`에 kube-api server를 지나는 모든 DNS명, IP 명시)
...
[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster.local
IP.1 =
IP.2 =
인증서 서명
openssl x509 -req -in apiserver.csr -CA=ca.crt -CAkey=ca.key -out=apiserver.crt
인증서, 키 위치 명시
`kube-apiserver.yaml`
api server가 client와 통신하는 경우와 api server가 client인 경우(etcd, kubelet과 통신하는 경우) 모두 각각에 맞게 만든 인증서를 사용해야 한다. etcd, kubelet의 CA 파일은 각 컴포넌트가 가진 고유한 CA를 명시해주어야 한다. 예를 들어, kube-api server가 사용하는 CA 파일이 `/etc/kubernetes/pki/ca.crt` 이고, etcd가 사용하는 CA 파일이 `/etc/kubernetes/pki/etcd/ca.crt` 라면 둘을 구분해서 써줘야 한다. 전자는 `etcd-cafile`에, 후자는 `tls-ca-file`에 명시해주어야 한다.
`/etc/kubernetes/manifests/kube-apiserver.yaml`
spec:
containers:
- command:
- kube-apiserver:
- -- etcd-cafile=/var/lib/kubernetes/ca.crt
- -- etcd-certfile=/var/lib/kubernetes/apiserver-etcd-client.crt
- -- etcd-keyfile=/var/lib/kubernetes/apiserver-etcd-client.key
- -- kubelet-client-certificate-authority=/var/lib/kubernetes/ca.crt
- -- kubelet-client-certificate=/var/lib/kubernetes/apiserver-kubelete-client.crt
- -- kubelet-client-key=/var/lib/kubernetes/apiserver-kubelet-client.key
- -- client-ca-file=/var/lib/kubernetes/ca.crt
- -- tls-cert-file=/var/lib/kubernetes/apiserver.crt
- -- tls-private-key-file=/var/lib/kubernetes/apiserver.key
Kubelet
각 노드 별로 노드 이름을 포함하여 서버측 인증서 & 키와 클라이언트측 인증서 & 키를 만들어야 함
Cf. 서버 측: kube-api server가 kubelet에 요청을 보낼 때
Cf. 클라이언트 측: kubelet이 kube-api server에 요청을 보낼 때
` kubelet-config.yaml(node01)`
kind:
apiVersion:
authentication:
x509:
clientCAFile: "/var/lib/kubernetes/ca.crt"
tlsCertFile: "/var/lib/kubelet/kubelet-node01.crt"
tlsPrivateKeyFile: "/var/lib/kubelet/kubelet-node01.key"
api server가 해당 노드들에 알맞은 관리 권한을 부여하게 하기 위해선 system 그룹에 노드를 추가할 수 있다. (`subj=”/O=system:nodes"`)
Certificate details
Cf. kube-apiserver 정의 파일(`/etc/kubernetes/manifests/kube-apiserver.yaml`)에서 인증서들의 경로 확인 가능
인증서 상세 정보를 보려면 아래의 커맨드를 통해 가능
openssl x509 -in [crt-path] -text -noout
Logs
자체적으로 클러스터를 구성한 경우(모든 서비스가 네이티브 서비스로 구성된 경우)
journalctl -u [service-name] -l # example journalctl -u etcd.service -l
Kubeadm을 이용한 경우(컴포넌트들이 파드 형태로 배포된 경우)
kubectl logs [pod-name]
kube-api server 또는 etcd-server가 다운된 경우(kubectl 커맨드가 통하지 않는 경우)
# 모든 컨테이너 목록 조회
docker ps -a
# 특정 컨테이너의 로그 조회
docker logs [container-id]
Cf. 이 경우에는 도커 레벨로 내려가서 로그를 조회해야 한다.
kube-api server 또는 etcd-server가 다운됐는데 docker 명령어가 통하지 않는 경우
# identify the kube-apiserver container
crictl ps -a
# view the logs
crictl logs [container-id]
Certificate API
새로운 사용자를 만들고 이에 대한 인증서를 만드는 과정에서 관리자가 매번 CA 서버에 접속해 직접 서명하는 것은 매우 번거롭다. kubernetes에서 지원하는 Certificate API를 이용하면 커맨드를 통해 서명 요청(.csr)을 보내고 이를 서명하도록 할 수 있다.
CertificateSigningRequest object
`CertificateSigningRequest object manifest file(.yaml)`
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: [certificate-name]
spec:
groups:
- system:authenticated
usages:
- digital signature
- key encipherment
- server auth # 서버 권한
# client auth의 경우 일반 사용자
request:
[csr을 base64로 인코딩한 내용]
Cf. base64로 인코딩한 결과 출력
cat [csr-file-name] | base64 | tr -d "\n"
CertificateSigningRequest 오브젝트 생성 후에는 모든 관리자들이 이를 조회할 수 있다.
# 모든 csr 조회
kubectl get csr
# 특정 csr(서명 요청) 서명
kubectl certificate approve [csr-name]
# 특정 csr(서명 요청) 거부
kubectl certificate deny [csr-name]
YAML 파일 형태로 csr 조회시 `status.certificate` 필드 값을 디코딩 하면 텍스트 형태로 인증서를 가질 수 있다. - 이는 최종 사용자들과 공유 가능하다.
kubectl get csr -o yaml
echo "[status.certificate 필드 값]" | base64 --decode
kubernetes에서 위와 같이 Certificate 요청을 처리하는 컴포넌트는 Controller manager이다. Controller manager 내부에는 CSR-APPRVING, CSR-SIGNING 이라는 두 개의 컨트롤러가 존재한다. 인증서를 허가하고 승인하기 위해서는 루트 인증서(CA crt)와 키(.key)가 필요하다.
kube-controller-manager manifest 파일(`.yaml`)에는 `cluster-signing-cert-file`과 `cluster-signing-key-file`을 통해 해당 요소들을 지정할 수 있다.
'Kubernetes' 카테고리의 다른 글
k8s) Security - 3. Authorization(RBAC, Cluster Role, Service Account) (0) | 2024.03.10 |
---|---|
k8s) Security - 2. KubeConfig, API Groups (0) | 2024.03.10 |
k8s) Cluster Maintenance (0) | 2023.11.17 |
k8s) Application Lifecycle Management (0) | 2023.11.17 |
k8s) Scheduling - 5. Scheduler (1) | 2023.11.17 |