2026๋…„ Kubernetes ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ ์™„๋ฒฝ ๊ฐ€์ด๋“œ: External Secrets, Vault, ๋ฉด์ ‘ ๋Œ€๋น„

Kubernetes ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ์˜ ๋ชจ๋“  ๊ฒƒ์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค. External Secrets Operator, HashiCorp Vault ์—ฐ๋™, ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ๋ชจ๋ฒ” ์‚ฌ๋ก€, ๊ธฐ์ˆ  ๋ฉด์ ‘ ๋นˆ์ถœ ์งˆ๋ฌธ๊นŒ์ง€ ์ƒ์„ธํžˆ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

Kubernetes Secrets Management with External Secrets Operator and HashiCorp Vault architecture diagram

Kubernetes ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ๋Š” ์ปจํ…Œ์ด๋„ˆ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ณด์•ˆ ๊ณผ์ œ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ๋„ค์ดํ‹ฐ๋ธŒ Kubernetes Secret์€ ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋ฅผ base64 ์ธ์ฝ”๋”ฉ์œผ๋กœ ์ €์žฅํ•˜์ง€๋งŒ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์ €์žฅ ์‹œ ์•”ํ˜ธํ™”๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ทจ์•ฝ์ ์€ DevOps ์ฑ„์šฉ ๋ฉด์ ‘์—์„œ ์ž์ฃผ ๋‹ค๋ค„์ง€๋Š” ๋ณด์•ˆ ์œ„ํ—˜์„ ์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค.

๋ฉด์ ‘ ์ฆ‰๋‹ต ํฌ์ธํŠธ

Kubernetes ์‹œํฌ๋ฆฟ ๋ณด์•ˆ์— ๋Œ€ํ•ด ์งˆ๋ฌธ๋ฐ›์„ ๋•Œ: ๋„ค์ดํ‹ฐ๋ธŒ Secret์€ base64 ์ธ์ฝ”๋”ฉ์ด๋ฉฐ ์•”ํ˜ธํ™”๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” HashiCorp Vault ๋˜๋Š” AWS Secrets Manager์™€ ๊ฐ™์€ ์™ธ๋ถ€ ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ์ž๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ, External Secrets Operator(ESO)๋ฅผ ํ†ตํ•ด ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ถ„๋ฆฌ๋ฅผ ํ†ตํ•ด ์‹œํฌ๋ฆฟ์ด Git ์ €์žฅ์†Œ์— ์กด์žฌํ•˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

๋„ค์ดํ‹ฐ๋ธŒ Kubernetes Secret์˜ ํ•œ๊ณ„

๋‚ด์žฅ Secret ๋ฆฌ์†Œ์Šค๋Š” etcd์— base64 ์ธ์ฝ”๋”ฉ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด ์ธ์ฝ”๋”ฉ์€ ๋‹จ์ผ ๋ช…๋ น์œผ๋กœ ๋ณต์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

bash
# decoding-secret.sh
# Kubernetes ์‹œํฌ๋ฆฟ ๊ฐ’์„ ์ฆ‰์‹œ ๋””์ฝ”๋”ฉ
kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d

