kubernetes security
ServiceAccount and RBAC
ServiceAccount
는 사용자 또는 어플리케이션 하나에 해당한다. RBAC(Role Based Access Control)
라는 기능을 통해 특정 명령을 실행할 수 있는 권한을 ServiceAccount
에 부여한다.
kubectl 명령어가 동작하는 과정
1
2
3
4
1) kubectl 명령어는 쿠버네티스 API 서버의 HTTP 핸들러에 요청을 전송한다.
2) API 서버는 해당 클라이언트가 쿠버네티스 사용자가 맞는지 `인증(Authentication)`, 해당 기능이 `인가(Authorization)` 되어있는지 확인한다.
-> kubectl 명령어는 config 파일-user항목에 client-certification, keydata가 있는데 이는 k8s에서 최고권한(cluster-admin)을 갖는다.
3) Admission Controller라는 별도의 과정을 거친 뒤 요청받은 기능 수행
ServiceAccount, Role, Cluster-Role
Role
1
2
3
4
5
6
7
8
# service-account ( serviceAccount or sa ) / default 라는 서비스어카운트가 디폴트로 존재
kubectl get sa
# 새로운 서비스어카운트 생성
kubectl create sa lsy1206
# 에러발생. 아직 서비스목록을 조회할 권한이 없음
kubectl get services --as system:serviceaccount:default:lsy1206
Role(네임스페이스에 속한 오브젝트들에 대한 권한을 정의)
과 Cluster-Role(클러스터 단위의 권한을 정의)
은 부여할 권한이 무엇인지를 나타내는 쿠버네티스 오브젝트이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Role(네임스페이스에 속한 오브젝트들에 대한 권한을 정의)
kubectl get role
## yaml(role을 생성) ##
apiVersion: rbac.authorication.k8s.io/v1
kind: Role
metadata:
namespace: default
name: service-reader
rules:
apiGroups: [""] # 1. 대상이 될 오브젝트 API 그룹
resources: ["services"] # 2. 대상이 될 오브젝트의 이름
verbs: ["get", "list"] # 3. 허용하고자 하는 동작
kubectl apply -f {yaml-file-name}
## yaml(role을 바인딩(binding)) ##
apiVersion: rbac.authorication.k8s.io/v1
kind: RoleBinding
metadata:
name: service-reader-rolebinding
namespace: default
subjects:
- kind: ServiceAccount # 권한을 부여할 대상이 ServiceAccount
name: lsy1206 # 권한을 부여할 서비스어카운트는 lsy1206
namespace: default
roleRef:
kind: Role # Role에 정의된 권한을 부여한다.
name: service-reader # service-reader라는 이름의 Role을 대상(Subject)에 연결환다.
apiGroup: rbc.authorization.k8s.io
kubectl apply -f {yaml-file-name}
# 권한을 부여받았으므로 정상조회
kubectl get services --as system:serviceaccount:default:lsy1206
Role vs Cluster-Role
Cluster-Role은 클러스터 단위의 리소스에 대한 권한을 정의하기 위해 사용한다. kind가 Role -> ClusterRole로 바뀐점을 제외하면 Role 정의부와 대부분이 닮아 있다.
1
2
3
4
5
6
7
8
# 2) Cluster-Role(클러스터 단위의 권한을 정의)
kubectl get clusterrole
kubectl apply -f {cluster-yaml-file-name}
kubectl describe clusterrole nodes-reader
Cluster-Role aggregation
cluster-role-aggregation : 자주 사용되는 클러스터 롤이 있다면 다른 클러스터 롤에 포함시켜 재사용할 수 있다. 상속 구조로 작성하여, 부모의 권한을 자식 롤에서 물려 받아 사용할 수 있다. aggregationRole.clusterRoleSelectors 옵션을 사용한다.
Kubernetes API Server Accesss
ServiceAccount Secret 이용해 접근
ServiceAccount에 연결된 Secret에는 ca.crt, namespaces, token 세가지 데이터가 저장되어 있다.
1
2
3
1) ca.crt: 쿠버네티스 공개 인증서를 의미
2) namespace: 서비스 어카운트가 존재하는 네임스페이스를 저장
3) token: 쿠버네티스 API 서버와의 JWT인증에 사용된다. -> API서버에 HTTP Rest-API방식으로 접근할 떄 신분을 증명할 수 있다.
Cluster 내부 kubernetes Service 이용해 접근
클러스터 내부에서 API서버에 접근할 수 있는 서비스 리소스가 바로 kubernetes 서비스이다. 따라서 내부 포드는 kubernetes.default.svc 라는 DNS 이름을 통해 kubernetes api를 사용할 수 있다.
(이때, 쿠버네티스는 자동으로 서비스 어카운트의 시크릿을 포드 내부에 마운트하기 떄문에, 포드 내부에서 API 서버에 접근하기 위해 시크릿 데이터를 가져올 필요는 없다.)
Kubernetes SDK 이용해 Pod 내부에서 접근
쿠버네티스 SDK(특정언어로 바인딩 된)를 사용하면 다음과 같이 동작한다. 포드를 생성하는 yaml에서 ServiceAccountName을 명시해두면, 시크릿은 포드내부에 마운트될 것이므로 포드에서 해당 SDK로 쿠버네티스 API서버에 접근한다.
Configs 설정하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# ServiceAccount에 secret 설정하기
imagePullSecrets 항목을 사용한다.
# Kubeconfig에 인증정보 설정하기
kubeconfig 파일에 직접 인증정보를 설정해 kubectl 명령어를 통해 사용할 수도 있다(원래는 root 권한) kubeconfig는 크게 3가지로 나눠져있다.
1) clusters : kubectl이 사용할 쿠버네티스 API 서버의 접속 정보 목록을 의미한다.
2) users : 쿠버네티스ㅜ의 API 서버에 접속하기 위한 사용자 인증정보 목록이다.
3) contexts : clusters 항목과 users 항목에 정의된 값을 조작해 최종적으로 사용할 쿠버네티스 클러스터의 정보를 설정한다.
# User 와 Group
쿠버네티스에서는 유저(User) 나 그룹(Group)이라는 오브젝트는 없지만 서비스 어카운트는 개념상으로 유저의 한 종류이다.
--as system:serviceaccount:<네임스페이스 이름, ex) default >:< 서비스 어카운트 이름, ex) lsy1206> 는 사실 ServiceAccount를 지칭하는
고유한 유저(User)의 이름을 의미한다.
그룹(Group)은 이런 유저를 모아놓은 집합이다. system:serviceaccount가 바로 그룹 이름이다.
쿠버네티스에의해 미리 정의된 유저나 그룹은 접두어로 system: 을 사용한다.
# x509 인증서를 통한 인증
쿠버네티스에서 지원하는 인증방식은 별도의 인증(깃헙, 구글계정 등)서버를 두는 방식도 있지만 기본적으로는 x509라는 self-signed 루트 인증서를 사용한다.
이 인증서는 k8s를 설치할 떄 자동으로 생성된다.
쿠버네티스 최상위 인증서는 ca.crt이며 ca.key 값이 이 인증서에 대응하는 비밀키값이다. 해당 루트 인증서로부터 하위 인증서를 직접 생성하여 API 서버에
인증을 하는 방법도 가능하다. CertificateSigningRequest 오브젝트를 사용하면 openssl 에 비해 비교적 안정적으로 인증서 사인 요청(.csr) 파일에
사인이 가능하다. -> 해당 오브젝트로부터 하위 인증서를 추출한다.
(단 x509와 하위 인증서는 인증서가 유출되었을 때 하위 인증서를 파기하는 기능을 제공하지 않으므로 실제 운영상에서는 솔루션(Dex, Guard)을 이용해 서드
파티에서 인증 정보를 관리하는 것이 더욱 효율적일 수도 있다.)