이번 포스팅에서는 Kubernetes 보안의 중요성을 강조하기 위해, 쿠버네티스를 해킹하여 secret 리소스에 저장된 비밀번호를 찾는 여러 가지 방법을 알아봅니다. 특히, etcd와 Pod를 해킹하는 실습으로 쿠버네티스 보안의 중요성을 알아보겠습니다.

Secret은 어디에 저장되나요?

먼저 사용자가 kubectl 명령을 통해 리소스를 선언하면, 쿠버네티스는 이 리소스를 정의한 메니페스트 파일을 만들어 etcd에 저장합니다. secret 또한 마찬가지로 사용자가 secret 리소스를 선언하면 etcd에 저장됩니다. 그리고 사용자가 secret을 볼륨 혹은 환경 변수로 읽는 pod을 만들게 되면, secret은 해당 pod에 저장되게 됩니다.

따라서 우리는 secret이 저장되는 etcd와 secret이 사용되는 pod을 해킹하면 secret에 저장된 비밀번호를 알아낼 수 있습니다.

사전 준비하기

EKS, AKS 등 관리형 쿠버네티스는 기본적인 보안이 매우 잘 되어있기 때문에 실습이 불가합니다. 따라서 이번 실습에서는 가장 기초적인 방법인 kubeadm을 통해 클러스터를 생성합니다.

또한 실습을 위해 세 가지 리소스를 미리 만듭니다.

  • Password: 1234 값을 가지는 secret credit-card
  • secret credit-card를 환경 변수로 받는 pod app1
  • secret credit-card를 volume(/var/lib/secret)으로 받는 pod app2
apiVersion: v1
kind: Secret
metadata:
name: credit-card
type: Opaque
data:
password: MTIzNA== # "1234"의 base64 인코딩 값
---
apiVersion: v1
kind: Pod
metadata:
name: app1
spec:
containers:
- name: app1-container
image: app1-image
env:
- name: CREDIT_CARD_PASSWORD
valueFrom:
secretKeyRef:
name: credit-card
key: password
---
apiVersion: v1
kind: Pod
metadata:
name: app2
spec:
containers:
- name: app2-container
image: app2-image
volumeMounts:
- name: secret-volume
mountPath: /var/lib/secret
volumes:
- name: secret-volume
secret:
secretName: credit-card

1. etcd 해킹하기

etcd는 쿠버네티스의 클러스터 상태를 저장하는 키-값 데이터 저장소입니다. 쿠버네티스에 선언된 모든 정보가 여기에 저장되기 때문에 secret도 etcd를 조회해보면 알 수 있습니다. 이번 실습 환경에서는 etcd가 암호화되어 있지 않다는 것을 가정하고 진행합니다.

1.1. etcdctl로 비밀번호 찾기

이 방법은 만약 컨트롤 플레인의 정보가 노출되었고, etcd가 암호화되어 있지 않으며, etcd가 있는 서버에 접근할 수 있다는 많은 전제를 바탕으로 합니다.

photo | 인포그랩 GitLab | 인포그랩 GitLab
  1. /etc/kubernetes/manifests 디렉터리에는 쿠버네티스의 동작에 필수적인 정적 pod 메니페스트가 정의되어 있습니다. 그중 kube-apiserver의 메니페스트를 조회해 etcd 서버의 certificate authority(ca), 공개 키(cert)와 개인 키(key)를 가져옵니다.
  2. etcd를 편하게 조작할 수 있는 etcdctl 명령을 통해 비밀번호를 찾습니다. 인증 정보가 손안에 있기 때문에 손쉽게 etcd 내부를 탐색할 수 있습니다.

1.2. etcd DB에 직접 접근해서 가져오기

etcd의 인증 정보는 모르지만, etcd가 존재하는 서버에 칩입했다고 가정해봅시다. etcd가 동작하는 프로세스를 찾고, 해당 프로세스의 데이터를 모두 탐색하면 원하는 비밀번호를 찾을 수 있습니다.

photo | 인포그랩 GitLab | 인포그랩 GitLab
  1. ps aux | grep etcd - etcd의 PID를 가져옵니다.
  2. ll /proc/<pid>/fd를 보면 db라고 적힌 link 파일이 보입니다.
  3. cat /proc/<pid>/fd/<db> | grep -A10 -B10 credit-card 명령을 통해 사전에 만들었던 비밀번호를 찾습니다. 넉넉하게 앞뒤로 10줄씩 추가로 출력합니다.
  4. (옵션) Binary file matches 오류가 뜨면 중간에 strings를 넣어줍니다.

