Post

[Kubernetes] Secret

๐Ÿ“Œ ๊ฐœ์š”

ํ•œ ์ค„ ์š”์•ฝ: ํŒŒ๋“œ๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ๋ฏผ๊ฐํ•œ ์ •๋ณด(๋น„๋ฐ€๋ฒˆํ˜ธ, ์ธ์ฆ์„œ, ํ† ํฐ ๋“ฑ)๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฆฌ์†Œ์Šค

์™œ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€:

  • ๋ณด์•ˆ: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋‚˜ ์ด๋ฏธ์ง€ ์•ˆ์— ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•จ
  • ์œ ์—ฐ์„ฑ: ๊ฐœ๋ฐœ/์šด์˜ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ์„ค์ •๊ฐ’๋งŒ ๋ฐ”๊ฟ” ๋ผ์šธ ์ˆ˜ ์žˆ์–ด ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•  ํ•„์š” ์—†์Œ
  • ๋ถ„๋ฆฌ: โ€œ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์งโ€๊ณผ โ€œ๋ณด์•ˆ ์„ค์ •โ€์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ

ํŠน์ง•:

  • ์ €์žฅ ๋ฐฉ์‹: ๋ฐ์ดํ„ฐ๋Š” base64๋กœ ์ธ์ฝ”๋”ฉ๋˜์–ด ์ €์žฅ (์•”ํ˜ธํ™”๊ฐ€ ์•„๋‹˜์— ์ฃผ์˜!)
  • ์‚ฌ์šฉ ๋ฐฉ์‹: ํŒŒ๋“œ ๋‚ด๋ถ€์— ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์ฃผ์ž…ํ•˜๊ฑฐ๋‚˜, Volume Mount ํ˜•ํƒœ๋กœ ๋งˆ์šดํŠธํ•˜์—ฌ ์‚ฌ์šฉ
  • ์šฉ๋Ÿ‰ ์ œํ•œ: etcd์˜ ๋ถ€ํ•˜๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด 1MB๋กœ ์ œํ•œ

๐Ÿ—‚ Secret Type ์ด์ •๋ฆฌ

Secret์˜ type ํ•„๋“œ๋Š” โ€œ์ด ๋ด‰ํˆฌ ์•ˆ์— ์–ด๋–ค ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์žˆ๋Š”์ง€โ€ ๋ฅผ ์‹œ์Šคํ…œ์— ์•Œ๋ ค์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

โ‘  Opaque (์ผ๋ฐ˜ํ˜•)

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ด๊ณ  ๋ฒ”์šฉ์ ์ธ ํƒ€์ž…. โ€œ๋ถˆํˆฌ๋ช…โ€์ด๋ผ๋Š” ๋œป์œผ๋กœ, ์‚ฌ์šฉ์ž๊ฐ€ ์ •์˜ํ•œ ์ž„์˜์˜ Key-Value ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์Šต๋‹ˆ๋‹ค.

  • ์šฉ๋„: DB ๋น„๋ฐ€๋ฒˆํ˜ธ, API Key, ์„ค์ • ํŒŒ์ผ ๋“ฑ ์ •ํ•ด์ง„ ํ˜•์‹์ด ์—†๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ
  • ํ•„์ˆ˜ ํ‚ค: ์—†์Œ (์‚ฌ์šฉ์ž ๋งˆ์Œ๋Œ€๋กœ ์ •์˜)
1
2
3
4
5
6
apiVersion: v1
kind: Secret
type: Opaque
data:
  db-pass: MWYyaZD...   # base64 ์ธ์ฝ”๋”ฉ ๊ฐ’
  api-key: dXNlcnB...

โ‘ก kubernetes.io/service-account-token (ํŒŒ๋“œ ์ธ์ฆ์šฉ)

ํŒŒ๋“œ๊ฐ€ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค API ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•  ๋•Œ ์‹ ์›์„ ์ฆ๋ช…ํ•˜๊ธฐ ์œ„ํ•œ JWT ํ† ํฐ์„ ๋‹ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์šฉ๋„: ServiceAccount ์ƒ์„ฑ ์‹œ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ง€๊ฑฐ๋‚˜, API ์ ‘๊ทผ์šฉ ํ† ํฐ์ด ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ
  • ํ•„์ˆ˜ ํ‚ค:
    • ca.crt: API ์„œ๋ฒ„ ์ธ์ฆ์„œ
    • token: ์‹ค์ œ Bearer Token (JWT)
    • namespace: ํ•ด๋‹น ๊ณ„์ •์˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค

โ‘ข kubernetes.io/tls (HTTPS ์ธ์ฆ์„œ์šฉ)

