본문 바로가기
카테고리 없음

[AEWS-3기][6주차-도전과제-4][EKS Workshop] EKS Pod Identity Securing Secrets Using Sealed Secrets

by james_janghun 2025. 3. 15.

 

Sealed Secrets은 Bitnami Labs의 서드파티 오픈소스입니다.

 

Sealed Secrets 개요

Sealed Secrets는 시크릿 객체를 암호화하여 공개 저장소에도 안전하게 저장할 수 있는 메커니즘을 제공합니다. SealedSecret은 Kubernetes 클러스터에서 실행되는 컨트롤러에 의해서만 복호화될 수 있으며, 다른 누구도 SealedSecret에서 원래의 시크릿을 얻을 수 없습니다.

이 장에서는 SealedSecrets를 사용하여 Kubernetes 시크릿과 관련된 YAML 매니페스트를 암호화하고, kubectl과 같은 도구를 사용하여 일반적인 워크플로우로 이러한 암호화된 시크릿을 EKS 클러스터에 배포하는 방법을 배울 것입니다.

Sealed Secrets의 주요 이점

  1. 보안 강화: 암호화된 시크릿은 공개 저장소에 안전하게 저장될 수 있습니다.
  2. GitOps 호환: 암호화된 시크릿을 Git 저장소에 저장하고 GitOps 워크플로우에 통합할 수 있습니다.
  3. 중앙 집중식 관리: 클러스터 컨트롤러가 시크릿 암호화 및 복호화를 담당합니다.
  4. 롤백 지원: 이전 버전의 암호화된 시크릿으로 쉽게 롤백할 수 있습니다.

이어지는 실습에서는 Sealed Secrets를 사용하여 시크릿을 암호화하고, 이를 클러스터에 배포하는 방법을 단계별로 배우게 됩니다.

 

Sealed Secrets for Kubernetes 작동 원리

구성 요소

Sealed Secrets는 두 부분으로 구성됩니다.

  • 클러스터 측 컨트롤러
  • kubeseal이라는 클라이언트 측 CLI 도구

키 관리 메커니즘

컨트롤러가 시작되면 클러스터 전체 비공개/공개 키 쌍을 찾고, 없는 경우 새로운 4096비트 RSA 키 쌍을 생성합니다. 비공개 키는 컨트롤러와 동일한 네임스페이스(기본적으로 kube-system)에 Secret 객체로 저장됩니다. 이 키 쌍의 공개 키 부분은 이 클러스터에서 SealedSecrets를 사용하려는 모든 사용자에게 공개적으로 제공됩니다.

암호화 과정

암호화 과정에서는 원본 Secret의 각 값이 무작위로 생성된 세션 키를 사용하여 AES-256으로 대칭 암호화됩니다. 그런 다음 세션 키는 컨트롤러의 공개 키를 사용하여 SHA256과 원본 Secret의 네임스페이스/이름을 입력 매개변수로 사용하여 비대칭적으로 암호화됩니다. 암호화 과정의 출력은 다음과 같이 구성된 문자열입니다: 암호화된 세션 키의 길이(2바이트) + 암호화된 세션 키 + 암호화된 Secret

복호화 과정

SealedSecret 커스텀 리소스가 Kubernetes 클러스터에 배포되면, 컨트롤러가 이를 감지하고 비공개 키를 사용하여 봉인을 해제한 다음 Secret 리소스를 생성합니다. 복호화 과정에서는 SealedSecret의 네임스페이스/이름이 다시 입력 매개변수로 사용됩니다. 이를 통해 SealedSecret과 Secret이 동일한 네임스페이스와 이름에 엄격하게 연결됩니다.

kubeseal CLI 도구

동반 CLI 도구인 kubeseal은 공개 키를 사용하여 Secret 리소스 정의에서 SealedSecret 커스텀 리소스 정의(CRD)를 생성하는 데 사용됩니다. kubeseal은 Kubernetes API 서버를 통해 컨트롤러와 통신하고 실행 시 Secret을 암호화하는 데 필요한 공개 키를 검색할 수 있습니다. 공개 키는 컨트롤러에서 다운로드하여 로컬에 저장하여 오프라인으로 사용할 수도 있습니다.

SealedSecrets의 범위

SealedSecrets는 다음과 같은 세 가지 범위를 가질 수 있습니다:

  • strict (기본값) : 시크릿은 정확히 동일한 이름과 네임스페이스로 봉인되어야 합니다. 이러한 속성은 암호화된 데이터의 일부가 되므로 이름 및/또는 네임스페이스를 변경하면 "복호화 오류"가 발생합니다.
  • namespace-wide : 봉인된 시크릿은 지정된 네임스페이스 내에서 자유롭게 이름을 바꿀 수 있습니다.
  • cluster-wide : 시크릿은 어느 네임스페이스에서나 봉인 해제될 수 있으며 아무 이름이나 지정할 수 있습니다.