base64๋Š” ์•”ํ˜ธํ™”๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ํด๋Ÿฌ์Šคํ„ฐ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์žˆ๋Š” ์‚ฌ๋žŒ์ด๋ผ๋ฉด ๋ˆ„๊ตฌ๋‚˜ ์‹œํฌ๋ฆฟ ๊ฐ’์„ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Kubernetes ๋ฌธ์„œ์—์„œ๋Š” Secret์ด "๊ธฐ๋ณธ์ ์œผ๋กœ ์•”ํ˜ธํ™”๋˜์ง€ ์•Š๋Š”๋‹ค"๊ณ  ๋ช…์‹œํ•˜๋ฉฐ, ์ €์žฅ ์‹œ ์•”ํ˜ธํ™”๋ฅผ ํ™œ์„ฑํ™”ํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ์„ธ ๊ฐ€์ง€ ์ฃผ์š” ์ œํ•œ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ๊ฐ์‚ฌ ์ถ”์  ๋ถ€์žฌ: ๋„ค์ดํ‹ฐ๋ธŒ Secret์€ ๋ˆ„๊ฐ€ ์–ธ์ œ ์–ด๋–ค ๊ฐ’์— ์ ‘๊ทผํ–ˆ๋Š”์ง€์— ๋Œ€ํ•œ ๋กœ๊ทธ๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
  2. ๋กœํ…Œ์ด์…˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๋ถ€์žฌ: ์‹œํฌ๋ฆฟ ๋ณ€๊ฒฝ์—๋Š” ์ˆ˜๋™ ๊ฐœ์ž…๊ณผ Pod ์žฌ์‹œ์ž‘์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค
  3. GitOps ๋น„ํ˜ธํ™˜์„ฑ: ์•”ํ˜ธํ™”๋œ ์‹œํฌ๋ฆฟ์„ Git์— ์ €์žฅํ•ด๋„ ์•”ํ˜ธํ™” ํ‚ค ๊ด€๋ฆฌ ๋ฌธ์ œ๊ฐ€ ๋‚จ์Šต๋‹ˆ๋‹ค

External Secrets Operator ์•„ํ‚คํ…์ฒ˜

External Secrets Operator(ESO)๋Š” Kubernetes์™€ ์™ธ๋ถ€ ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์„ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. 2023๋…„ CNCF Sandbox ํ”„๋กœ์ ํŠธ๋กœ ์ถœ์‹œ๋˜์–ด 2026๋…„์— v0.10์— ๋„๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค. ESO๋Š” AWS Secrets Manager, HashiCorp Vault, Google Secret Manager, Azure Key Vault ๋ฐ 15๊ฐœ ์ด์ƒ์˜ ๋ฐฑ์—”๋“œ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์•„ํ‚คํ…์ฒ˜๋Š” ์„ธ ๊ฐ€์ง€ ์ปค์Šคํ…€ ๋ฆฌ์†Œ์Šค๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค:

yaml
# secret-store.yaml
# ClusterSecretStore๋Š” Vault๋กœ์˜ ์—ฐ๊ฒฐ์„ ์ •์˜
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: vault-backend
spec:
  provider:
    vault:
      server: "https://vault.internal:8200"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "external-secrets"
          serviceAccountRef:
            name: "external-secrets"
            namespace: "external-secrets"

์ด ClusterSecretStore๋Š” Kubernetes ์„œ๋น„์Šค ๊ณ„์ • ํ† ํฐ์„ ์‚ฌ์šฉํ•˜์—ฌ Vault์—์„œ ์ธ์ฆํ•˜๋„๋ก ESO๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. kubernetes ์ธ์ฆ ๋ฐฉ์‹์€ ํด๋Ÿฌ์Šคํ„ฐ์˜ TokenReview API์— ๋Œ€ํ•ด ์„œ๋น„์Šค ๊ณ„์ • JWT๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

yaml
# external-secret.yaml
# ExternalSecret์€ ์‹ค์ œ ์‹œํฌ๋ฆฟ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€ ๋™๊ธฐํ™”
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: database-credentials
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore
  target:
    name: db-secret
    creationPolicy: Owner
  data:
    - secretKey: username
      remoteRef:
        key: secret/data/production/database
        property: username
    - secretKey: password
      remoteRef:
        key: secret/data/production/database
        property: password

ESO๋Š” 1์‹œ๊ฐ„๋งˆ๋‹ค Vault๋ฅผ ํด๋งํ•˜๊ณ (refreshInterval: 1h), Kubernetes Secret์„ ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. creationPolicy: Owner๋Š” ExternalSecret์ด ์‚ญ์ œ๋  ๋•Œ Secret๋„ ์‚ญ์ œ๋˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

HashiCorp Vault ์—ฐ๋™ ํŒจํ„ด