์›น ์„œ๋ฒ„์˜ HTTPS ํ†ต์‹ ์ด๋‚˜ ๋‚ด๋ถ€ ๋ณด์•ˆ ํ†ต์‹ ์„ ์œ„ํ•œ TLS/SSL ์ธ์ฆ์„œ๋ฅผ ์ €์žฅํ•˜๋Š” ํ‘œ์ค€ ๊ทœ๊ฒฉ์ž…๋‹ˆ๋‹ค.

  • ์šฉ๋„: Ingress ์ปจํŠธ๋กค๋Ÿฌ์˜ TLS ์„ค์ •, ์›น ์„œ๋ฒ„ ํŒŒ๋“œ์˜ ์ธ์ฆ์„œ ๋งˆ์šดํŠธ
  • ํ•„์ˆ˜ ํ‚ค:
    • tls.crt: ๊ณต๊ฐœ ์ธ์ฆ์„œ (Certificate)
    • tls.key: ๊ฐœ์ธํ‚ค (Private Key)
1
2
3
4
5
# TLS Secret ์ƒ์„ฑ
kubectl create secret tls my-tls-secret \
  --cert=tls.crt \
  --key=tls.key \
  -n default

โ‘ฃ kubernetes.io/basic-auth (๊ธฐ๋ณธ ์ธ์ฆ์šฉ)

HTTP Basic Authentication์„ ์œ„ํ•œ ์ž๊ฒฉ ์ฆ๋ช…์ž…๋‹ˆ๋‹ค.

  • ์šฉ๋„: Ingress์— ๊ฐ„๋‹จํ•œ ๋กœ๊ทธ์ธ(์ ‘๊ทผ ์ œ์–ด) ๊ธฐ๋Šฅ์„ ๋ถ™์ผ ๋•Œ ์‚ฌ์šฉ
  • ํ•„์ˆ˜ ํ‚ค:
    • username: ์‚ฌ์šฉ์ž ์•„์ด๋””
    • password: ๋น„๋ฐ€๋ฒˆํ˜ธ

โ‘ค kubernetes.io/dockerconfigjson (์ด๋ฏธ์ง€ ํ’€ ์‹œํฌ๋ฆฟ)

Private ์ปจํ…Œ์ด๋„ˆ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์šด๋กœ๋“œํ•  ๋•Œ ํ•„์š”ํ•œ ๋กœ๊ทธ์ธ ์ •๋ณด์ž…๋‹ˆ๋‹ค.

  • ์šฉ๋„: ํŒŒ๋“œ ์„ค์ •์˜ imagePullSecrets ํ•ญ๋ชฉ์— ์‚ฌ์šฉ
  • ํ•„์ˆ˜ ํ‚ค: .dockerconfigjson
1
2
3
4
5
6
# Docker Registry Secret ์ƒ์„ฑ
kubectl create secret docker-registry my-registry-secret \
  --docker-server=hyperregistry.example.com \
  --docker-username=myuser \
  --docker-password=mypassword \
  -n default
1
2
3
4
5
6
7
# ํŒŒ๋“œ์—์„œ ์‚ฌ์šฉ
spec:
  imagePullSecrets:
  - name: my-registry-secret
  containers:
  - name: app
    image: hyperregistry.example.com/myapp:1.0

โ‘ฅ helm.sh/release.v1 (Helm ๋ฐฐํฌ ์ด๋ ฅ)

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €์ธ Helm์ด ๋ฐฐํฌ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์ „์šฉ ์‹œํฌ๋ฆฟ์ž…๋‹ˆ๋‹ค.

  • ์šฉ๋„: Helm ์ฐจํŠธ์˜ ๋ฒ„์ „, values.yaml, ๋ฐฐํฌ ์ƒํƒœ ๋“ฑ์„ ์ €์žฅ
  • โš ๏ธ ์ฃผ์˜: ์ ˆ๋Œ€ ์ˆ˜๋™์œผ๋กœ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. Helm์ด ๋ฐฐํฌ๋œ ์•ฑ์„ ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ํŠน์ง•: ๋ฐ์ดํ„ฐ๊ฐ€ ์••์ถ•๋˜์–ด ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“‹ ํƒ€์ž… ์š”์•ฝ ํ…Œ์ด๋ธ”

ํƒ€์ž…์—ญํ•  (๋น„์œ )์ฃผ์š” Key๋น„๊ณ 
Opaque๋นˆ ๋ด‰ํˆฌ(์‚ฌ์šฉ์ž ์ •์˜)๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋จ (Default)
kubernetes.io/tls์‹ ๋ถ„์ฆ ์„ธํŠธtls.crt, tls.key์ธ์ฆ์„œ ๋งŒ๋ฃŒ ๊ด€๋ฆฌ ํ•„์š”
kubernetes.io/service-account-token์‚ฌ์›์ฆtoken, ca.crtํŒŒ๋“œ ๋‚ด๋ถ€์— ์ž๋™ ๋งˆ์šดํŠธ๋จ
kubernetes.io/basic-auth๋กœ๊ทธ์ธ ๋ฉ”๋ชจusername, passwordIngress ์ธ์ฆ์— ์ฃผ๋กœ ์‚ฌ์šฉ
kubernetes.io/dockerconfigjson์ฐฝ๊ณ  ์—ด์‡ .dockerconfigjsonPrivate ์ด๋ฏธ์ง€ ๋ฐ›์„ ๋•Œ ํ•„์ˆ˜
helm.sh/release.v1์„ค์น˜ ์ด๋ ฅ์„œ(Helm ๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ)๊ฑด๋“œ๋ฆฌ์ง€ ๋ง ๊ฒƒ ๐Ÿšซ

