이 글에서 다루는 것
Kubernetes Secret과 ConfigMap으로 S3/PostgreSQL 인증 정보를 안전하게 주입하는 전략을 다룹니다.
선수지식
- MLOps 플랫폼 구축 1단계: 인프라 설계 및 환경 준비 — NFS/PostgreSQL/S3 환경 구축
이 단계에서 해결하려는 문제
모든 구성 요소(MLflow, Airflow, FastAPI)가 외부 DB, GitHub, S3 등 민감한 리소스와 연동됩니다. API 키와 비밀번호를 YAML이나 코드에 직접 넣으면 보안 위험이 발생합니다. 이 단계에서는 Kubernetes Secret과 ConfigMap을 활용하여 인증 정보를 안전하게 분리하고 주입하는 구조를 설계합니다.
아키텍처 구성도

🔐 왜 Secret 처리가 중요한가?
| 항목 | 이유 |
|---|---|
| AWS Access Key | 노출 시 데이터 삭제/탈취 위험 있음 |
| PostgreSQL 접속 URI | 내부망 DB 구조 노출 + Credential 유출 위험 |
| MLflow Tracking URI | 내부 시스템 구조 노출 가능 |
실무에서는 인증정보를 Git에 노출하지 않고, 환경에 안전하게 주입해야 합니다. 부득이하게 Git에 올려야 할 경우 SealedSecret 또는 SOPS로 암호화 처리합니다.
📦 S3 인증 정보 처리 전략
실습 환경 조건
- MLflow, FastAPI, Airflow에서 모두
boto3로 S3에 접근해야 함 - FastAPI는
env방식으로 처리, Airflow는volumeMount방식이 안정적
Secret 생성 (env 방식 - MLflow & FastAPI)
kubectl create secret generic aws-credentials-secret \
--from-literal=AWS_ACCESS_KEY_ID=your-access-key \
--from-literal=AWS_SECRET_ACCESS_KEY=your-secret-key \
--from-literal=MLFLOW_S3_ENDPOINT_URL=https://s3.ap-northeast-2.amazonaws.com \
-n mlflow
envFrom.secretRef로 사용하면 환경변수로 바로 주입되어 boto3가 자동 인식합니다.
envFrom:
- secretRef:
name: aws-credentials-secret
Secret 생성 (volumeMount 방식 - Airflow 전용)
# .aws/credentials 파일 예시
[default]
aws_access_key_id = your-access-key
aws_secret_access_key = your-secret-key
region = ap-northeast-2
kubectl create secret generic aws-credentials-secret \
--from-file=credentials=.aws/credentials \
-n airflow
Airflow는 Task마다 새 Pod가 생성되고 MLflow + S3 연동 시 boto3를 사용합니다. AWS EKS가 아닌 로컬 Kubernetes 환경에서는 .aws 경로 마운트 방식이 안정적입니다.
extraVolumes:
- name: aws-credentials
secret:
secretName: aws-credentials-secret
extraVolumeMounts:
- name: aws-credentials
mountPath: /home/airflow/.aws
readOnly: true
🗄 PostgreSQL 접속 정보 관리 전략
목표
- Helm 차트 내부에서
backend-store-uri혹은sql_alchemy_conn값을 직접 넣지 않음 - 대신
Secret이나ConfigMap으로 구성 요소 분리
🔐 MLflow 접속 정보 구성 (Secret + ConfigMap 분리 방식)
목표: 실험 metadata 저장소(PostgreSQL)에 대한 안전한 연결 설정
# Secret: 인증 정보 (username/password)
kubectl create secret generic mlflow-db-secret \
--from-literal=username=mlflow_user \
--from-literal=password='<YOUR_PASSWORD>' \ # 실제 환경: SealedSecrets 사용
-n mlflow
# ConfigMap: 일반 정보 (host/port/dbname)
kubectl create configmap mlflow-db-config \
--from-literal=host=192.168.18.142 \
--from-literal=port=5432 \
--from-literal=dbname=mlflow_db \
-n mlflow
Helm chart에서 env.valueFrom으로 조합하여 주입합니다.
- name: DB_USER
valueFrom:
secretKeyRef:
name: mlflow-db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: mlflow-db-secret
key: password
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: mlflow-db-config
key: host
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: mlflow-db-config
key: port
- name: DB_NAME
valueFrom:
configMapKeyRef:
name: mlflow-db-config
key: dbname
🔐 Airflow 접속 정보 구성 (통합 URI 방식)
목표: Airflow 메타 DB(PostgreSQL) URI를 단일 문자열로 관리
kubectl create secret generic airflow-db-secret \
--from-literal=connection="postgresql://airflow_user:<AIRFLOW_DB_PASSWORD>@192.168.18.142:5432/airflow_db" \ # 실제 환경: SealedSecrets 사용
-n airflow
Helm values.yaml에서 metadataSecretName으로 참조합니다.
data:
metadataSecretName: airflow-db-secret
내부적으로 AIRFLOW__DATABASE__SQL_ALCHEMY_CONN 환경변수로 설정됩니다.
🔄 Secret 방식 정리 비교
| 방식 | 대상 | 장점 | 단점 |
|---|---|---|---|
envFrom.secretRef | MLflow, FastAPI | 깔끔하고 가독성 좋음 | Airflow에서는 실패 가능성 존재 |
.aws 마운트 | Airflow | Task Pod에서도 안정적 | 경로 구조 명확히 맞춰야 함 (boto3 대비) |
base64 Secret | DB URI, 민감한 키 | Helm에서 깔끔히 관리 | Git에 올리면 암호화 없이 노출됨 (주의) |
🚨 트러블슈팅
TS_01: Airflow DAG Task에서 boto3 인증 실패
| 증상 | 원인 | 해결 |
|---|---|---|
botocore.exceptions.NoCredentialsError | env 방식으로 주입했지만 Task Pod에는 적용되지 않음 | .aws/credentials 경로로 마운트 방식 사용해야 함 |
설계 판단 (Why This Way?)
Airflow KubernetesExecutor의 Task Pod에는 envFrom이 전파되지 않을 수 있으므로 volumeMount 방식으로 AWS 인증을 주입하고, Secret과 ConfigMap은 컴포넌트별 주입 구조에 맞게 분리 또는 통합했습니다. Git에 커밋되는 Secret은 반드시 SealedSecrets 등으로 암호화해야 하며, base64 인코딩은 보안이 아닙니다.
다음에 읽을 글
→ MLOps 플랫폼 구축 3단계: MLflow Helm 구성 — PostgreSQL + S3 연동 기반 MLflow Helm 배포