Overview
Kubernetes에서 민감한 정보를 다룰 때 가장 먼저 고려해야 할 리소스가 바로 Secret이다.
이번 글에서는 Kubernetes Secret의 개념부터 다양한 Secret 유형(Opaque, TLS, Docker config, Basic Auth 등), 그리고 실무에서 많이 쓰이는 External Secrets까지 폭넓게 다뤄보려 한다.
또한 다양한 생성 방법(CLI, YAML, base64, stringData 등)과 실제 사용하는 패턴(환경 변수, volume 마운트)까지 함께 정리했다.
Kubernetes 클러스터 보안을 강화하고, 민감 데이터를 안전하게 관리하는 데 도움이 되는 실용 가이드가 될 것이다.
Kubernetes Secret이란?
Kubernetes 시크릿은 비밀번호, API 키, 토큰 또는 인증서와 같은 민감한 정보를 Kubernetes 클러스터 내에 안전하게 저장하는 데 사용된다. 민감한 데이터를 애플리케이션 코드 및 구성 파일과 분리하는 데 도움이 된다. 시크릿은 클러스터의 포드 및 컨테이너에서 사용할 파일 또는 환경 변수로 마운트할 수 있다.
Kubernetes Secrets으로 저장할 수 있는 아래의 리소스에 대해 알아보려고 한다.
- Opaque Secrets
- Service account token Secrets
- Docker config Secrets
- Basic authentication Secret
- SSH authentication secrets
- TLS secrets
- External Secrets
Opaque Secrets
Opaque Secrets 은 Kubernetes secret 구성 중 기본 유형이다.
응용 프로그램은 종종 인증이 필요한 데이터베이스에 액세스해야 한다. 데이터베이스 비밀번호를 Kubernetes 시크릿으로 저장하고 애플리케이션에서 환경 변수로 사용할 수 있도록 할 수 있다. 이렇게 하면 비밀번호가 애플리케이션 코드 및 구성과 안전하게 분리할 수 있다.
apiVersion: v1
kind: Secret
metadata:
name: somaz-server-db-secret
namespace: somaz-server-dev1
labels:
app: somaz-server-dev1
type: Opaque
data:
DB_USERNAME: c29tYXoK # echo -n "somaz" | base64
DB_PASSWORD: c29tYXo5NAo= # echo -n "somaz94" | base64
DB_ROOT_PASSWORD: YWRtaW4K # echo -n "admin" | base64
apiVersion: apps/v1
kind: Deployment
metadata:
name: somaz-server-db-dev1
labels:
app: somaz-server-db-dev1
spec:
selector:
matchLabels:
app: somaz-server-db-dev1
strategy:
type: Recreate
template:
metadata:
labels:
app: somaz-server-db-dev1
spec:
containers:
- image: mysql:8.0
name: mysql
env:
# Use secret in real usage
# - name: MYSQL_ALLOW_EMPTY_PASSWORD
# value: 'yes'
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: somaz-server-db-secret
key: DB_USERNAME
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: somaz-server-db-secret
key: DB_PASSWORD
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: somaz-server-db-secret
key: DB_ROOT_PASSWORD
ports:
- containerPort: 3306
protocol: TCP
name: mysql
volumeMounts:
- name: mysql-persistent-storage-dev1
mountPath: /var/lib/mysql
- name: config-volume
mountPath: /etc/mysql/conf.d
volumes:
- name: mysql-persistent-storage-dev1
persistentVolumeClaim:
claimName: somaz-server-db-dev1-pv-claim
- name: config-volume
configMap:
name: somaz-server-db-config
MetalLB memberlist key 생성 방법(랜덤방식)
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)" -o yaml > metallb-secret.yaml
Service account token Secrets
Secret 유형 `kubernetes.io/service-account-token` 은 ServiceAccount를 확인하는 token credential을 저장한다.
서비스 계정이 생성될 때 자동으로 생성되며, 서비스 계정과 연결되어 있다. 서비스 계정 토큰 시크릿을 사용하면, Pod는 Kubernetes API에 대한 인증을 위해 토큰을 사용할 수 있다. 토큰은 자동으로 쿠버네티스 클러스터의 API 서버로 전달되어 인증 및 권한 부여 프로세스에 사용된다.
apiVersion: v1
kind: Secret
metadata:
name: secret-sa-sample
annotations:
kubernetes.io/service-account.name: "sa-name"
type: kubernetes.io/service-account-token
data:
# You can include additional key value pairs as you do with Opaque Secrets
extra: YmFyCg==
Docker config Secrets
다음 type값 중 하나를 사용하여 컨테이너 이미지 레지스트리에 액세스하기 위한 자격 증명을 저장할 비밀을 만들 수 있다.
- `kubernetes.io/dockercfg`
- `kubernetes.io/dockerconfigjson`
Docker Hub 또는 Google Container Registry, Harbor 같은 컨테이너 레지스트리에서 프라이빗 컨테이너 이미지를 가져오려면 인증 자격 증명이 필요하다.
이러한 자격 증명을 Kubernetes 보안 비밀로 저장하고 포드 사양에서 사용하여 레지스트리로 인증할 수 있다.
$ cat harbor-secret.yaml
apiVersion: v1
data:
.dockerconfigjson: e2F1dGhzOntodHRwOi8vaGFyYm9yLnRlc3Q6e3VzZXJuYW1lOmFkbWluLHBhc3N3b3JkOmFkbWluLGVtYWlsOnRlc3RAdGVzdC5jb20sYXV0aDpZV1J0YVc0NlNHRnlZbTlYWFhYWFhYWFg9fX19Cg==
kind: Secret
metadata:
creationTimestamp: null
name: harbor-secret
type: kubernetes.io/dockerconfigjson
$ echo "e2F1dGhzOntodHRwOi8vaGFyYm9yLnRlc3Q6e3VzZXJuYW1lOmFkbWluLHBhc3N3b3JkOmFkbWluLGVtYWlsOnRlc3RAdGVzdC5jb20sYXV0aDpZV1J0YVc0NlNHRnlZbTlYWFhYWFhYWFg9fX19Cg==" | base64 --decode
{auths:{http://harbor.test:{username:admin,password:admin,email:test@test.com,auth:YWRtaW46SGFyYm9XXXXXXXXX=}}}
Harbor key 생성 방법
kubectl create secret docker-registry <secret_name> --docker-username=<private_registry_user_name> --docker-password=<private_registry_user_password> --docker-email=<private_registry_email> --docker-server=<private_registry_url> --dry-run=client -o yaml > secret.yaml
Basic authentication Secret
`kubernetes.io/basic-auth` 유형은 기본 인증에 필요한 자격 증명을 저장하기 위해 제공된다.
data secret 필드에는 다음 두 키 중 하나가 포함되어야 한다.
- username: 인증을 위한 사용자 이름
- password: 인증을 위한 암호 또는 토큰
apiVersion: v1
kind: Secret
metadata:
name: secret-basic-auth
type: kubernetes.io/basic-auth
stringData:
username: admin # required field for kubernetes.io/basic-auth
password: t0p-Secret # required field for kubernetes.io/basic-auth
SSH authentication secrets
SSH 인증에 사용되는 데이터를 저장하기 위해 builtin type이 kubernetes.io/ssh-auth제공한다.
원격 서버에 대한 SSH 액세스가 필요한 애플리케이션이 있을 수 있다. 비공개 SSH 키를 Kubernetes 보안 비밀로 저장하고 액세스가 필요한 컨테이너 내부에 파일로 탑재할 수 있다. 이렇게 하면 SSH 키가 안전하게 관리되며 컨테이너 이미지나 애플리케이션 코드에 노출되지 않는다.
apiVersion: v1
kind: Secret
metadata:
name: secret-ssh-auth
type: kubernetes.io/ssh-auth
data:
# the data is abbreviated in this example
ssh-privatekey: |
MIIEpQIBAAKCAQEAulqb/Y ...
TLS secrets
`kubernetes.io/tls` 는 일반적으로 TLS에 사용되는 인증서 및 관련 키를 저장하기 위한 기본 보안 비밀 유형을 제공한다.
apiVersion: v1
kind: Secret
metadata:
name: secret-tls
type: kubernetes.io/tls
data:
# the data is abbreviated in this example
tls.crt: |
MIIC2DCCAcCgAwIBAgIBATANBgkqh ...
tls.key: |
MIIEpgIBAAKCAQEA7yn3bRHQ5FHMQ ...
External Secrets
External-secrets 는 외부 API에서 AWS Secrets Manager , HashiCorp Vault , Google Secrets Manager , Azure Key Vault와 같은 외부 보안 관리 시스템을 통합하고 해당 값을 Kubernetes Secret 에 자동으로 동기화하는 Kubernetes operator이다.
External Secrets은 Kubernetes 컨트롤러를 사용하여 작동하여 External Secrets 저장소와 Kubernetes 간에 비밀을 자동으로 동기화한다. External Secrets 저장소에서 Secret이 추가되거나 업데이트되면 컨트롤러는 변경 사항을 감지하고 해당 Kubernetes 비밀 개체를 업데이트 한다.
# yaml 파일
...
externalSecrets:
- name: somaz-database
backendType: secretsManager
region: ap-northeast-2
namespace: somaz-db
datas:
- key: somaz-database
property: username
name: ADMIN_DB_ID
- key: somaz-database
property: password
name: ADMIN_DB_PW
- key: somaz-database
property: username
...
$ k get secret -n somaz-db somaz-database -o yaml
apiVersion: v1
data:
ADMIN_DB_ID: YWRtaW4K # echo "admin" | base64
ADMIN_DB_PW: c29tYXoK # echo "somaz" | base64
kind: Secret
metadata:
creationTimestamp: "2023-03-23T06:47:38Z"
name: somaz-database
namespace: somaz-db
ownerReferences:
- apiVersion: kubernetes-client.io/v1
controller: true
kind: ExternalSecret
name: somaz-database
uid: dab4xxxxx-88xx-4axx-aaxx-6dxxxxxxxxx
resourceVersion: "75617647"
uid: 82axxxx-ebxx-49xx-97xx-0881xxxxxxx
type: Opaque
- AWS SecretsManager 예시이다.
- SecretsManager에 미리 값을 넣어놓고 가져와서 쓸 수 있다.
Kubernetes Secret 생성 방법
Kubernetes에서 시크릿을 생성하는 방법은 아래와 같다.
- Command-Line and Text Files
- Command-Line and Literal Input
- Definition Files
- Base64 and The Data Parameter
- Clear Text and The StringData Parameter
Command-Line and Text Files
`-n` 옵션과 함께 `echo` 를 사용하여 텍스트에 개행 문자가 추가되지 않도록 했다.
app-user-cred 라는 secret을 생성하는 예시이다.
echo -n 'superuser' > ./username.txt
echo -n 'Q%FvqS$*F$k^6i' > ./password.txt
kubectl create secret generic app-user-cred --from-file=./username.txt --from-file=./password.txt
Command-Line and Literal Input
secret 텍스트에 특수 문자가 포함될 때마다 각 고유 문자 앞에 \\를 붙여서 이스케이프 처리해야 한다.
`-from-literal` 옵션을 통해 쉽게 secret을 생성할 수 있다.
kubectl create secret generic app-user-cred --from-literal=username=devuser
--from-literal=password=Q\\%FvqS\\$\\*F\\$k\\^6i
Definition Files
YAML 또는 JSON으로 작성된 정의 파일을 사용하여 생성할 수 있다.
Base64 and The Data Parameter
비밀 텍스트를 base64 로 인코딩된 문자열로 정의가 가능하다. YAML 파일을 생성하고 사용하여 자격 증명을 저장할 비밀을 생성한다.
$ echo -n 'superuser' | base64
c3VwZXJ1c2Vy
$ echo -n 'Q%FvqS$*F$k^6i' | base64
USVGdnFTJCpGJGteNmk=
자격 증명이 base64로 인코딩되었다. 정의 파일 `mysecret.yaml` 을 생성한다.
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
superuser: YWRtaW4=
password: USVGdnFTJCpGJGteNmk=
Clear Text and The StringData Parameter
문자열 인코딩을 건너뛰고 Kubernetes가 자동으로 인코딩하도록 할 수 있다.
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
stringData:
superuser: 'superuser'
password: 'Q%FvqS$*F$k^6i'
$ k apply -f mysecret.yaml -n <namespace>
$ k get secret -n <namespace> mysecret -o yaml
apiVersion: v1
data:
password: USVGdnFTJCpGJGteNmk=
superuser: c3VwZXJ1c2Vy
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},
"name":"mysecret","namespace":"default"},
"stringData":{"password":"Q%FvqS$*F$k^6i","superuser":"superuser"},"type":"Opaque"}
creationTimestamp: "2019-07-21T14:14:56Z"
name: mysecret
namespace: default
resourceVersion: "708718"
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: eaddc88c-abc1-11e9-8bff-025000000001
type: Opaque
Kubernetes Secret Data Access
다음 이미지에 설명된 대로 컨테이너는 configMap 볼륨과 거의 동일한 방식으로 볼륨을 통해 Secret에 액세스 한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: somaz-admin-dev
labels:
app: somaz-admin-dev
spec:
revisionHistoryLimit: 1
selector:
matchLabels:
app: somaz-admin-dev
replicas: 1
template:
metadata:
labels:
app: somaz-admin-dev
spec:
imagePullSecrets:
- name: secret
volumes:
- name: data
persistentVolumeClaim:
claimName: somaz-admin-dev-data-pv-claim
Secret 보안 모범 사례
Kubernetes Secret은 민감한 데이터를 저장하는 만큼, 적절한 보안 설정이 무엇보다 중요하다.
첫째, RBAC(Role-Based Access Control) 정책을 통해 불필요한 네임스페이스나 서비스 계정에는 Secret 읽기 권한을 부여하지 않아야 한다. 최소 권한 원칙을 철저히 적용해야 한다.
둘째, etcd 암호화를 활성화해야 합니다. Kubernetes Secret은 etcd에 저장되는데, 기본적으로는 단순한 base64 인코딩만 적용된다. 따라서 별도의 설정을 통해 AES와 같은 강력한 암호화를 적용해야 보안이 보장된다.
셋째, kubectl 접근 제어도 필요하다. 운영자 계정 외에는 Secret 리소스를 조회할 수 없도록 제한하고, 실수로 민감한 정보가 노출되지 않도록 해야 한다.
넷째, Git 저장소에 Secret을 올리지 않는 것이 중요하다. YAML 내의 stringData나 base64로 인코딩된 값도 결국은 민감한 정보이므로, Git에 업로드되면 보안 사고로 이어질 수 있다.
마지막으로, GitOps 환경에서는 Sealed Secrets, SOPS, HashiCorp Vault 같은 도구를 활용해 Secret을 암호화한 상태로 안전하게 관리하는 것이 좋다. 이러한 도구는 자동 복호화 및 권한 기반 제어 기능을 통해 Secret의 실수를 최소화할 수 있다.
마무리: 민감한 정보는 Secret으로 안전하게
Kubernetes Secret은 민감한 데이터를 안전하게 관리하기 위한 핵심 도구이다.
환경 변수, 볼륨 마운트, 이미지 풀 인증 정보, 외부 비밀 연동까지, 실무에서 다양하게 활용되며 클러스터 보안을 책임지는 중요한 역할을 한다.
이번 글에서 소개한 다양한 Secret 유형과 생성 방법, 그리고 External Secrets까지 잘 활용하면 코드와 민감 데이터를 확실히 분리하고, 유지보수와 보안 모두를 만족시킬 수 있다.
🔐 “ConfigMap은 일반 설정을, Secret은 민감한 정보를.”
이 원칙만 기억해도 실무에서의 실수가 크게 줄어들 것이다.
Reference
How to Create, Use, and Access Kubernetes Secrets
'Container Orchestration > Kubernetes' 카테고리의 다른 글
Helm 이란? (Kubernetes Package manager) (2) | 2023.05.16 |
---|---|
Kuberntes Service Account란? (0) | 2023.05.10 |
MetalLB란? (2) | 2023.05.03 |
Kubernetes Resources(쿠버네티스 리소스) (0) | 2023.05.02 |
Kubernetes 플러그인 매니저 Krew란? (0) | 2023.04.30 |