공부/Kubernetes

Kubernetes Secret은 정말 Secret일까?

토고미 2021. 3. 25. 10:00

개발을 하다 보면 아이디, 비밀번호 등 민감 정보가 필요할 때가 필연적으로 생긴다.

 

쿠버네티스에서는 이러한 경우를 위해 시크릿을 사용한다.

공식문서에는 다음과 같이 쓰여있다.

 

쿠버네티스 시크릿을 사용하면 비밀번호, OAuth 토큰, ssh 키와 같은 민감한 정보를 저장하고 관리할 수 ​​있다. 기밀 정보를 시크릿에 저장하는 것이 파드(Pod) 정의나 컨테이너 이미지 내에 그대로 두는 것보다 안전하고 유연하다.

 

시크릿을 만들 때는 아래처럼 base64로 인코딩 된 값을 넘겨준다.

apiVersion: v1
kind: Secret
metadata:
  name: sample-secret
data:
  sample_key: c2FtcGxlX3ZhbHVl

나는 여기서 의문이 들었다. 아니, 쿠버네티스를 모르는 사람이 봐도 같은 의문이 들 것이다.

 

민감 정보가 인코딩(encoding) 됐을 뿐, 암호화(encrypted) 된 건 아니지 않나? 하는 의문 말이다.

base 64로 인코딩 한다는 것 이외에는 평문으로 저장하는 컨피그맵과 다를 게 없다는 것이다.

 

예를 들어, 침입자가 kubectl get secret sample-secret -o yaml 명령어를 입력 후, 밸류 값을 디코딩하면

sapmle_key: sample_value 라는 것을 손쉽게 알아낼 수 있다.

 

그럼 도대체 시크릿을 쓰는 의미가 무엇인가?

 

 

그래서 쿠버네티스에서는 시크릿을 안전하게 사용하는 방법 두 가지를 제시하고 있다.

공식 문서에 다음과 같이 나와있다.

 

쿠버네티스 시크릿은 기본적으로 암호화되지 않은 base64 인코딩 문자열로 저장된다. 기본적으로 API 액세스 권한이 있는 모든 사용자 또는 쿠버네티스의 기본 데이터 저장소 etcd에 액세스 할 수 있는 모든 사용자가 일반 텍스트로 검색할 수 있다. 시크릿을 안전하게 사용하려면 (최소한) 다음과 같이 하는 것이 좋다.

  1. 시크릿에 대한 암호화 활성화.
  2. 시크릿 읽기 및 쓰기를 제한하는 RBAC 규칙 활성화 또는 구성. 파드를 만들 권한이 있는 모든 사용자는 시크릿을 암묵적으로 얻을 수 있다.

 

내가 가지고 있는 의문점에 대한 직접적인 대답은 2번이 가깝다.

아무나 secret get / describe 등의 명령어를 하지 못하도록 제한하는 것이다.

 

롤, 클러스터 롤을 이용하면 이를 구현할 수 있다.

아래와 같은 롤을 만든 뒤, 특정 유저 혹은 서비스 어카운트 등에 바인딩을 해서 신뢰할 수 있는 자만 secret에 접근할 수 있도록 하는 것이다.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

 

kubectl get secret에 실패한 침입자가 이번엔 etcd를 노린다면, 어떻게 막아야 할까?

그것이 1번에 나와있는 암호화 활성화이다.

 

쿠버네티스 1.13버전부터 쓸 수 있는 EncryptionConfiguration이라는 리소스를 이용해 암호화하여 etcd에 저장하는 기술이다. 특정 provider를 이용하여 etcd에 암호화하여 저장하고, 조회를 위해서는 해당 키 값을 알고 있어야 한다.

내 의문점과는 거리가 좀 있고 글도 길어지므로 실제 사용법을 다루지는 않겠다.

 

 

하지만 여전히 위험성은 남아있다.

이는 공식문서에도 상세히 기술되어 있다.

위험

  • API 서버에서 시크릿 데이터는 etcd에 저장된다. 따라서,
    • 관리자는 클러스터 데이터에 대해 저장 시 암호화를 활성화해야 한다. (v1.13 이상 필요)
    • 관리자는 etcd에 대한 접근을 admin 사용자로 제한해야 한다.
    • 관리자는 더 이상 사용하지 않을 때 etcd에서 사용하는 디스크를 지우거나 폐기할 수 있다.
    • 클러스터에서 etcd를 실행하는 경우, 관리자는 etcd peer-to-peer 통신에 대해 SSL/TLS를 사용해야 한다.
  • base64로 인코딩된 시크릿 데이터가 있는 매니페스트(JSON 또는 YAML) 파일을 통해 시크릿을 구성하는 경우, 이 파일을 공유하거나 소스 리포지터리에 체크인하면 시크릿이 손상된다. Base64 인코딩은 암호화 방법이 아니며 일반 텍스트와 동일한 것으로 간주된다.
  • 실수로 기록하거나 신뢰할 수 없는 상대방에게 전송하지 않는 것과 같이, 애플리케이션은 볼륨에서 읽은 후에 시크릿 값을 보호해야 한다.
  • 시크릿을 사용하는 파드를 생성할 수 있는 사용자는 해당 시크릿의 값도 볼 수 있다. API 서버 정책이 해당 사용자가 시크릿을 읽을 수 있도록 허용하지 않더라도, 사용자는 시크릿을 노출하는 파드를 실행할 수 있다.
  • 현재, 모든 노드에 대한 루트 권한이 있는 모든 사용자는 kubelet을 가장하여 API 서버에서 모든 시크릿을 읽을 수 있다. 단일 노드에 대한 루트 취약점 공격의 영향을 제한하기 위해, 실제로 필요한 노드에만 시크릿을 보내는 것이 앞으로 계획된 기능이다

 

공식 문서에 나와있는 것 처럼, 파드를 생성할 수 있는 사용자라면 권한과 관계 없이 시크릿을 마운트(혹은 환경변수)하여 값을 볼 수 있다.

또, 모든 노드에 대해 루트 권한이 있는 사용자도 당연히 볼 수 있다.(모든 노드 루트 권한을 탈취한 시점에서 시크릿만이 문제가 아닌 것 같긴 하지만...)

 

 

요악하자면

1. 시크릿은 인코딩될 뿐, 암호화되지 않는다.

2. 이를 안전하게 사용하기 위해 RBAC을 이용해 접근을 제한하고, 암호화 활성화(EncryptionConfiguration)을 이용해 etcd에 암호화하여 저장해야 한다.

3. 그럼에도 완전히 안전한 것은 아니므로, 이를 인지하고 있어야 한다.

 

 

======

참고 사이트

- kubernetes.io/ko/docs/concepts/configuration/secret/

- stackoverflow.com/questions/66777620/kubernetes-secret-is-really-secret

- kubernetes.io/docs/tasks/administer-cluster/encrypt-data/