Skip to main content

SealedSecrets으로 Secret 오브젝트 암호화

현재 Kustomize를 사용해서 클러스터 내 오브젝트들의 매니페스트를 관리하고 있고 깃헙에 푸시되고 있어 base64로 인코딩만 된 secrets을 그대로 올리기에는 보안에 취약하기 때문에 어떤 도구들이 있을까 찾아보다가 SealedSecrets를 발견하였다. SealedSecrets에 대해서 간단하게 말하면 SealedSecrets는 비대칭 암호화를 사용하고 복호화가 가능한 기밀키를 가지고 있어 공개키로 암호화된 SealedSecret 오브젝트를 기밀키로 복호화하여 Secret 오브젝트를 생성해준다.

SealedSecret 작동 방식

SealedSecrets를 사용하는 사용자는 사전에 기밀키와 공개키를 생성한 뒤에 이 기밀키를 SealedSecrets에 넣어준다. 이후에 깃헙에 올라갈 Secret 오브젝트를 공개키로 암호화하여 SealedSecrets로 변경하여 깃헙에 푸시한다. 그러면 깃헙에는 공개키로 암호화된 SealedSecret 오브젝트의 매니페스트만 올라가게 되며 공개키로 암호화가 되어 있기 때문에 어떤 내용인지 알 수가 없다. 이를 SealedSecret 디플로이먼트가 올라가 있는 클러스터에 apply 해주면 SealedSecret 디플로이먼트가 가지고 있는 기밀키로 복호화하여 Secret을 생성한다.

그림으로 표현하자면 아래와 같습니다.

Kubernetes_SealedSecrets

SealedSecret 디플로이먼트 역할

공개키로 암호화된 SealedSecret 오브젝트 --(기밀키로 복호화)--> Secret 오브젝트로 변환

SealedSecret 사용법

먼저 클러스터 내 kube-system 네임스페이스 아래 SealedSecret 디플로이먼트가 생성되어 있다고 가정합니다. 초기 생성시에는 랜덤으로 기밀키와 공개키가 SealedSecret에 등록되어 있기 때문에 내가 만든 기밀키 및 공개키로 업데이트 해준뒤에 디플로이먼트를 재시작해주는 작업이 필요합니다. 여기서 재시작을 해주지 않으면 변경된 키 내용이 반영되지 않으니 재시작은 필수입니다.

# 비밀키 tls.key와 공개키 tls.crt를 생성
$ openssl req -x509 -nodes -newkey rsa:4096 -keyout tls.key -out tls.crt -days 365

# tls.key와 tls.crt를 base64로 인코딩하여 환경변수 설정
$ TLS_CRT=$(cat tls.crt | base64)
$ TLS_KEY=$(cat tls.key | base64)

# SealedSecret 디플로이먼트에서 사용중인 secret에 기밀키와 공개키를 업데이트
$ kubectl patch secret sealed-secrets-keyx9wtt -n kube-system --type='json' -p="[
{'op': 'replace', 'path': '/data/tls.crt', 'value':'${TLS_CRT}'},
{'op': 'replace', 'path': '/data/tls.key', 'value':'${TLS_KEY}'}
]"

# 키를 갱신한 이후 디플로이먼트 재시작이 필수
$ kubectl rollout restart -n kube-system deployment/sealed-secrets-controller

다음은 로컬에 있는 Secret 중 깃헙에 올라갈 Secret을 위에서 만든 공개키로 암호화합니다. 본문에서는 공개키로 암호화한다고 표현하였지만 엄밀히 말하면 Secret 오브젝트를 공개키로 암호화된 SealedSecret 오브젝트로 변경하는 것입니다. 제가 만든 공개키는 /Users/jinhyeokhong/.ssh/sealed-secrets/tls.crt에 위치합니다.

여기서 몇가지 주의할 점이 있습니다.

  • 공개키로 암호화할 때 새로 생성되는 파일명이 같을 경우 덮어쓰게 되는데 덮어쓰기가 되지 않아 EMPTY가 된다.
  • 정확하게 표현하면 Secret을 SealedSecret로 만들 때 새로 생성되는 파일명이 같을 경우 덮어쓰게 되는데 덮어쓰기가 되지 않아 EMPTY가 된다.
  • 따라서 STDOUT을 리다이렉트하여 파일로 저장할 때의 파일명은 Secret 파일명과 다르게 해야합니다.
# Secret 오브젝트를 SealedSecret 오브젝트로 변경
$ cat redis.yaml | kubeseal --cert=/Users/jinhyeokhong/.ssh/sealed-secrets/tls.crt -o yaml > ./redis2.yaml

이후 SealedSecret 오브젝트를 apply하여 클러스터에 적용하면 SealedSecret 디플로이먼트가 SealedSecret 오브젝트를 복호화하여 Secret 오브젝트로 변경합니다.

마지막으로 아래 base64로 인코딩된 Secret 오브젝트와 제가 생성한 공개키로 암호화된 SealedSecret 오브젝트의 매니페스트 예시를 보여드리고 마무리하고자 합니다.

Secret Object manifest

apiVersion: v1
kind: Secret
metadata:
name: redis
namespace: test
labels:
project: test
type: Opaque
data:
host: dGVzdA==

SealedSecret Object manifest

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: redis
namespace: test
spec:
encryptedData:
host: AgBwxRavICV3kUSjCzacETrWJ2LaBe3IsDTYhnG74oK225kPFHU0PMscYEEJpSs9sYtwSpyIM0KzSa4zTKSZCaW58dlu49aqnS8MjlPlC+G4vbbRAzlrAqN+OKtKAX25bJHHvp1EMO2oQQn8HLBbxHGJhHycCAvxO8BooKRyjJ56SniUxM9pR3WwlfclVSiU7YNP9hZz1zHyGzd1bWNXlVXPVE994OzayfL+QQ1NaRZ/7cFL0MvmZdoeL5ZdBwbRzL+ertYHz7XrULSdnja3RokXlKzKNUc7PjCLj52UrpsjXVEvKK8VpDlTYNVCCDdv32yUHsXdhqzGm76En5fXhA96U2vSbSZrW8uhG5Asx/PhMAZmIP18XVeK5j9Z22jNxvxXnXr4x1Mb5ihLLp+jwfwIdKmULNngik0Sq1LSUe6GVhtLJEuHwLEAx7m9LJwyxOkUJ5W1IvnbM3jxn3PPhyPhH+beN7gqJZdaoNNIM2G6LSF7NyA4R4gdDLAZRYb8p88vKlUGPYK9FyBXXLUshlBH2tQLQGtNDKV6bUIZROzLvuQ3nQw7END/oRLvVfHBefStuwyta1SEB1kEd5vDNpNhJ7TLstSPEJHBck1pajOTXuxN/efAh8GwvKyXuoLrZT/FTzTVPO05wkQRGiLnqCOsHy4yjuk8b0OCDt4Gy8suljkNyEPpZ9+jc2xPK9f8CvgnI920
template:
metadata:
labels:
project: test
name: redis
namespace: test
type: Opaque