Vault๋Š” ๋™์  ์‹œํฌ๋ฆฟ, ์ž๋™ ๋กœํ…Œ์ด์…˜, ํฌ๊ด„์ ์ธ ๊ฐ์‚ฌ ๋กœ๊น…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Vault Kubernetes ์ธ์ฆ ๋ฌธ์„œ์— ์„ค๋ช…๋œ Kubernetes ์ธ์ฆ ๋ฐฉ์‹์„ ํ†ตํ•ด ์žฅ๊ธฐ ์ž๊ฒฉ ์ฆ๋ช…์„ ๋ฐฐํฌํ•˜์ง€ ์•Š๊ณ ๋„ Pod๊ฐ€ ์ธ์ฆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Vault ์ธ์ฆ ์„ค์ •์—๋Š” ์„ธ ๊ฐ€์ง€ ๋‹จ๊ณ„๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค:

bash
# vault-k8s-auth.sh
# Vault์—์„œ Kubernetes ์ธ์ฆ ๋ฐฉ์‹ ํ™œ์„ฑํ™”
vault auth enable kubernetes

# Kubernetes API์— ๋Œ€ํ•ด ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๋„๋ก Vault ๊ตฌ์„ฑ
vault write auth/kubernetes/config \
  kubernetes_host="https://kubernetes.default.svc:443" \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

# ์„œ๋น„์Šค ๊ณ„์ •์„ ์ •์ฑ…์— ๋ฐ”์ธ๋”ฉํ•˜๋Š” ์—ญํ•  ์ƒ์„ฑ
vault write auth/kubernetes/role/external-secrets \
  bound_service_account_names=external-secrets \
  bound_service_account_namespaces=external-secrets \
  policies=readonly-secrets \
  ttl=1h

์ด ๊ตฌ์„ฑ์€ external-secrets ์„œ๋น„์Šค ๊ณ„์ •์„ Vault ์ •์ฑ…์— ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค. TTL์€ ํ† ํฐ ์œ ํšจ ๊ธฐ๊ฐ„์„ ์ œํ•œํ•˜์—ฌ ์žฌ์ธ์ฆ์„ ๊ฐ•์ œํ•˜๊ณ , ์†์ƒ๋œ ํ† ํฐ์˜ ์˜ํ–ฅ ๋ฒ”์œ„๋ฅผ ์ค„์ž…๋‹ˆ๋‹ค.

ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ์—์„œ๋Š” ์ตœ์†Œ ๊ถŒํ•œ ์›์น™์„ ๋”ฐ๋ฅด๋Š” ์ •์ฑ…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค:

hcl
# readonly-secrets.hcl
# ํŠน์ • ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์ฝ๊ธฐ ์ „์šฉ ์ ‘๊ทผ์„ ๋ถ€์—ฌํ•˜๋Š” Vault ์ •์ฑ…
path "secret/data/production/*" {
  capabilities = ["read"]
}

path "secret/metadata/production/*" {
  capabilities = ["list"]
}

์ด ์ •์ฑ…์€ ํ”„๋กœ๋•์…˜ ์‹œํฌ๋ฆฟ ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์ฝ๊ธฐ ์ ‘๊ทผ๋งŒ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ™˜๊ฒฝ์„ ๊ด€๋ฆฌํ•˜๋Š” ํŒ€์€ ํ•ด๋‹น ๊ฒฝ๋กœ ์ œํ•œ์ด ์žˆ๋Š” ๋ณ„๋„์˜ ์ •์ฑ…์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

๋‹ค์šดํƒ€์ž„ ์—†๋Š” ์‹œํฌ๋ฆฟ ๋กœํ…Œ์ด์…˜

์ž๋™ ๋กœํ…Œ์ด์…˜์€ ์‹œํฌ๋ฆฟ์ด ๋…ธํ›„ํ™”๋œ ๊ณต๊ฒฉ ๋ฒกํ„ฐ๊ฐ€ ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ESO๋Š” Kubernetes ์ธก์„ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์žฌ์‹œ์ž‘ ์—†์ด ์‹œํฌ๋ฆฟ์„ ๋‹ค์‹œ ๋กœ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ œ๋กœ ๋‹ค์šดํƒ€์ž„ ๋กœํ…Œ์ด์…˜์„ ์œ„ํ•œ ๋‘ ๊ฐ€์ง€ ์ ‘๊ทผ ๋ฐฉ์‹์ด ์žˆ์Šต๋‹ˆ๋‹ค:

