Sealed Secrets으로 Kubernetes Secret 안전하게 관리하기

김유경·2025년 6월 19일

들어가며

일반적으로 쿠버네티스 Secret 리소스는 단순히 base64로 인코딩된 형태로 저장됩니다. 그러나 base64는 암호화가 아닌 단순한 인코딩 방식이기 때문에, 이를 Git에 그대로 커밋하는 것은 보안상 큰 위험을 초래할 수 있습니다.

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
data:
  password: cGFzc3dvcmQxMjM=  # 'password123'의 base64 인코딩 값

GitOps 환경에서 Secret을 보다 안전하게 관리할 방법을 고민하던 중, LG U+ 기술블로그 글을 접하게 되었습니다.

😃 GitOps 환경에 적합하다고 생각하였고, 직접 도입해 보며 활용해 보기로 했습니다.


Sealed Secrets란?

🔗 GitHub 바로가기

Sealed Secrets는 쿠버네티스 Secret을 안전하게 Git에 저장할 수 있도록 암호화해주는 오픈소스입니다

핵심 개념

  • 공개키로 Secret을 암호화 → Git 저장소에 커밋
  • 클러스터 내 컨트롤러가 개인키로 복호화 → 일반 Secret 생성
  • 암호화된 상태로 Git에 저장하므로 외부 노출에도 안전

동작 구조

개발자 → kubeseal → SealedSecret(YAML) → Git 커밋
                                          ↓
              클러스터: Sealed Secrets Controller → 복호화 → Kubernetes Secret 생성

암호화 흐름 요약

  1. kubectl create secret으로 일반 Secret 생성
  2. kubeseal로 암호화하여 SealedSecret 생성
  3. Git에 커밋 후 배포
  4. 클러스터 내 Controller가 복호화하여 실제 Secret 생성

설치 방법

컨트롤러 설치

kubectl 방식

kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml

Helm 차트 방식

# Helm 저장소 추가
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets

# 설치
helm install sealed-secrets -n kube-system \
  --set-string fullnameOverride=sealed-secrets-controller \
  sealed-secrets/sealed-secrets

kubeseal 설치

macOS

brew install kubeseal

Linux

wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/kubeseal-0.24.0-linux-amd64.tar.gz
tar -xzf kubeseal-0.24.0-linux-amd64.tar.gz
sudo install -m 755 kubeseal /usr/local/bin/kubeseal

Secret 암호화 및 배포 흐름

1) 공개키(cert) 다운로드

kubeseal --fetch-cert --controller-name=sealed-secrets-controller \
  --controller-namespace=kube-system > sealed-secrets-public.pem

2) 환경변수 파일을 Secret으로 변환 후 암호화

.env.secret 파일 예시

DB_PASSWORD=secret123
API_KEY=abc123

암호화

kubectl create secret generic my-secret \
  --from-env-file=.env.secret \
  --namespace=production \
  --dry-run=client -o yaml | \
  kubeseal --cert sealed-secrets-public.pem -o yaml > sealed-secret.yaml

3) 배포 및 확인

kubectl apply -f sealed-secret.yaml
kubectl get secrets -n production
kubectl get secret my-secret -n production -o yaml

실제 적용 방법

kubeseal은 개발자가 사용하는 커맨드라인 도구로, 일반 Kubernetes Secret을 암호화된 SealedSecret으로 변환해줍니다. YAML 또는 JSON 형식의 Secret 오브젝트를 입력으로 받아, Git 저장소에 안전하게 커밋할 수 있는 SealedSecret 오브젝트로 출력합니다.

🚀 저는 .env.secret 파일 기반으로 암호화 및 배포를 자동화하는 스크립트를 아래와 같이 구성하여 반복적인 작업을 간소화했습니다.

# How to run:
# chmod +x generate-sealed-secret.sh
#./generate-sealed-secret.sh

#!/bin/bash

# === Configuration ===
SECRET_NAME="community-db-secret"
NAMESPACE="dev-community-service"
ENV_FILE=".env.secret"
SECRET_FILE="secret.yaml"
SEALED_SECRET_FILE="../sealed-secret.yaml"

# sealed-secrets-public.pem 파일 경로 확인
if [ -z "$SEALED_SECRETS_CERT" ]; then
    echo "❌ 오류: SEALED_SECRETS_CERT 환경 변수가 설정되지 않았습니다."
    exit 1
fi

if [ ! -f "$SEALED_SECRETS_CERT" ]; then
    echo "❌ 오류: sealed-secrets-public.pem 파일을 찾을 수 없습니다: $SEALED_SECRETS_CERT"
    exit 1
fi

echo "======================================="
echo "Sealed Secret Generation Script (Mac/Linux)"
echo "Location: overlays/develop/community-service/"
echo "======================================="

# Check if the .env.secret file exists
if [ ! -f "$ENV_FILE" ]; then
    echo "$ENV_FILE file is missing. Please create it before running this script."
    exit 1
fi

# Generate Kubernetes Secret YAML
echo "[1/3] Creating Kubernetes Secret YAML..."
kubectl create secret generic $SECRET_NAME \
    --from-env-file=$ENV_FILE \
    --namespace $NAMESPACE \
    --dry-run=client -o yaml > $SECRET_FILE

# Encrypt the Secret using kubeseal
echo "[2/3] Encrypting the Secret with kubeseal..."
kubeseal \
    --cert "$SEALED_SECRETS_CERT" \
    --format yaml < $SECRET_FILE > $SEALED_SECRET_FILE

# Done
echo "[3/3] Done! Output file: $SEALED_SECRET_FILE"
echo "Sealed Secret has been successfully created!"

결과적으로 다음과 같은 구조로 secret을 안전하면서도 GitOps 방식으로 관리할 수 있게 됩니다.


트러블슈팅

Sealed Secret이 제대로 복호화되지 않는 경우, 가장 흔한 원인은 암호화 시 설정한 scope와 배포 시점의 정보가 일치하지 않기 때문입니다.

kubeseal은 기본적으로 다음 정보를 암호화 범위(scope)에 포함시킵니다.

  • Secret의 이름
  • Secret의 네임스페이스

복호화 시점에 이 정보가 달라지면 Sealed Secrets 컨트롤러는 복호화를 거부하고 Secret을 생성하지 않습니다.

✅ 해결 방법

암호화 시점과 배포 시점의 metadata.name, metadata.namespace가 반드시 일치해야 합니다.

필요에 따라 --scope 옵션을 명시적으로 지정할 수 있습니다.

kubeseal --cert sealed-secrets-public.pem \
  --format yaml \
  --scope namespace-wide  # 또는 cluster-wide, strict (기본값)
  • strict: 이름 + 네임스페이스 모두 일치해야 복호화됨 (기본값)
  • namespace-wide: 동일한 네임스페이스 내에서만 복호화 가능
  • cluster-wide: 어느 네임스페이스에서도 복호화 가능

0개의 댓글