2. Pod 해킹하기

kubeconfig에 적절한 권한이 있거나, node에 직접 접근할 수 있다고 가정합니다.

2.1. kubectl exec을 통해서 가져오기

쿠버네티스를 조회하는 적절한 권한이 있다면, kubectl 명령을 통해 비밀번호를 가져올 수 있습니다. 가장 쉬운 방법입니다.

kubectl exec app1 -- env
kubectl exec app2 -- cat /var/lib/secret/Password
photo | 인포그랩 GitLab | 인포그랩 GitLab

2.2. 컨테이너에 직접 접근해서 가져오기

아무리 쿠버네티스에서 pod에 대한 권한을 설정한다고 해도, 워커 노드 입장에서 쿠버네티스는 단순히 도커 컨테이너의 집합일 뿐입니다. 따라서 워커 노드에서 도커 명령만 자유롭게 쓸 수 있다면 손쉽게 비밀번호를 빼낼 수 있습니다.

photo | 인포그랩 GitLab | 인포그랩 GitLab

위 그림처럼 pod app1이 스케줄 된 워커 노드에서 컨테이너를 찾아, 컨테이너에 등록된 환경 변수 목록을 추출할 수 있습니다.

  1. crictl pods - app1의 Pod ID를 찾습니다.
  2. crictl ps - Pod ID에 상응하는 컨테이너를 찾습니다.
  3. crictl inspect <container id> | grep -A16 env - 해당 컨테이너를 상세 조회해 환경 변수를 추출합니다.

photo | 인포그랩 GitLab | 인포그랩 GitLab

비밀번호가 파일 형태로 저장된 app2의 경우에는 조금 복잡합니다.

  1. 먼저 앞서 설명했던 방법으로 컨테이너를 찾습니다.
  2. crictl inspect <container id> | grep pid - 컨테이너를 상세 조회해서 컨테이너의 프로세스 ID(PID)를 찾습니다.
  3. crictl inspect <container id> | grep -A10 mounts - 또한 secret이 어느 위치에 mount 되었는지도 찾습니다.
  4. /proc/[pid] 디렉터리에서 secret이 마운트된 위치에 접근해 비밀번호를 추출합니다.

2.3. Secret에 접근 권한을 가진 ServiceAccount를 이용해 가져오기

만약 Pod의 ServiceAccount가 secret에 접근할 수 있는 권한을 가진다면, pod 내부에서 API 호출을 통해 비밀번호를 찾을 수 있습니다.

curl https://kubernetes.default/api/v1/namespaces/default/secrets -k \
-H "Authorization: Bearer $(cat /run/secrets/kubernetes.io/serviceaccount/token)"

보안 지키기

사람들은 여러 악의적인 방법으로 여러분의 서비스를 망치려고 합니다. 서비스와 비즈니스 가치를 지키기 위해 촘촘한 보안 전략을 구성이 필요합니다. 앞서 설명한 해킹을 막기 위해서는 첫째, “최소 권한의 원칙”에 따라 불필요한 권한을 가진 service account을 만들지 않습니다. 둘째, 소셜 엔지니어링 등의 위협에 대비해 사용자의 credential이 노출되지 않도록 합니다. 마지막으로 EncryptionConfiguration 리소스를 통해 etcd를 암호화합니다.

맺음말

지금까지 여러 방법으로 쿠버네티스의 secret을 해킹하는 방법에 대해 알아보았습니다. 만약 이 방법으로 악의적인 목적을 가진 해커가 비밀번호를 탈취한다면 정말 천문학적인 손실이 발생합니다. 따라서 전 세계 수많은 기업이 사용하고 있는 쿠버네티스의 보안 문제는 절대 소홀히 다루어서는 안 됩니다. 다음 블로그 포스팅에서는 어떻게 이러한 해킹을 막고 쿠버네티스를 안전하게 지킬 수 있을지 알아보겠습니다.

보안은 과거와 현재를 막론하고 매우 중요하게 당면한 과제입니다. GitLab은 완전한 DevOps를 제공하는 플랫폼으로, DevSecOps를 적용하여 보안을 점검하고 여러 방식으로 보안 수정 사항에 대한 정보를 제공합니다.

인포그랩은 GitLab 및 DevOps에 대한 맞춤 기술 지원을 제공합니다. GitLab(Omnibus/Cloud Native Hybrid) 구축 관련한 지원이 필요하시면 문의하기 로 연락 주십시오.