๐Ÿ’ป ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

Secret ์ƒ์„ฑ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ๋ช…๋ น์–ด๋กœ ์ƒ์„ฑ (Opaque)
kubectl create secret generic my-secret \
  --from-literal=db-password=mysecretpassword \
  --from-literal=api-key=abc123 \
  -n default

# ํŒŒ์ผ๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑ
kubectl create secret generic my-secret \
  --from-file=config.json \
  -n default

# YAML๋กœ ์ƒ์„ฑ (base64 ์ธ์ฝ”๋”ฉ ํ•„์š”)
echo -n 'mysecretpassword' | base64
# bXlzZWNyZXRwYXNzd29yZA==
1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
  namespace: default
type: Opaque
data:
  db-password: bXlzZWNyZXRwYXNzd29yZA==  # base64 ์ธ์ฝ”๋”ฉ ๊ฐ’
  api-key: YWJjMTIz

Secret ์กฐํšŒ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Secret ๋ชฉ๋ก
kubectl get secret -n default

# Secret ์ƒ์„ธ (์ธ์ฝ”๋”ฉ๋œ ๊ฐ’ ํฌํ•จ)
kubectl get secret my-secret -n default -o yaml

# ํŠน์ • ํ‚ค ๊ฐ’ ๋””์ฝ”๋”ฉ
kubectl get secret my-secret -n default \
  -o jsonpath='{.data.db-password}' | base64 -d

# ๋ชจ๋“  ํ‚ค-๊ฐ’ ๋””์ฝ”๋”ฉ
kubectl get secret my-secret -n default -o go-template='
{{range $k, $v := .data}}{{$k}}: {{$v | base64decode}}
{{end}}'

๐Ÿ”Œ ํŒŒ๋“œ์—์„œ Secret ์‚ฌ์šฉ

ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์ฃผ์ž…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: myapp:1.0
        env:
        # ๋‹จ์ผ ํ‚ค ์ฃผ์ž…
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: my-secret
              key: db-password
        # Secret ์ „์ฒด ์ฃผ์ž…
        envFrom:
        - secretRef:
            name: my-secret

Volume์œผ๋กœ ๋งˆ์šดํŠธ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spec:
  containers:
  - name: app
    image: myapp:1.0
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secrets
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: my-secret
      # ํŠน์ • ํ‚ค๋งŒ ๋งˆ์šดํŠธ
      items:
      - key: db-password
        path: db-password.txt
1
2
3
# ๋งˆ์šดํŠธ ํ™•์ธ
# /etc/secrets/db-password.txt ํŒŒ์ผ๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅ
kubectl exec -it <pod-name> -- cat /etc/secrets/db-password.txt

โš ๏ธ ๋ณด์•ˆ ์ฃผ์˜์‚ฌํ•ญ

1. Base64๋Š” ์•”ํ˜ธํ™”๊ฐ€ ์•„๋‹ˆ๋‹ค kubectl get secret -o yaml๋กœ ์กฐํšŒํ•˜๋ฉด ๋ˆ„๊ตฌ๋‚˜ ๋””์ฝ”๋”ฉํ•˜์—ฌ ์›๋ณธ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1
2
3
# ๋ˆ„๊ตฌ๋‚˜ ์ด๋ ‡๊ฒŒ ๋””์ฝ”๋”ฉ ๊ฐ€๋Šฅ
echo "bXlzZWNyZXRwYXNzd29yZA==" | base64 -d
# mysecretpassword

2. RBAC ์„ค์ • ํ•„์ˆ˜ ์•„๋ฌด๋‚˜ Secret์„ ์กฐํšŒ(get, list, watch)ํ•  ์ˆ˜ ์—†๋„๋ก Role์„ ์—„๊ฒฉํ•˜๊ฒŒ ์ œํ•œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
# Secret ์กฐํšŒ ๊ถŒํ•œ์„ ํŠน์ • ServiceAccount์—๋งŒ ๋ถ€์—ฌ
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames: ["my-secret"]  # ํŠน์ • Secret๋งŒ ํ—ˆ์šฉ
  verbs: ["get"]

3. Git์— ์˜ฌ๋ฆฌ์ง€ ๋ง ๊ฒƒ Secret YAML ํŒŒ์ผ์„ ๊ทธ๋Œ€๋กœ GitHub์— ์˜ฌ๋ฆฌ๋ฉด ์œ ์ถœ ์‚ฌ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. Sealed Secrets๋‚˜ External Secrets ๊ฐ™์€ ๋„๊ตฌ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

1
2
3
# .gitignore์— ์ถ”๊ฐ€
*-secret.yaml
*-secrets.yaml

๐Ÿ”— ๊ด€๋ จ ๋ฌธ์„œ

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.