ํŒŒ์ผ ๊ฐ์‹œ๋ฅผ ํ†ตํ•œ ๋ณผ๋ฅจ ๋งˆ์šดํŠธ ์‹œํฌ๋ฆฟ:

yaml
# deployment-volume-secrets.yaml
# ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜๋Š” ํŒŒ์ผ๋กœ ์‹œํฌ๋ฆฟ ๋งˆ์šดํŠธ
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
spec:
  template:
    spec:
      containers:
        - name: api
          image: api:v2.1.0
          volumeMounts:
            - name: secrets
              mountPath: /etc/secrets
              readOnly: true
      volumes:
        - name: secrets
          secret:
            secretName: db-secret

Kubernetes๋Š” kubelet ๋™๊ธฐํ™” ๊ธฐ๊ฐ„ ๋‚ด(๊ธฐ๋ณธ 1๋ถ„)์— ๋งˆ์šดํŠธ๋œ ์‹œํฌ๋ฆฟ ํŒŒ์ผ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๊ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์‹œ /etc/secrets/password์—์„œ ์ž๊ฒฉ ์ฆ๋ช…์„ ์ฝ์–ด ์žฌ์‹œ์ž‘ ์—†์ด ์ƒˆ ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์‹œํฌ๋ฆฟ์„ ์œ„ํ•œ Reloader:

ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—๋Š” Pod ์žฌ์‹œ์ž‘์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. Stakater Reloader๊ฐ€ ์ด๋ฅผ ์ž๋™ํ™”ํ•ฉ๋‹ˆ๋‹ค:

yaml
# deployment-with-reloader.yaml
# ์–ด๋…ธํ…Œ์ด์…˜์ด ์‹œํฌ๋ฆฟ ๋ณ€๊ฒฝ ์‹œ ๋กค๋ง ์žฌ์‹œ์ž‘์„ ํŠธ๋ฆฌ๊ฑฐ
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
  annotations:
    reloader.stakater.com/auto: "true"
spec:
  template:
    spec:
      containers:
        - name: api
          envFrom:
            - secretRef:
                name: db-secret

Reloader๋Š” Secret ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฐ์‹œํ•˜๊ณ  ๋กค๋ง ์žฌ์‹œ์ž‘์„ ์ˆ˜ํ–‰ํ•˜์—ฌ ๋กœํ…Œ์ด์…˜ ์ค‘ ๊ฐ€์šฉ์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

DevOps ๋ฉด์ ‘ ์ค€๋น„๊ฐ€ ๋˜์…จ๋‚˜์š”?

์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ, flashcards, ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์—ฐ์Šตํ•˜์„ธ์š”.

Kubernetes ์‹œํฌ๋ฆฟ ๋ฉด์ ‘ ์งˆ๋ฌธ

DevOps ๋ฉด์ ‘์—์„œ๋Š” ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ์— ๋Œ€ํ•œ ์ดํ•ด๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์งˆ๋ฌธ์€ ์ฃผ๋‹ˆ์–ด๋ถ€ํ„ฐ ์‹œ๋‹ˆ์–ด ๋ ˆ๋ฒจ๊นŒ์ง€ ์ถœ์ œ๋ฉ๋‹ˆ๋‹ค:

Q: Kubernetes Secret์ด ์‚ฌ์šฉํ•˜๋Š” ์ธ์ฝ”๋”ฉ์€ ๋ฌด์—‡์ด๋ฉฐ, ์™œ ๋ณด์•ˆ์— ๋ถˆ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๊นŒ?

Secret์€ base64 ์ธ์ฝ”๋”ฉ์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์ด๋Š” ๊ฐ€์—ญ ๋ณ€ํ™˜์ด์ง€ ์•”ํ˜ธํ™”๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. Secret์— ๋Œ€ํ•œ get ๊ถŒํ•œ์ด ์žˆ๋Š” ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ’์„ ๋””์ฝ”๋”ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณด์•ˆ์„ ์œ„ํ•ด์„œ๋Š” ์ €์žฅ ์‹œ ์•”ํ˜ธํ™”(etcd ์•”ํ˜ธํ™” ํ™œ์„ฑํ™”)์™€ RBAC ๊ถŒํ•œ ์ œํ•œ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋” ๊นŠ์€ Kubernetes ๊ฐœ๋…์— ๋Œ€ํ•ด์„œ๋Š” Kubernetes ๋ฉด์ ‘ ๊ธฐ์ดˆ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

