이전 Kubernetes 보안 1/2에 이어 글이 이어진다.
5. polaris
polaris는 오픈소스 보안 점검 도구로 기본적인 취약점 검사 뿐 아니라 어드미션 단, 웹훅단 배포하는 yaml, helm chart등을 확인, 거부할 수도 있다.
polaris 설치 및 웹 주소 접속
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 설치
kubectl create ns polaris
#
cat <<EOT > polaris-values.yaml
dashboard:
replicas: 1
service:
type: LoadBalancer
EOT
# 배포
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm install polaris fairwinds-stable/polaris --namespace polaris --version 5.7.2 -f polaris-values.yaml
# CLB에 ExternanDNS 로 도메인 연결
kubectl annotate service polaris-dashboard "external-dns.alpha.kubernetes.io/hostname=polaris.$KOPS_CLUSTER_NAME" -n polaris
# 웹 접속 주소 확인 및 접속
echo -e "Polaris Web URL = http://polaris.$KOPS_CLUSTER_NAME"
|
cs |
분류는 Passing/Warning/Dangerous로 위험 등급 분류가 되고 위험 단계 취약점은 조치를 권고한다.
네임스페이스 별로 필터링 해서도 볼 수 있다. netshoot-pod를 보면 해당 파드의 취약점을 스캔한 내용을 확인 할 수 있다. 기존 netshoot-pod를 삭제하고 이 취약점 조치를 해서 확인 해본다. 스터디에서 조치한 내용 보다 더 조치 해서 확인을 해봤다. (probe 영역을 깜빡했지만 ㅎㅎ)
취약점을 확인 하면 조치된 항목이 체크가 되어 있는 것을 확인 할 수 있다.
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
36
37
38
39
40
41
42
43
|
# 기존 netshoot-pod 삭제
kubectl delete deploy netshoot-pod
# netshoot-pod 생성
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: netshoot-pod
spec:
replicas: 2
selector:
matchLabels:
app: netshoot-pod
template:
metadata:
labels:
app: netshoot-pod
spec:
containers:
- name: netshoot-pod
image: nicolaka/netshoot:v0.9
command: ["tail"]
args: ["-f", "/dev/null"]
imagePullPolicy: Always
resources:
limits:
cpu: 150m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
runAsNonRoot: true
allowPrivilegeEscalation: false
terminationGracePeriodSeconds: 0
EOF
|
cs |
IaC 활용 cli - 마리오 파드 yaml 점검
cli로 취약점을 확인할 수도 있다. 웹에서 보는 취약점을 CLI을 통해 확인한다. 아래는 마리오 파드 yaml을 점검해보 확인 해봤다. CLI에 마크와 함께 취약점을 확인 할 수있다.
1
2
3
4
5
6
7
8
|
# 다운로드
wget https://github.com/FairwindsOps/polaris/releases/download/7.3.2/polaris_linux_amd64.tar.gz
tar zxvf polaris_linux_amd64.tar.gz
mv polaris /usr/local/bin
polaris audit --help
# 마리오 파드 yaml 점검
polaris audit --audit-path ~/pkos/1/mario.yaml --format=pretty
|
cs |
6. RBAC
K8S(API 접근) 인증/인가는 API 서버를 사용한다. kubectl(config, 다수 클러스터 관리 가능), 서비스 어카운트, https(x.509 Client Certs) 세가지 방법이 있다. API 서버 접근 과정은 인증 → 인가 → Admission Control(API 요청 검증)이다.
마스터 노드에 API 서버가 있다. 이 서버를 통해서만 내부 자원, 조회가 가능하다. 외부에서는 인증서가 있어야 https로 접근가능 하고, 관리자가 kubectl로 프록시를 열어줬을 때만 인증서없이 접근가능하다. 외부 PC에서도 kubectl설치할 수 있는데 config로 연결상태를 유지한다.
RBAC
알백이라고 읽는 RBAC 역할기반 접근 통제는 클라우드의 IAM과 닮았다. 서비스 어카운트(Service Account)를 사용할 수 있다. 노드, pv, ns - 클러스터 단위 / 파드나 서비스와 같이 ns단위로 관리되는 오브젝트가 있다. 네임스페이스를 만들면 자동적으로 default라는 SA만들어진다. 역할 기반의 권한 관리, 사용자와 역할을 별개로 선언 후 두가지를 조합(binding)해서 사용자에게 권한을 부여하여 kubectl or API로 관리 가능하다.
- Role(네임스페이스내 자원의 권한) vs ClusterRole(클러스터 수준의 자원의 권한)
역할은 Role과 ClusterRole 두 가지로 나뉜다. 네임스페이스 내부, 클러스터 수준으로 적용 범위로 나뉜다.
각각 네임스페이스에 롤(Role)를 생성 후 서비스 어카운트 바인딩
- 롤(Role) : apiGroups 와 resources 로 지정된 리소스에 대해 verbs 권한을 인가
- 실행 가능한 조작(verbs) : *(모두 처리), create(생성), delete(삭제), get(조회), list(목록조회), patch(일부업데이트), update(업데이트), watch(변경감시)
dev, infra 네임스페이스 내부의 파드를 생성하고 Role과 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
# 네임스페이스(Namespace, NS) 생성 및 확인
kubectl create namespace dev-team
kubectl create ns infra-team
# 네임스페이스 확인
kubectl get ns
NAME STATUS AGE
default Active 6h56m
dev-team Active 9s
infra-team Active 4s
kube-node-lease Active 6h56m
kube-public Active 6h56m
kube-system Active 6h56m
polaris Active 139m
# 네임스페이스에 각각 서비스 어카운트 생성 : serviceaccounts 약자(=sa)
kubectl create sa dev-k8s -n dev-team
kubectl create sa infra-k8s -n infra-team
# 서비스 어카운트 정보 확인
kubectl get sa -n dev-team
NAME SECRETS AGE
default 0 73s
dev-k8s 0 24s
kubectl get sa dev-k8s -n dev-team -o yaml | yh
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2023-04-09T07:28:32Z"
name: dev-k8s
namespace: dev-team
resourceVersion: "99395"
uid: d1597ee0-6917-41ed-9e27-3bef8fddad02
kubectl get sa -n infra-team
sa infra-k8s -n infra-team -o yaml | yhNAME SECRETS AGE
default 0 83s
infra-k8s 0 18s
kubectl get sa infra-k8s -n infra-team -o yaml | yh
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2023-04-09T07:28:53Z"
name: infra-k8s
namespace: infra-team
resourceVersion: "99475"
uid: 561724fd-75c7-4f0a-80ab-910813378a83
# 각각 네임스페이스내의 모든 권한에 대한 롤 생성
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-dev-team
namespace: dev-team
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
EOF
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-infra-team
namespace: infra-team
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
EOF
# 롤 확인
kubectl get roles -n dev-team
NAME CREATED AT
role-dev-team 2023-04-09T07:55:30Z
kubectl get roles -n infra-team
NAME CREATED AT
role-infra-team 2023-04-09T07:55:32Z
kubectl get roles -n dev-team -o yaml
apiVersion: v1
items:
- apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
creationTimestamp: "2023-04-09T07:55:30Z"
name: role-dev-team
namespace: dev-team
resourceVersion: "105744"
uid: a99d420d-982e-4fc3-8e2d-83862759215f
rules:
- apiGroups:
- '*'
resources:
- '*'
verbs:
- '*'
kind: List
metadata:
resourceVersion: ""
kubectl describe roles role-dev-team -n dev-team
Name: role-dev-team
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
*.* [] [] [*]
# 롤바인딩 생성 : '서비스어카운트 <-> 롤' 간 서로 연동
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: roleB-dev-team
namespace: dev-team
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role-dev-team
subjects:
- kind: ServiceAccount
name: dev-k8s
namespace: dev-team
EOF
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: roleB-infra-team
namespace: infra-team
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role-infra-team
subjects:
- kind: ServiceAccount
name: infra-k8s
namespace: infra-team
EOF
# 롤바인딩 확인
kubectl get rolebindings -n dev-team
NAME ROLE AGE
roleB-dev-team Role/role-dev-team 58s
kubectl get rolebindings -n infra-team
NAME ROLE AGE
roleB-infra-team Role/role-infra-team 6s
kubectl get rolebindings -n dev-team -o yaml
kubectl describe rolebindings roleB-dev-team -n dev-team
Name: roleB-dev-team
Labels: <none>
Annotations: <none>
Role:
Kind: Role
Name: role-dev-team
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount dev-k8s dev-team
|
cs |
서비스 어카운트를 지정하여 생성한 파드에서 다시 권한 테스트
두 파드의 내부에서 접속하여 권한을 테스트 해보면 네임스페이스 내부의 권한은 모두 가지고 있고, 클러스터 단의 권한은 없다. 네임스페이스 내부의 pod생성 삭제는 가능하지만 클러스터 단위로 조작은 안된다.
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
|
# 각각 파드로 Shell 접속하여 정보 확인 : 단축 명령어(alias) 사용
alias k1='kubectl exec -it dev-kubectl -n dev-team -- kubectl'
alias k2='kubectl exec -it infra-kubectl -n infra-team -- kubectl'
# 권한 테스트
k1 get pods
k1 run nginx --image nginx:1.20-alpine
k1 get pods
k1 delete pods nginx
k1 get pods -n kube-system
k1 get nodes
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:dev-team:dev-k8s" cannot list resource "pods" in API group "" in the namespace "kube-system"
command terminated with exit code 1
k2 get pods
k2 run nginx --image nginx:1.20-alpine
k2 get pods
k2 delete pods nginx
k2 get pods -n kube-system
k2 get nodes
# (옵션) kubectl auth can-i 로 kubectl 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
yes
|
cs |
신규 서비스 어카운트(SA) 생성 후 '클러스터 수준(모든 네임스페이스 포함)에서 읽기 전용'의 권한을 주고 테스트
ClusterRole - 클러스터 단의 읽기 권한에 대한 롤을 생성한다. 바인딩 시에도 이름이 ClusterRoleBinding이다. 클러스터 관련 설정이므로 .metadata 하위가 아닌 .subjects[] 하위에 .namespace 필드가 있다. 권한 Verbs는 [get list]로 지정한다. 위 테스트와는 다르게 클러스터 단의 노드 조회가 가능하다.
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# 네임스페이스(Namespace, NS) 생성 및 확인
kubectl create ns cluster-team
# 네임스페이스 확인
kubectl get ns
NAME STATUS AGE
cluster-team Active 3s
default Active 8h
kube-node-lease Active 8h
kube-public Active 8h
kube-system Active 8h
kubescape Active 31m
polaris Active 3h31m
# 네임스페이스에 각각 서비스 어카운트 생성 : serviceaccounts 약자(=sa)
kubectl create sa cluster-k8s -n cluster-team
# 서비스 어카운트 정보 확인
kubectl get sa -n cluster-team
NAME SECRETS AGE
cluster-k8s 0 10s
default 0 40s
kubectl get sa cluster-k8s -n cluster-team -o yaml | yh
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2023-04-09T08:39:50Z"
name: cluster-k8s
namespace: cluster-team
resourceVersion: "116440"
uid: c21ca8ca-85fd-4d37-8343-9e6152780f48
# 클러스터 단의 읽기 권한에 대한 롤 생성
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: role-cluster-team
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["get", "list"]
EOF
# 클러스터롤 확인
kubectl get clusterrole |grep role-cluster-team
role-cluster-team 2023-04-09T11:52:58Z
kubectl describe clusterroles role-cluster-team
Name: role-cluster-team
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
*.* [] [] [get list]
# ClusterRoleBinding 생성 : '서비스어카운트 <-> 클러스터롤' 간 서로 연동
cat <<EOF | kubectl create -f -
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-read-rolebinding
subjects:
- kind: ServiceAccount
name: cluster-k8s
namespace: cluster-team #클러스터 관련 설정이므로 .metadata 하위가 아닌 .subjects[] 하위에 .namespace 필드가 있음
apiGroup: "" #어떤 유형의 사용자 계정과 연결하는지 설정, 핵심 API 그룹에 설정
roleRef: #사용자에게 어떤 롤을 할당할지를 설정
kind: ClusterRole
name: role-cluster-team
apiGroup: rbac.authorization.k8s.io
EOF
# 클러스터 롤바인딩 확인
kubectl get clusterrolebindings -n cluster-team |grep cluster-read-rolebinding
cluster-read-rolebinding ClusterRole/role-cluster-team 3m4s
kubectl describe clusterrolebindings cluster-read-rolebinding
Name: cluster-read-rolebinding
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: role-cluster-team
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount cluster-k8s cluster-team
# 네임스페이스에 생성
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: cluster-kubectl
namespace: cluster-team
spec:
serviceAccountName: cluster-k8s
containers:
- name: kubectl-pod
image: bitnami/kubectl:1.24.10
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
k get pod -n cluster-team
NAME READY STATUS RESTARTS AGE
cluster-kubectl 1/1 Running 0 6s
# 파드로 Shell 접속하여 정보 확인 : 단축 명령어(alias) 사용
alias k3='kubectl exec -it cluster-kubectl -n cluster-team -- kubectl'
# 권한 테스트
k3 get pods
k3 run nginx --image nginx:1.20-alpine #생성은 되지 않음
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:cluster-team:cluster-k8s" cannot create resource "pods" in API group "" in the namespace "cluster-team"
command terminated with exit code 1
k3 get pods -n kube-system
NAME READY STATUS RESTARTS AGE
aws-cloud-controller-manager-fmd98 1/1 Running 0 11h
aws-load-balancer-controller-664d755cc-tzf7f 1/1 Running 0 11h
aws-node-92tsl 1/1 Running 0 9h
...
k3 get nodes
NAME STATUS ROLES AGE VERSION
i-013c32ef6c6893c64 Ready control-plane 11h v1.24.12
i-02efcebe833916388 Ready node 9h v1.24.12
i-0b169dc4ebfdd3820 Ready node 11h v1.24.12
|
cs |
마치며
5주 동안 가시다님 덕분에 쿠버네티스 운영에서 배워야할 많은 것들을 배울 수 있었다. 다른 멤버들의 발표에서도 운영상의 많은 고민들을 같이 생각할 수 있었다. 처음 쿠버네티스를 접했을 때의 막막함이 스터디를 통해 많이 해소되었다. 여유가 없었던 처음 보다 조금씩 새로운 시도를 해볼 수 있었다. 올해 안에는 회사 내부나 외부든 지식을 전파하고 나눌 기회를 더 잡아봐야 겠다!
'스터디 > Kubernetes' 카테고리의 다른 글
[AEWS] Amzaon EKS - Cluster Endpoint 구성 톱아보기 (0) | 2023.04.30 |
---|---|
[AEWS] Amzaon EKS (0) | 2023.04.30 |
[PKOS] Kubernetes 보안 - kubescape, polaris, RBAC (1/2) (0) | 2023.04.09 |
[PKOS] Kubernetes 모니터링과 로깅 - Prometheus, Grafana, Loki (0) | 2023.04.02 |
[PKOS] Kubernetes GitOps 시스템 - Harbor, GitLab, ArgoCD (0) | 2023.03.26 |