이러한 범위를 통해 시크릿 관리의 유연성과 보안성 사이의 균형을 맞출 수 있습니다.

 

Sealed Secrets 설치

컨트롤러 설치

sealed secrets 컨트롤러를 설치합니다.

kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.18.0/controller.yaml
kubectl wait --for=condition=Ready --timeout=30s pods -l name=sealed-secrets-controller -n kube-system

 

확인해보겠습니다.

kubectl get pods -n kube-system -l name=sealed-secrets-controller

 

컨트롤러 로그를 확인해봅니다.

kubectl logs deployments/sealed-secrets-controller -n kube-system

sealed secrets 컨트롤러의 로그에는 컨트롤러가 시작 중에 기존 비공개 키를 찾으려고 시도하는 것을 보여줍니다. 비공개 키가 없으면 인증서 정보가 포함된 새 시크릿을 생성합니다.

 

시크릿 키 확인

다음과 같이 public/private 키 쌍 형태로 yaml 형식의 봉인 키가 포함된 secret 내용을 볼 수 있습니다.

kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml

이제 kubeseal이라는 CLI를 사용해 sealed secrets 컨트롤러와 상호작용이 가능합니다.

 

Secrets 만들기

실습에서는 catalog Deployment는 데이터베이스 값을 catalog-db라는 secret의 환경변수를 통해서 접근하게 됩니다.

DB_USER, DB_PASSWORD라는 두개의 키를 가집니다.

시크릿을 살펴보면 단순히 base64로만 인코딩 되어있어 디코딩이 쉽습니다.

kubectl -n catalog get deployment catalog -o yaml | yq '.spec.template.spec.containers[] | .env'

 

kubectl -n catalog get secrets catalog-db --template {{.data.username}} | base64 -d
# catalog_user

kubectl -n catalog get secrets catalog-db --template {{.data.password}} | base64 -d
# default_password

 

시크릿을 생성해보겠습니다.

 

kubeseal --format=yaml < ~/environment/eks-workshop/modules/security/sealed-secrets/new-catalog-db.yaml \
  > /tmp/sealed-catalog-db.yaml
# ~/environment/eks-workshop/modules/security/sealed-secrets/new-catalog-db.yaml
apiVersion: v1
kind: Secret
metadata:
  name: catalog-sealed-db
  namespace: catalog
type: Opaque
data:
  password: ZGVmYXVsdF9wYXNzd29yZA==
  username: Y2F0YWxvZ191c2Vy

 

kubeseal을 사용해 sealedSecret Yaml 매니페스트를 생성합니다.

kubeseal --format=yaml < ~/environment/eks-workshop/modules/security/sealed-secrets/new-catalog-db.yaml \
  > /tmp/sealed-catalog-db.yaml

 

또는 컨트롤러에서 공개 키를 가져와 오프라인으로 시크릿을 sealing합니다.

kubeseal --fetch-cert > /tmp/public-key-cert.pem
kubeseal --cert=/tmp/public-key-cert.pem --format=yaml < ~/environment/eks-workshop/modules/security/sealed-secrets/new-catalog-db.yaml \
  > /tmp/sealed-catalog-db.yaml

 

해당 sealed-catalog-db.yaml이라는 파일을 이용해서 EKS 클러스터에 배포해봅니다.

kubectl apply -f /tmp/sealed-catalog-db.yaml

 

컨트롤러 로그를 확인해보면 방금 배포한 SealedSecret CRD를 감지하고 일반 시크릿으로 변환하는 것을 확인할 수 있습니다.

kubectl logs deployments/sealed-secrets-controller -n kube-system

 

SealedSecret에서 봉인 해제된 catalog-sealed-db 시크릿이 컨트롤러에 의해 catalog 네임스페이스에 배포되었는지 확인합니다.

kubectl get secret -n catalog catalog-sealed-db

 

배포 업데이트하기

이제 위 시크릿에서 읽는 catalog 배포를 재배포해봅니다. catalog-sealed-db 시크릿을 읽도록 catalog 배포를 다음과 같이 변경합니다.

kubectl apply -k ~/environment/eks-workshop/modules/security/sealed-secrets
kubectl rollout status -n catalog deployment/catalog --timeout 30s

 

# ~/environment/eks-workshop/modules/security/sealed-secrets/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: catalog
spec:
  template:
    spec:
      containers:
        - name: catalog
          env:
            - name: DB_USER
              valueFrom:
                secretKeyRef:
                  name: catalog-sealed-db
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: catalog-sealed-db

 

Sealed Secrets를 사용함으로써 시크릿 정보를 안전하게 저장하고 배포할 수 있을 뿐 아니라 이번 예시를 통해서 SealedSecret 리소스를 위한 yaml은 다른 일반적인 yaml과 함께 저장하거나 활용할 수 있다는 장점이 매력적인것을 확인할 수 있습니다.