Q: GitOps๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์‹œํฌ๋ฆฟ์ด Git ์ €์žฅ์†Œ์— ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๋„๋ก ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

External Secrets Operator๋Š” ๊ฐ’ ์ž์ฒด๊ฐ€ ์•„๋‹Œ ์‹œํฌ๋ฆฟ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋งŒ Git์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ExternalSecret ๋งค๋‹ˆํŽ˜์ŠคํŠธ์—๋Š” Vault ๋˜๋Š” AWS Secrets Manager์˜ ์‹œํฌ๋ฆฟ ๊ฒฝ๋กœ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ, ์‹ค์ œ ์‹œํฌ๋ฆฟ์€ ์ €์žฅ์†Œ์— ์ ˆ๋Œ€ ์ ‘์ด‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Bitnami์˜ Sealed Secrets๋Š” ๋น„๋Œ€์นญ ์•”ํ˜ธํ™”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์•ˆ์  ์ ‘๊ทผ ๋ฐฉ์‹์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Q: SecretStore์™€ ClusterSecretStore์˜ ์ฐจ์ด์ ์„ ์„ค๋ช…ํ•˜์‹ญ์‹œ์˜ค.

SecretStore๋Š” ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋ฒ”์œ„์ž…๋‹ˆ๋‹ค: ๋™์ผํ•œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์˜ ExternalSecrets๊ฐ€ ์ด๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ClusterSecretStore๋Š” ํด๋Ÿฌ์Šคํ„ฐ ์ „์ฒด ๋ฒ”์œ„์ž…๋‹ˆ๋‹ค: ๋ชจ๋“  ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—์„œ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ํŒ€์ด ๋‹จ์ผ Vault ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•  ๋•Œ๋Š” ClusterSecretStore๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ๊ฐ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๊ฐ€ ๊ฒฉ๋ฆฌ๋œ ์‹œํฌ๋ฆฟ ๋ฐฑ์—”๋“œ๋ฅผ ๊ฐ€์งˆ ๋•Œ๋Š” SecretStore๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

Q: ๋ฐฐํฌ ํ›„ Pod๊ฐ€ ์‹œํฌ๋ฆฟ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

ExternalSecret ์ƒํƒœ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค:

bash
# troubleshoot-secrets.sh
# ExternalSecret ๋™๊ธฐํ™” ์ƒํƒœ ๋ฐ ์กฐ๊ฑด ํ™•์ธ
kubectl get externalsecret database-credentials -o yaml

# Secret์ด ์ƒ์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
kubectl get secret db-secret -o yaml

# ์ธ์ฆ ์˜ค๋ฅ˜์— ๋Œ€ํ•ด ESO ์ปจํŠธ๋กค๋Ÿฌ ๋กœ๊ทธ ํ™•์ธ
kubectl logs -n external-secrets deployment/external-secrets

์ผ๋ฐ˜์ ์ธ ์‹คํŒจ ์›์ธ์œผ๋กœ๋Š” ๋งŒ๋ฃŒ๋œ Vault ํ† ํฐ, ์ž˜๋ชป๋œ ์‹œํฌ๋ฆฟ ๊ฒฝ๋กœ, ClusterSecretStore์˜ RBAC ๊ตฌ์„ฑ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Q: ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž๊ฒฉ ์ฆ๋ช…์˜ ์‹œํฌ๋ฆฟ ๋กœํ…Œ์ด์…˜์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

