-
17. 클러스터 유지와 보안 트러블 슈팅 (3)24년 11월 이전/데브옵스(DevOps)를 위한 쿠버네티스 마스터 2021. 9. 8. 20:49반응형
이 문서는 인프런 강의 "데브옵스를 위한 쿠버네티스 마스터"을 듣고 작성되었습니다. 최대한 요약해서 강의 내용을 최소로 하는데 목표를 두고 있어서, 더 친절하고 정확한 내용을 원하신다면 강의를 구매하시는 것을 추천드립니다. => 강의 링크
Security Context
Security Context
는Kubernetes
클러스터의 보안을 위한 리소스 중 하나이다. 아무것도 설정되지 않은Pod
의 컨테이너들은 모두 "root" 권한으로 실행된다. 만약Persistent Volume
에 연결된 컨테이너가 해킹된다면? 이런 경우 외에도 수 많은 보안 위험에 노출될 수 있는데Security Context
를 사용하면 어느 정도 보호해줄 수 있다.Security Context
로Pod
혹은 컨테이너 단위로 할 수 있는 것은 다음과 같다.- 권한 상승 가능 여부
- 프로세스 "UID/GID"를 통한 오브젝트 액세스 제어
- "Linux Capability"를 활용한 커널 기능 추가
- SELinux 기능
- AppArmor 기능
- Seccomp Process 기능
먼저 다음을 한 번 만들어보자.
apiVersion: v1 kind: Pod metadata: name: sc-1 spec: containers: - name: sc-1 image: gcr.io/google-samples/node-hello:1.0
위 생성된
Pod
은 여지껐 만들어왔던 방식이다. 먼저 쉘에 접속해보자.$ kubectl exec -it sc-1 -- bash root@sc-1:/#
여기서
id
라는 명령어를 입력해보자.root@sc-1:/# id uid=0(root) gid=0(root) groups=0(root)
"uid", "gid", "group"이 모두 "root" 권한으로 실행된 것을 확인할 수 있다. 이번엔
ps aux
라는 명령어를 입력해본다.root@sc-1:/# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND 0 1 0.0 0.0 4332 712 ? Ss 10:32 0:00 /bin/sh -c node server.js 0 6 0.0 0.5 772120 22880 ? Sl 10:32 0:00 node server.js 0 11 0.0 0.0 20240 3256 pts/0 Ss 10:32 0:00 bash 0 25 0.0 0.0 17496 2128 pts/0 R+ 10:38 0:00 ps aux
실행되는 모든 프로세스를 확인할 수 있다. 여기서 이제 "root"라는 디렉토리를 지워보자.
# 디렉토리 목록 확인 root@sc-1:/# ls bin boot dev etc home lib lib64 media mnt opt proc root run sbin server.js srv sys tmp usr var # root 디렉토리 제거 root@sc-1:/# rm -rf root # 제거됨 root@sc-1:/# ls bin boot dev etc home lib lib64 media mnt opt proc run sbin server.js srv sys tmp usr var
마음대로 삭제가 가능하다. 굉장히 보안에 취약한 상태라고 볼 수 있다. 이제 다음 리소스를 생성해보자
.
apiVersion: v1 kind: Pod metadata: name: sc-2 spec: securityContext: runAsUser: 1000 containers: - name: sc-2 image: gcr.io/google-samples/node-hello:1.0 securityContext: runAsUser: 4000 # container 단위 allowPrivilegeEscalation: false
위
Pod
는 "uid=1000, gid=root, group=root"으로 실행된다. 컨테이너의 "uid=4000"이다. 이렇게 하면 쉘에 접속은 되도 권한이 막혀 어떤 명령어로도 내부를 수정할 수 없다.Pod
가 생성되면 똑같이 쉘에 접속해본다.$ kubectl exec -it sc-2 -- bash I have no name!@sc-2:/$
이제 "id"를 입력해보자.
I have no name!@sc-2:/$ id uid=4000 gid=0(root) groups=0(root)
이제
ps aux
라는 명령어를 입력해보자.I have no name!@sc-2:/$ ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND 4000 1 0.0 0.0 4332 728 ? Ss 10:52 0:00 /bin/sh -c node server.js 4000 8 0.0 0.5 772120 22768 ? Sl 10:52 0:00 node server.js 4000 13 0.0 0.0 20240 3260 pts/0 Ss 10:52 0:00 bash 4000 20 0.0 0.0 17496 2088 pts/0 R+ 10:53 0:00 ps aux
이제 "uid=4000"으로 실행되는 것을 확인할 수 있다. 한 번 똑같이 "root"라는 디렉토리를 삭제해보자.
I have no name!@sc-2:/$ rm -rf root rm: cannot remove 'root': Permission denied
에러다. 왜냐하면 파일에 대한 권한이 "root"이기 때문이다. 프로세스 실행 권한은 "4000"이다. 그래서 권한이 낮기 때문에 삭제할 수 없다. 이런 식으로 컨테이너 혹은
Pod
단위의 보안 수준을 높일 수가 있다.Network Policy
Network Policy
는Pod
별로 방화벽을 설정해줄 수 있다. 쉽게 생각하면AWS
의Security Group
과 유사하다. 다음과 같이 3개의 식별자 조합을 통해 네트워크 트래픽을 제어할 수 있다.- 허용되는 다른 Pod
- 허용되는 Namespace
- IP 블록
이 리소스는
Kubernetes
클러스터에 설치된CNI
가 네트워크 플러그인을 지원해야 한다.Weavenet
은 지원하고 있고GKE
같은 경우 클러스터를 만들 때 다음과 같이 왼쪽 탭의 "네트워크"를 클릭한다.그 후 "Kubernetes 네트워크 정책 사용 설정" 옵션을 활성화해주고 만들어준다.
이제 다음과 같이
Pod
들을 만들고Network Policy
를 만들어줄 것이다.먼저 다음 리소스들을 생성해보자.
apiVersion: v1 kind: Service metadata: creationTimestamp: null labels: app: np1 name: np1 spec: clusterIP: None selector: app: np1 type: ClusterIP status: loadBalancer: {} --- apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: np1 name: np1 spec: replicas: 1 selector: matchLabels: app: np1 strategy: {} template: metadata: creationTimestamp: null labels: app: np1 spec: containers: - image: nginx name: nginx resources: {} status: {} --- apiVersion: v1 kind: Service metadata: creationTimestamp: null labels: app: np2 name: np2 spec: clusterIP: None selector: app: np2 type: ClusterIP status: loadBalancer: {} --- apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: np2 name: np2 spec: replicas: 1 selector: matchLabels: app: np2 strategy: {} template: metadata: creationTimestamp: null labels: app: np2 spec: containers: - image: nginx name: nginx resources: {} status: {} --- apiVersion: v1 kind: Service metadata: creationTimestamp: null labels: app: np3 name: np3 spec: clusterIP: None selector: app: np3 type: ClusterIP status: loadBalancer: {} --- apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: np3 name: np3 spec: replicas: 1 selector: matchLabels: app: np3 strategy: {} template: metadata: creationTimestamp: null labels: app: np3 spec: containers: - image: nginx name: nginx resources: {} status: {}
이렇게 하면 이미지가
nginx
인Pod
1개,Service
1개씩 들어있는 세트가 총 3개 만들어진다. 현재는Network Policy
가 없기 때문에 모든Pod
가 다른Service
를 호출할 수 있다.# kubectl exec -it <생성된 pod id> -- curl <생성된 svc name> $ kubectl exec -it np3-d4799d44f-lfpjp -- curl np2
이제 위의 그림이 되게끔 통신을 막아보자. 다음과 같은 리소스를 생성하면 된다.
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: np1-ingress spec: podSelector: matchLabels: app: np1 policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: np2 --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: np2-ingress spec: podSelector: matchLabels: app: np2 policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: np3 --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: np3-ingress spec: podSelector: matchLabels: app: np3 policyTypes: - Ingress
"np1"의 경우 "np2"만 들어올 수 있게 "ingress" 설정을 진행했다. "np2"는 "np3"만, "np3"는 어느
Pod
도 다른 곳에 호출할 수 없게 막아두었다. 끝이다. 이제 이걸 만들고 또 호출을 하면 위에서 그린 그림과 같이 호출 관계가 형성된 것을 확인할 수 있다.현재는
Pod
에서 외부로 나가는 트래픽을 제어할 필요는 없기 때문에 "egress" 설정은 건너 뛰었다. 작성요령은 비슷하다. 그리고namespaceSelector
는 네임스페이스 별로,ipBlock
은 아이피 블록 별로podSelector
와 비슷하게 "ingress/egress"를 관리할 수 있다.Trouble Shooting 가이드
트러블 슈팅은 "로깅"이 매우 중요하다. 이걸 명심하자. 또한 트러블 슈팅은 크게 다음으로 나눌 수 있다.
- 클러스터 트러블 슈팅
- 애플리케이션 트러블 슈팅
보통 클러스터 수준의 트러블 슈팅은
API
가 "deprecated" 되었다던가, 인증서가 만료되었다던가하는 것 정도가 있다. 애플리케이션 트러블 슈팅은 거의 사용자가 문제를 일으키는 편이다.애플리케이션 트러블 슈팅은 다음과 같은 특징이 있다.
- Pod, ConfigMap 등의 로직이 잘못되었는지 단위 별로 체크
- 일반적으로 이름이나 레이블링이 틀려서 문제가 생김
클러스터 트러블 슈팅은 다음과 같은 특징이 있다.
- 쿠버네티스 시스템에 대한 깊은 이해가 필요
- 일반적으로 다수 보다는 한, 두군데 장애가 존재
예를 들면,
kubectl
이 접속이 안되면kube-apiserver
를 봐야 한다든가 컨테이너 배치가 안되면kube-scheduler
를 봐야 한다든가 깊은 이해가 필요하다. 로그를 찾을 때는 마스터 노드의 컴포넌트 로그들,journalctl
을 이용하여kubelet
등의 서비스 로그 순으로 확인하면 좋다.728x90'레거시 > 데브옵스(DevOps)를 위한 쿠버네티스 마스터' 카테고리의 다른 글
16. 클러스터 유지와 보안 트러블 슈팅 (2) (0) 2021.09.08 15. 클러스터 유지와 보안 트러블 슈팅 (1) (0) 2021.09.01 14. 서비스 매시 환경 모니터링 도구 istio 시작하기 (0) 2021.08.31 13. 리소스 로깅과 모니터링 (0) 2021.08.30 12. 애플리케이션 스케줄링과 라이프사이클 관리 (2) (0) 2021.08.20