일반적으로 쿠버네티스 Secret 리소스는 단순히 base64로 인코딩된 형태로 저장됩니다. 그러나 base64는 암호화가 아닌 단순한 인코딩 방식이기 때문에, 이를 Git에 그대로 커밋하는 것은 보안상 큰 위험을 초래할 수 있습니다.
apiVersion: v1
kind: Secret
metadata:
name: db-secret
data:
password: cGFzc3dvcmQxMjM= # 'password123'의 base64 인코딩 값
GitOps 환경에서 Secret을 보다 안전하게 관리할 방법을 고민하던 중, LG U+ 기술블로그 글을 접하게 되었습니다.
😃 GitOps 환경에 적합하다고 생각하였고, 직접 도입해 보며 활용해 보기로 했습니다.
Sealed Secrets는 쿠버네티스 Secret을 안전하게 Git에 저장할 수 있도록 암호화해주는 오픈소스입니다
핵심 개념
동작 구조
개발자 → kubeseal → SealedSecret(YAML) → Git 커밋
↓
클러스터: Sealed Secrets Controller → 복호화 → Kubernetes 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
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)에 포함시킵니다.
복호화 시점에 이 정보가 달라지면 Sealed Secrets 컨트롤러는 복호화를 거부하고 Secret을 생성하지 않습니다.
✅ 해결 방법
암호화 시점과 배포 시점의 metadata.name, metadata.namespace가 반드시 일치해야 합니다.
필요에 따라 --scope 옵션을 명시적으로 지정할 수 있습니다.
kubeseal --cert sealed-secrets-public.pem \
--format yaml \
--scope namespace-wide # 또는 cluster-wide, strict (기본값)