Vault์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œํฌ๋ฆฟ ์—”์ง„์€ ๋™์ ์ด๊ณ  ์ˆ˜๋ช…์ด ์งง์€ ์ž๊ฒฉ ์ฆ๋ช…์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ž๊ฒฉ ์ฆ๋ช… TTL๋ณด๋‹ค ์งง์€ refreshInterval๋กœ ESO๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋กœํ…Œ์ด์…˜์ด ํ•„์š”ํ•œ ์ •์  ์ž๊ฒฉ ์ฆ๋ช…์˜ ๊ฒฝ์šฐ, Vault์˜ ๋กœํ…Œ์ด์…˜ API์™€ Reloader๋ฅผ ๊ฒฐํ•ฉํ•˜์—ฌ ์—…๋ฐ์ดํŠธ ํ›„ Pod๋ฅผ ์žฌ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋กœํ…Œ์ด์…˜ ๊ธฐ๊ฐ„ ๋™์•ˆ ์—ฐ๊ฒฐ ์‹คํŒจ๋ฅผ ์šฐ์•„ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

AWS Secrets Manager์™€ ESO

AWS Secrets Manager ์—ฐ๋™์—๋Š” ์„œ๋น„์Šค ๊ณ„์ •์šฉ IAM ์—ญํ• (IRSA)์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์€ ์ •์  ์ž๊ฒฉ ์ฆ๋ช…์„ ์™„์ „ํžˆ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค:

yaml
# aws-secret-store.yaml
# IRSA๋ฅผ ์‚ฌ์šฉํ•œ AWS Secrets Manager์šฉ ClusterSecretStore
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: aws-secrets
spec:
  provider:
    aws:
      service: SecretsManager
      region: ap-northeast-2
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa
            namespace: external-secrets

์„œ๋น„์Šค ๊ณ„์ • ์–ด๋…ธํ…Œ์ด์…˜์ด IAM ์—ญํ• ์— ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค:

yaml
# service-account-irsa.yaml
# IAM ์—ญํ•  ์–ด๋…ธํ…Œ์ด์…˜์ด ์žˆ๋Š” ์„œ๋น„์Šค ๊ณ„์ •
apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-secrets-sa
  namespace: external-secrets
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/external-secrets

AWS๋Š” Lambda ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Secrets Manager์—์„œ ์ƒ์„ฑ๋œ ์‹œํฌ๋ฆฟ์„ ์ž๋™์œผ๋กœ ๋กœํ…Œ์ด์…˜ํ•ฉ๋‹ˆ๋‹ค. ESO์˜ ๋ฆฌํ”„๋ ˆ์‹œ ๊ฐ„๊ฒฉ๊ณผ ๊ฒฐํ•ฉํ•˜๋ฉด, ๊ตฌ์„ฑ๋œ ํด๋ง ๊ธฐ๊ฐ„ ๋‚ด์— ์‹œํฌ๋ฆฟ์ด Kubernetes๋กœ ์ „ํŒŒ๋ฉ๋‹ˆ๋‹ค.

๋ฉ€ํ‹ฐ ํด๋Ÿฌ์Šคํ„ฐ ์‹œํฌ๋ฆฟ ๋™๊ธฐํ™”

์—ฌ๋Ÿฌ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์šด์˜ํ•˜๋Š” ์กฐ์ง์—๋Š” ์ผ๊ด€๋œ ์‹œํฌ๋ฆฟ ๋ฐฐํฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด ์š”๊ตฌ ์‚ฌํ•ญ์„ ํ•ด๊ฒฐํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ํŒจํ„ด์ด ์žˆ์Šต๋‹ˆ๋‹ค:

ClusterSecretStore๋ฅผ ์‚ฌ์šฉํ•œ ํ—ˆ๋ธŒ ์•ค ์Šคํฌํฌ:

๋ชจ๋“  ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ์ค‘์•™ Vault ์ธ์Šคํ„ด์Šค์— ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ํด๋Ÿฌ์Šคํ„ฐ์˜ ESO ์„ค์น˜๊ฐ€ ๋™์ผํ•œ ์‹œํฌ๋ฆฟ์„ ์ฐธ์กฐํ•˜๊ณ , Vault๊ฐ€ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ์ •์ฑ…์„ ํ†ตํ•ด ์ ‘๊ทผ ์ œ์–ด๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

Vault Enterprise๋ฅผ ํ†ตํ•œ ๋ณต์ œ:

Vault Enterprise๋Š” ๋ฆฌ์ „ ๊ฐ„ ์„ฑ๋Šฅ ๋ณต์ œ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ๋กœ์ปฌ Vault ๋ณต์ œ๋ณธ์— ์—ฐ๊ฒฐํ•˜์—ฌ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์ง€์—ฐ ์‹œ๊ฐ„์„ ์ค„์ž…๋‹ˆ๋‹ค. Vault ๋ณต์ œ ๋ฌธ์„œ์—์„œ ์žฌํ•ด ๋ณต๊ตฌ ๋ฐ ์„ฑ๋Šฅ ๋ณต์ œ ๋ชจ๋“œ๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

ArgoCD๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํŒ€์˜ ๊ฒฝ์šฐ, GitOps ๋ฐฐํฌ ํŒจํ„ด ๋ฌธ์„œ์—์„œ ์—ฌ๋Ÿฌ ํด๋Ÿฌ์Šคํ„ฐ์— ExternalSecrets๋ฅผ ๋ฐฐํฌํ•˜๋Š” ApplicationSets๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

์‹œํฌ๋ฆฟ ์ ‘๊ทผ์„ ์œ„ํ•œ RBAC ๊ฐ•ํ™”

๊ธฐ๋ณธ ํด๋Ÿฌ์Šคํ„ฐ ์—ญํ• ์€ ๊ณผ๋„ํ•œ ์‹œํฌ๋ฆฟ ์ ‘๊ทผ์„ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œํ•œ์˜ ์—ญํ• ์„ ์ƒ์„ฑํ•˜์—ฌ RBAC๋ฅผ ๊ฐ•ํ™”ํ•ฉ๋‹ˆ๋‹ค:

yaml
# restricted-role.yaml
# ํŠน์ • ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—์„œ๋งŒ ์‹œํฌ๋ฆฟ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋Š” ์—ญํ• 
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-reader
  namespace: production
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get"]
    resourceNames: ["db-secret", "api-key"]

resourceNames ํ•„๋“œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ๋‚˜์—ด๋œ ์‹œํฌ๋ฆฟ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•„๋“œ๊ฐ€ ์—†์œผ๋ฉด ์—ญํ• ์€ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์˜ ๋ชจ๋“  ์‹œํฌ๋ฆฟ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

Kubernetes ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ๋Š” base64 ์ธ์ฝ”๋”ฉ์˜ ํ•œ๊ณ„๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์—์„œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” External Secrets Operator๋ฅผ ํ†ตํ•œ HashiCorp Vault ๋˜๋Š” AWS Secrets Manager์™€ ๊ฐ™์€ ์™ธ๋ถ€ ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ์ž๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค: ๋„ค์ดํ‹ฐ๋ธŒ Secret์€ ์•”ํ˜ธํ™”๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค, ESO๋Š” ์™ธ๋ถ€ ๋ฐฑ์—”๋“œ์™€์˜ ๋™๊ธฐํ™”๋ฅผ ์ž๋™ํ™”ํ•ฉ๋‹ˆ๋‹ค, Vault๋Š” ๋™์  ์‹œํฌ๋ฆฟ๊ณผ ๊ฐ์‚ฌ ๋กœ๊น…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค, ๊ทธ๋ฆฌ๊ณ  RBAC๋Š” ์ตœ์†Œ ๊ถŒํ•œ ์›์น™์— ๋”ฐ๋ผ ๊ฐ•ํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐœ๋…์€ DevOps ๋ฉด์ ‘์—์„œ ์ •๊ธฐ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๋˜๋ฉฐ, ํด๋ผ์šฐ๋“œ ๋„ค์ดํ‹ฐ๋ธŒ ํ™˜๊ฒฝ์—์„œ ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ์˜ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ํ˜•์„ฑํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋Š˜์˜ ์ฑŒ๋ฆฐ์ง€

DevOps ์ฝ”๋“œ์˜ ๋ฒ„๊ทธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‚˜์š”

์‹ค์ œ ์ฝ”๋“œ ํ•œ ์กฐ๊ฐ, ์ˆจ์€ ๋ฒ„๊ทธ ํ•˜๋‚˜, ํ•˜๋ฃจ ํ•œ ๋ฒˆ. ๊ณ„์ • ์—†์ด ๋ฐ”๋กœ ๋„์ „ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Anthony Fillion-Maillet

์ž‘์„ฑ์ž

Anthony Fillion-Maillet

SharpSkill ์ฐฝ์—…์ž

10๋…„ ์ด์ƒ ํ’€์Šคํƒ ๊ฐœ๋ฐœ์„ ํ•ด์™”์Šต๋‹ˆ๋‹ค. SharpSkill์„ ์šด์˜ํ•˜๋ฉฐ ์ด๊ณณ์— ๊ฒŒ์‹œ๋˜๋Š” ๋ชจ๋“  ๋‚ด์šฉ์— ์ฑ…์ž„์„ ์ง‘๋‹ˆ๋‹ค.

2026๋…„ 9์›” 2์ผ ์—…๋ฐ์ดํŠธ

ํƒœ๊ทธ

#kubernetes
#secrets
#vault
#devops
#security

๊ณต์œ 

๊ด€๋ จ ๊ธฐ์‚ฌ

Kubernetes Helm Charts 2026 ํŠœํ† ๋ฆฌ์–ผ ๋ฐ ๋ฉด์ ‘ ์งˆ๋ฌธ

Kubernetes Helm Charts ์™„๋ฒฝ ๊ฐ€์ด๋“œ 2026: ํŒจํ‚ค์ง•, ๋ฐฐํฌ, ๋ฉด์ ‘ ์งˆ๋ฌธ

Helm 3์„ ์‚ฌ์šฉํ•œ Kubernetes ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํŒจํ‚ค์ง•๊ณผ ๋ฐฐํฌ ๋ฐฉ๋ฒ•์„ ์ƒ์„ธํžˆ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ฐจํŠธ ๊ตฌ์กฐ, ํ…œํ”Œ๋ฆฟ ์ž‘์„ฑ, ์˜์กด์„ฑ ๊ด€๋ฆฌ, ๊ทธ๋ฆฌ๊ณ  ๊ธฐ์ˆ  ๋ฉด์ ‘์—์„œ ์ž์ฃผ ๋‚˜์˜ค๋Š” ์งˆ๋ฌธ๊ณผ ๋‹ต๋ณ€์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

ArgoCD GitOps Kubernetes continuous deployment

ArgoCD์™€ GitOps ์™„๋ฒฝ ๊ฐ€์ด๋“œ 2026: Kubernetes ์ง€์†์  ๋ฐฐํฌ ์ „๋žต๊ณผ ๋ฉด์ ‘ ํ•ต์‹ฌ ์งˆ๋ฌธ

ArgoCD 3.4 GitOps ํŠœํ† ๋ฆฌ์–ผ. Kubernetes ์ง€์†์  ๋ฐฐํฌ, Application CRD, Sync Waves, ๋ฉ€ํ‹ฐํด๋Ÿฌ์Šคํ„ฐ ๊ด€๋ฆฌ, Flux ๋น„๊ต, ๋ฉด์ ‘ ๋นˆ์ถœ ์งˆ๋ฌธ์„ YAML ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ํ•ด์„คํ•ฉ๋‹ˆ๋‹ค.

Pod, Service, Deployment๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” Kubernetes ์•„ํ‚คํ…์ฒ˜ ๋‹ค์ด์–ด๊ทธ๋žจ

Kubernetes ๋ฉด์ ‘ ์™„๋ฒฝ ๊ฐ€์ด๋“œ: Pod, Service, Deployment ํ•ต์‹ฌ ์ •๋ฆฌ

Kubernetes ๋ฉด์ ‘์—์„œ ์ž์ฃผ ์ถœ์ œ๋˜๋Š” Pod, Service, Deployment์˜ ํ•ต์‹ฌ ๊ฐœ๋…์„ YAML ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ์ƒ์„ธํžˆ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค. 2026๋…„ ์ตœ์‹  ํŠธ๋ Œ๋“œ๋ฅผ ๋ฐ˜์˜ํ•œ ์‹ค์ „ ๋Œ€๋น„ ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค.