Data Engineering/s3 minio

EP17 [ MinIO S3 + Cilium 기초 과정 ] 기본 보안 설정 #1 | 쿠버네티스 Secret 활용하기 - MinIO 자격 증명 보호

ygtoken 2025. 3. 29. 16:37
728x90

이 글에서는 쿠버네티스 Secret을 활용하여 MinIO의 민감한 자격 증명 정보를 안전하게 관리하는 방법에 대해 알아보겠습니다. 보안 모범 사례와 함께 실제 구현 방법을 상세히 설명합니다.


📌 쿠버네티스 Secret 개념 이해하기

✅ Secret이란 무엇인가?

Secret은 비밀번호, API 키, 인증서와 같은 민감한 정보를 저장하기 위한 쿠버네티스 리소스입니다. ConfigMap과 유사하지만 보안에 중점을 둔 리소스입니다.

▶️ Secret의 주요 특징:

  • 민감 데이터를 저장하도록 설계됨
  • Base64 인코딩으로 저장 (암호화는 아님)
  • etcd에 저장될 때 암호화 가능 (추가 구성 필요)
  • 메모리에만 마운트 가능 (tmpfs)
  • Pod 간 공유 제한 가능
apiVersion: v1                   # 핵심 API 그룹의 v1 버전, Secret은 쿠버네티스 핵심 리소스이므로 v1 사용
kind: Secret                     # 리소스 종류는 Secret으로, 민감한 정보를 저장하기 위한 전용 리소스
metadata:
  name: minio-creds              # Secret 이름, Pod에서 이 이름으로 Secret을 참조하므로 명확하게 지정
  namespace: minio-system        # Secret이 속한 네임스페이스, MinIO가 배포된 네임스페이스와 동일하게 설정해야 접근 가능
type: Opaque                     # Secret 유형을 Opaque로 지정, 일반적인 키-값 쌍 데이터에 적합한 기본 유형
data:
  # Base64 인코딩된 데이터 (echo -n "minio" | base64)
  root-user: bWluaW8=            # MinIO 루트 사용자명을 Base64로 인코딩한 값, 평문은 "minio"
  # Base64 인코딩된 데이터 (echo -n "minio123" | base64)
  root-password: bWluaW8xMjM=    # MinIO 루트 비밀번호를 Base64로 인코딩한 값, 평문은 "minio123"

✅ Secret vs ConfigMap

Secret과 ConfigMap의 차이점과 각각의 사용 사례를 이해합시다.

특성 Secret ConfigMap
용도 민감한 데이터 일반 구성 데이터
인코딩 Base64 인코딩 평문
크기 제한 1MB 1MB
접근 제어 더 세밀하게 제어 가능 기본 RBAC
암호화 etcd 암호화 지원 암호화 없음

▶️ Secret 사용 사례:

  • 비밀번호, API 키
  • TLS 인증서 및 키
  • OAuth 토큰
  • SSH 키

▶️ ConfigMap 사용 사례:

  • 애플리케이션 설정 파일
  • 환경별 설정
  • 명령줄 인수
  • 포트 번호, 리소스 제한

📌 Secret 생성 방법

✅ 명령형 방식으로 Secret 생성

kubectl 명령어를 사용하여 Secret을 생성하는 방법입니다.

# 리터럴 값으로 Secret 생성
kubectl create secret generic minio-creds \
  --from-literal=root-user=minio \
  --from-literal=root-password=minio123 \
  --namespace minio-system

# 파일에서 Secret 생성
echo -n "minio" > ./root-user.txt
echo -n "minio123" > ./root-password.txt
kubectl create secret generic minio-creds \
  --from-file=root-user=./root-user.txt \
  --from-file=root-password=./root-password.txt \
  --namespace minio-system

✅ 선언형 방식으로 Secret 생성

YAML 파일로 Secret을 정의하고 적용하는 방법입니다.

apiVersion: v1                   # 핵심 API 그룹의 v1 버전, Secret은 기본 리소스 타입
kind: Secret                     # 리소스 종류는 Secret
metadata:
  name: minio-creds              # Secret 이름, 나중에 이 이름으로 참조
  namespace: minio-system        # Secret이 속한 네임스페이스
type: Opaque                     # 일반적인 키-값 쌍에 사용되는 기본 Secret 타입
stringData:                      # stringData 필드는 자동으로 Base64 인코딩됨, 평문을 직접 입력할 때 사용
  root-user: minio               # MinIO 루트 사용자 이름, 평문으로 입력하면 쿠버네티스가 자동 인코딩
  root-password: minio123        # MinIO 루트 비밀번호, 평문으로 입력하면 쿠버네티스가 자동 인코딩
# YAML 파일 적용
kubectl apply -f minio-secret.yaml

✅ 다양한 Secret 타입

쿠버네티스는 여러 유형의 Secret을 지원합니다.

  1. Opaque: 기본 유형, 임의의 키-값 쌍 저장
  2. kubernetes.io/tls: TLS 인증서 및 키 저장
  3. kubernetes.io/dockerconfigjson: Docker 레지스트리 자격 증명
  4. kubernetes.io/service-account-token: 서비스 어카운트 토큰
  5. kubernetes.io/ssh-auth: SSH 인증 키
# TLS Secret 예시
apiVersion: v1                   # 핵심 API 그룹의 v1 버전
kind: Secret                     # 리소스 종류는 Secret
metadata:
  name: minio-tls                # TLS 인증서를 위한 Secret 이름
  namespace: minio-system        # Secret이 속한 네임스페이스
type: kubernetes.io/tls          # TLS 타입 Secret, 인증서와 키를 저장하기 위한 특별한 형식
data:
  tls.crt: base64_encoded_cert   # TLS 인증서 데이터, Base64로 인코딩됨
  tls.key: base64_encoded_key    # TLS 개인 키 데이터, Base64로 인코딩됨
# TLS Secret 생성 (인증서 파일 사용)
kubectl create secret tls minio-tls \
  --cert=path/to/cert.pem \
  --key=path/to/key.pem \
  --namespace minio-system

📌 MinIO에서 Secret 활용하기

✅ 환경 변수로 Secret 사용

MinIO Deployment에서 Secret을 환경 변수로 사용하는 방법입니다.

apiVersion: apps/v1              # 앱 API 그룹의 v1 버전, Deployment는 apps API 그룹에 속함
kind: Deployment                 # 리소스 종류는 Deployment, Pod의 복제본을 관리하는 컨트롤러
metadata:
  name: minio                    # Deployment 이름
  namespace: minio-system        # Deployment가 속한 네임스페이스
spec:
  selector:
    matchLabels:
      app: minio                 # Pod 선택자, 이 라벨을 가진 Pod를 관리
  replicas: 1                    # 복제본 수, MinIO 단일 인스턴스 배포
  template:
    metadata:
      labels:
        app: minio               # Pod 라벨, selector의 matchLabels와 일치해야 함
    spec:
      containers:
      - name: minio              # 컨테이너 이름
        image: minio/minio:RELEASE.2023-07-21T21-12-44Z  # MinIO 이미지 버전, 안정적인 특정 버전 사용
        args:
        - server                 # MinIO 서버 모드로 실행
        - /data                  # 데이터 저장 경로
        env:
        - name: MINIO_ROOT_USER  # MinIO 루트 사용자 환경 변수 이름
          valueFrom:
            secretKeyRef:
              name: minio-creds  # 참조할 Secret 이름
              key: root-user     # Secret에서 가져올 키 이름
        - name: MINIO_ROOT_PASSWORD  # MinIO 루트 비밀번호 환경 변수 이름
          valueFrom:
            secretKeyRef:
              name: minio-creds  # 참조할 Secret 이름
              key: root-password # Secret에서 가져올 키 이름
        ports:
        - containerPort: 9000    # MinIO API 포트
          name: api              # 포트 이름
        - containerPort: 9001    # MinIO 콘솔 포트
          name: console          # 포트 이름

✅ 볼륨으로 Secret 마운트

Secret을 볼륨으로 마운트하여 파일 시스템을 통해 접근하는 방법입니다.

apiVersion: apps/v1              # 앱 API 그룹의 v1 버전, StatefulSet은 apps API 그룹에 속함
kind: StatefulSet                # 리소스 종류는 StatefulSet, 상태 유지가 필요한 애플리케이션에 적합
metadata:
  name: minio                    # StatefulSet 이름
  namespace: minio-system        # StatefulSet이 속한 네임스페이스
spec:
  serviceName: minio-headless    # 헤드리스 서비스 이름, StatefulSet에 필수 필드
  replicas: 1                    # 복제본 수
  selector:
    matchLabels:
      app: minio                 # Pod 선택자
  template:
    metadata:
      labels:
        app: minio               # Pod 라벨
    spec:
      containers:
      - name: minio              # 컨테이너 이름
        image: minio/minio:RELEASE.2023-07-21T21-12-44Z  # MinIO 이미지
        args:
        - server                 # 서버 모드
        - /data                  # 데이터 경로
        env:
        - name: MINIO_ROOT_USER  # 환경 변수로 사용자 이름 지정
          valueFrom:
            secretKeyRef:
              name: minio-creds  # Secret 이름
              key: root-user     # 키 이름
        - name: MINIO_ROOT_PASSWORD  # 환경 변수로 비밀번호 지정
          valueFrom:
            secretKeyRef:
              name: minio-creds  # Secret 이름
              key: root-password # 키 이름
        volumeMounts:
        - name: data             # 데이터 볼륨 이름
          mountPath: /data       # 마운트 경로
        - name: minio-config     # 설정 볼륨 이름
          mountPath: /root/.minio/  # MinIO 설정 디렉토리
        - name: credentials      # 자격 증명 볼륨 이름
          mountPath: /etc/credentials  # 자격 증명 마운트 경로
          readOnly: true         # 읽기 전용으로 마운트, 보안 강화
      volumes:
      - name: credentials        # 자격 증명 볼륨 정의
        secret:
          secretName: minio-creds  # 사용할 Secret 이름
          items:                 # Secret의 특정 키만 선택적으로 마운트
          - key: root-user       # Secret의 키
            path: access-key     # 마운트될 파일 이름
          - key: root-password   # Secret의 키
            path: secret-key     # 마운트될 파일 이름
      - name: minio-config       # 설정 볼륨 정의
        emptyDir: {}             # 임시 볼륨
  volumeClaimTemplates:          # 영구 볼륨 클레임 템플릿
  - metadata:
      name: data                 # 볼륨 이름
    spec:
      accessModes: [ "ReadWriteOnce" ]  # 접근 모드
      resources:
        requests:
          storage: 10Gi          # 요청 스토리지 크기

✅ MinIO 액세스 키 관리

MinIO용 액세스 키와 시크릿 키를 Secret으로 관리하는 방법입니다.

apiVersion: v1                   # 핵심 API 그룹의 v1 버전
kind: Secret                     # 리소스 종류는 Secret
metadata:
  name: minio-user1-creds        # 특정 사용자를 위한 Secret 이름
  namespace: minio-system        # Secret이 속한 네임스페이스
  labels:
    app: minio                   # Secret 라벨, 관리 용이성을 위한 라벨링
    user: user1                  # 사용자 식별 라벨
type: Opaque                     # 일반 Secret 타입
stringData:                      # 자동 Base64 인코딩되는 평문 데이터
  access-key: user1              # 사용자 액세스 키
  secret-key: user1password      # 사용자 시크릿 키

MinIO의 액세스 키를 초기화하는 Job 예시:

apiVersion: batch/v1             # 배치 API 그룹의 v1 버전, Job은 배치 워크로드를 위한 리소스
kind: Job                        # 리소스 종류는 Job, 일회성 작업을 실행하는 컨트롤러
metadata:
  name: minio-create-user        # Job 이름
  namespace: minio-system        # Job이 속한 네임스페이스
spec:
  template:
    spec:
      restartPolicy: OnFailure   # 실패 시 재시작 정책
      containers:
      - name: mc                 # 컨테이너 이름
        image: minio/mc:latest   # MinIO 클라이언트 이미지
        command: ["/bin/sh", "-c"]  # 실행할 명령
        args:
        - |
          # MinIO 서버에 연결
          mc alias set myminio http://minio:9000 $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD
          
          # 새 사용자 생성
          mc admin user add myminio $USER_ACCESS_KEY $USER_SECRET_KEY
          
          # 정책 설정 (읽기 전용 예시)
          mc admin policy set myminio readwrite user=$USER_ACCESS_KEY
        env:
        - name: MINIO_ROOT_USER  # 루트 사용자 환경 변수
          valueFrom:
            secretKeyRef:
              name: minio-creds  # Secret 이름
              key: root-user     # 키 이름
        - name: MINIO_ROOT_PASSWORD  # 루트 비밀번호 환경 변수
          valueFrom:
            secretKeyRef:
              name: minio-creds  # Secret 이름
              key: root-password # 키 이름
        - name: USER_ACCESS_KEY  # 새 사용자 액세스 키
          valueFrom:
            secretKeyRef:
              name: minio-user1-creds  # 사용자 Secret 이름
              key: access-key    # 키 이름
        - name: USER_SECRET_KEY  # 새 사용자 시크릿 키
          valueFrom:
            secretKeyRef:
              name: minio-user1-creds  # 사용자 Secret 이름
              key: secret-key    # 키 이름

📌 Secret 보안 강화 방법

✅ etcd 암호화 설정

쿠버네티스 etcd 데이터베이스에서 Secret 데이터를 암호화하는 방법입니다.

  1. 암호화 구성 파일 생성:
# encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1  # API 서버 구성 API 그룹 버전
kind: EncryptionConfiguration  # 리소스 종류는 EncryptionConfiguration, API 서버 암호화 설정
resources:
  - resources:
    - secrets                  # 암호화할 리소스 유형, Secret만 암호화
    providers:
    - aescbc:                  # AES-CBC 암호화 프로바이더, 강력한 암호화 알고리즘
        keys:
        - name: key1           # 키 이름
          secret: <base64-encoded-key>  # Base64로 인코딩된 32바이트 암호화 키
    - identity: {}             # Identity 프로바이더, 암호화하지 않음 (fallback)
  1. kube-apiserver 구성 업데이트:
# API 서버에 암호화 설정 적용 (kubeadm 설치의 경우)
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml

# 다음 줄 추가 (spec.containers[].command 아래)
- --encryption-provider-config=/etc/kubernetes/encryption-config.yaml

# 볼륨 마운트 추가
volumeMounts:
- name: encryption-config
  mountPath: /etc/kubernetes/encryption-config.yaml
  readOnly: true

# 볼륨 정의 추가
volumes:
- name: encryption-config
  hostPath:
    path: /etc/kubernetes/encryption-config.yaml
    type: File
  1. 기존 Secret 재암호화:
# 모든 Secret 목록 가져오기
kubectl get secrets --all-namespaces -o json | kubectl replace -f -

✅ RBAC를 통한 Secret 접근 제어

RBAC(Role-Based Access Control)를 사용하여 Secret에 대한 접근을 제한하는 방법입니다.

apiVersion: rbac.authorization.k8s.io/v1  # RBAC API 그룹의 v1 버전
kind: Role                       # 리소스 종류는 Role, 네임스페이스 범위의 권한 집합
metadata:
  name: minio-secrets-reader     # Role 이름
  namespace: minio-system        # Role이 속한 네임스페이스
rules:
- apiGroups: [""]                # 핵심 API 그룹
  resources: ["secrets"]         # Secret 리소스에 대한 권한
  resourceNames: ["minio-creds"] # 특정 Secret 이름으로 범위 제한
  verbs: ["get", "watch", "list"]  # 허용할 동작, 읽기 전용 권한만 부여
---
apiVersion: rbac.authorization.k8s.io/v1  # RBAC API 그룹의 v1 버전
kind: RoleBinding                # 리소스 종류는 RoleBinding, Role과 사용자/그룹/서비스어카운트 연결
metadata:
  name: read-minio-secrets       # RoleBinding 이름
  namespace: minio-system        # RoleBinding이 속한 네임스페이스
subjects:
- kind: ServiceAccount           # 권한 부여 대상 종류
  name: minio-operator           # 권한을 부여할 ServiceAccount 이름
  namespace: minio-system        # ServiceAccount가 속한 네임스페이스
roleRef:
  kind: Role                     # 참조할 권한 종류
  name: minio-secrets-reader     # 참조할 Role 이름
  apiGroup: rbac.authorization.k8s.io  # Role이 속한 API 그룹

✅ Secret 불변성 설정

불변 Secret을 사용하여 수정을 방지하는 방법입니다.

apiVersion: v1                   # 핵심 API 그룹의 v1 버전
kind: Secret                     # 리소스 종류는 Secret
metadata:
  name: minio-creds-immutable    # Secret 이름
  namespace: minio-system        # Secret이 속한 네임스페이스
  annotations:
    reflector.v1.k8s.emberstack.com/reflection-allowed: "false"  # 외부 도구를 통한 반영 방지
immutable: true                  # 불변성 설정, 생성 후 변경 불가능하게 만듦
type: Opaque                     # 일반 Secret 타입
data:
  root-user: bWluaW8=            # Base64로 인코딩된 루트 사용자 이름
  root-password: bWluaW8xMjM=    # Base64로 인코딩된 루트 비밀번호

📌 Sealed Secrets와 외부 시크릿 관리

✅ Sealed Secrets 소개

Bitnami Sealed Secrets를 사용하여 Git에 안전하게 Secret을 저장하는 방법입니다.

# Sealed Secrets 컨트롤러 설치
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.19.4/controller.yaml

# kubeseal CLI 설치 (Mac)
brew install kubeseal

# 기존 Secret을 Sealed Secret으로 변환
kubectl create secret generic minio-creds \
  --from-literal=root-user=minio \
  --from-literal=root-password=minio123 \
  --namespace minio-system \
  --dry-run=client -o yaml | \
  kubeseal --format yaml > sealed-minio-creds.yaml

생성된 Sealed Secret 예시:

apiVersion: bitnami.com/v1alpha1  # Bitnami API 그룹, Sealed Secrets 전용 API
kind: SealedSecret              # 리소스 종류는 SealedSecret, 암호화된 Secret
metadata:
  name: minio-creds             # SealedSecret 이름, 복호화 후 생성될 Secret 이름과 동일
  namespace: minio-system       # SealedSecret이 속한 네임스페이스
spec:
  encryptedData:               # 암호화된 데이터, 클러스터 내 Sealed Secrets 컨트롤러만 복호화 가능
    root-password: AgBy8hCL...  # 암호화된 비밀번호 데이터
    root-user: AgBd42fX...      # 암호화된 사용자 이름 데이터
  template:
    metadata:
      name: minio-creds         # 생성될 Secret 이름
      namespace: minio-system   # 생성될 Secret 네임스페이스
    type: Opaque                # Secret 타입

✅ 외부 시크릿 관리 도구

외부 시크릿 관리 도구를 쿠버네티스와 통합하는 방법입니다.

  1. External Secrets Operator:
apiVersion: external-secrets.io/v1beta1  # External Secrets API 그룹
kind: ExternalSecret             # 리소스 종류는 ExternalSecret, 외부 시크릿 참조
metadata:
  name: minio-external-secret    # ExternalSecret 이름
  namespace: minio-system        # ExternalSecret이 속한 네임스페이스
spec:
  refreshInterval: 1h            # 새로고침 간격, 1시간마다 외부 소스에서 시크릿 가져옴
  secretStoreRef:
    name: aws-secretsmanager     # SecretStore 참조, 외부 시크릿 제공자 정보
    kind: ClusterSecretStore     # SecretStore 종류, 클러스터 전체 범위
  target:
    name: minio-creds            # 생성될 Secret 이름
    creationPolicy: Owner        # 생성 정책, 없으면 생성하고 있으면 관리
  data:
  - secretKey: root-user         # Secret에 저장될 키 이름
    remoteRef:
      key: minio/credentials     # 외부 시크릿 저장소의 키 경로
      property: username         # 해당 키의 특정 속성 (JSON 필드 등)
  - secretKey: root-password     # Secret에 저장될 키 이름
    remoteRef:
      key: minio/credentials     # 외부 시크릿 저장소의 키 경로
      property: password         # 해당 키의 특정 속성
  1. HashiCorp Vault 통합:
apiVersion: secrets.hashicorp.com/v1beta1  # HashiCorp Secrets API 그룹
kind: VaultSecret               # 리소스 종류는 VaultSecret, Vault 시크릿 참조
metadata:
  name: minio-vault-secret      # VaultSecret 이름
  namespace: minio-system       # VaultSecret이 속한 네임스페이스
spec:
  vaultAuthRef: vault-auth      # Vault 인증 참조
  mount: secret                 # Vault 시크릿 엔진 마운트 경로
  path: minio                   # Vault 내 시크릿 경로
  destination:
    name: minio-creds           # 생성될 Secret 이름
    create: true                # Secret이 없으면 생성
  type: Opaque                  # Secret 타입
  refreshAfter: 1h              # 새로고침 간격
  data:
    - key: credentials          # Vault 내 키 이름
      property: username        # 해당 키의 특정 속성
      secretKey: root-user      # Secret에 저장될 키 이름
    - key: credentials          # Vault 내 키 이름
      property: password        # 해당 키의 특정 속성
      secretKey: root-password  # Secret에 저장될 키 이름

📌 MinIO 자격 증명 순환

✅ 자격 증명 순환 전략

MinIO 자격 증명을 안전하게 순환(변경)하는 전략입니다.

▶️ 자격 증명 순환 단계:

  1. 새 Secret 생성
  2. 새 자격 증명을 MinIO에 적용
  3. 애플리케이션 구성 업데이트
  4. 이전 자격 증명 비활성화
  5. 검증 후 이전 Secret 삭제
apiVersion: v1                   # 핵심 API 그룹의 v1 버전
kind: Secret                     # 리소스 종류는 Secret
metadata:
  name: minio-creds-new          # 새 Secret 이름, 버전 또는 날짜 포함 가능
  namespace: minio-system        # Secret이 속한 네임스페이스
  labels:
    app: minio                   # 애플리케이션 라벨
    version: "v2"                # 버전 라벨, 자격 증명 버전 추적
type: Opaque                     # 일반 Secret 타입
stringData:                      # 자동 Base64 인코딩되는 평문 데이터
  root-user: minio               # 새 루트 사용자 이름 (또는 변경된 값)
  root-password: minio123new     # 새 루트 비밀번호, 보안 강화를 위해 복잡한 값 사용

 

자격 증명 순환을 위한 Job 예시:

apiVersion: batch/v1             # 배치 API 그룹의 v1 버전
kind: Job                        # 리소스 종류는 Job, 일회성 작업 실행
metadata:
  name: minio-credential-rotation  # Job 이름
  namespace: minio-system        # Job이 속한 네임스페이스
spec:
  template:
    spec:
      restartPolicy: OnFailure   # 실패 시 재시작 정책
      containers:
      - name: mc                 # 컨테이너 이름
        image: minio/mc:latest   # MinIO 클라이언트 이미지
        command: ["/bin/sh", "-c"]  # 실행할 명령
        args:
        - |
          # 현재 자격 증명으로 MinIO 서버에 연결
          mc alias set myminio http://minio:9000 $CURRENT_ROOT_USER $CURRENT_ROOT_PASSWORD
          
          # 루트 사용자 비밀번호 변경
          mc admin user add myminio $NEW_ROOT_USER $NEW_ROOT_PASSWORD --update
          
          # 연결 테스트
          sleep 5  # 변경사항이 적용될 시간 대기
          mc alias set myminio-new http://minio:9000 $NEW_ROOT_USER $NEW_ROOT_PASSWORD
          mc ls myminio-new
          
          echo "Credential rotation completed successfully"
        env:
        - name: CURRENT_ROOT_USER  # 현재 루트 사용자 환경 변수
          valueFrom:
            secretKeyRef:
              name: minio-creds    # 현재 Secret 이름
              key: root-user       # 키 이름
        - name: CURRENT_ROOT_PASSWORD  # 현재 루트 비밀번호 환경 변수
          valueFrom:
            secretKeyRef:
              name: minio-creds    # 현재 Secret 이름
              key: root-password   # 키 이름
        - name: NEW_ROOT_USER      # 새 루트 사용자 환경 변수
          valueFrom:
            secretKeyRef:
              name: minio-creds-new  # 새 Secret 이름
              key: root-user       # 키 이름
        - name: NEW_ROOT_PASSWORD  # 새 루트 비밀번호 환경 변수
          valueFrom:
            secretKeyRef:
              name: minio-creds-new  # 새 Secret 이름
              key: root-password   # 키 이름

✅ 애플리케이션 재구성 없는 자격 증명 순환

애플리케이션을 재시작하지 않고 자격 증명을 순환하는 방법입니다.

apiVersion: v1                   # 핵심 API 그룹의 v1 버전
kind: ConfigMap                  # 리소스 종류는 ConfigMap, 비민감 구성 데이터 저장
metadata:
  name: credential-updater       # ConfigMap 이름
  namespace: minio-system        # ConfigMap이 속한 네임스페이스
data:
  update-script.sh: |            # 스크립트 파일 내용
    #!/bin/sh
    # 자격 증명 순환 스크립트
    
    NEW_CREDS_DIR=/new-creds
    CREDS_DIR=/credentials
    
    # 새 자격 증명 파일 복사
    cp $NEW_CREDS_DIR/* $CREDS_DIR/
    
    # MinIO 프로세스에 SIGHUP 시그널 전송하여 설정 다시 로드
    pkill -SIGHUP minio
    
    echo "Credentials updated at $(date)"
apiVersion: batch/v1             # 배치 API 그룹의 v1 버전
kind: Job                        # 리소스 종류는 Job
metadata:
  name: in-place-credential-update  # Job 이름
  namespace: minio-system        # Job이 속한 네임스페이스
spec:
  template:
    spec:
      restartPolicy: OnFailure   # 실패 시 재시작 정책
      serviceAccountName: minio-updater  # 권한 있는 ServiceAccount 사용
      containers:
      - name: updater            # 컨테이너 이름
        image: busybox:latest    # 경량 기본 이미지
        command: ["/bin/sh", "/scripts/update-script.sh"]  # 실행할 명령
        volumeMounts:
        - name: scripts          # 스크립트 볼륨
          mountPath: /scripts    # 마운트 경로
        - name: new-credentials  # 새 자격 증명 볼륨
          mountPath: /new-creds  # 마운트 경로
        - name: minio-credentials  # MinIO 자격 증명 볼륨
          mountPath: /credentials  # 마운트 경로
      volumes:
      - name: scripts            # 스크립트 볼륨 정의
        configMap:
          name: credential-updater  # 사용할 ConfigMap
          defaultMode: 0755       # 실행 권한 부여
      - name: new-credentials    # 새 자격 증명 볼륨 정의
        secret:
          secretName: minio-creds-new  # 새 Secret 이름
      - name: minio-credentials  # MinIO 자격 증명 볼륨 정의
        persistentVolumeClaim:
          claimName: minio-credentials-pvc  # MinIO가 사용하는 PVC

📌 최소 권한 원칙 적용

✅ 서비스 계정과 최소 권한

최소 권한 원칙을 적용하여 MinIO 관련 서비스 계정을 설정하는 방법입니다.

apiVersion: v1                   # 핵심 API 그룹의 v1 버전
kind: ServiceAccount             # 리소스 종류는 ServiceAccount, Pod가 사용할 신원
metadata:
  name: minio-sa                 # ServiceAccount 이름
  namespace: minio-system        # ServiceAccount가 속한 네임스페이스
---
apiVersion: rbac.authorization.k8s.io/v1  # RBAC API 그룹의 v1 버전
kind: Role                       # 리소스 종류는 Role, 네임스페이스 범위의 권한 집합
metadata:
  name: minio-role               # Role 이름
  namespace: minio-system        # Role이 속한 네임스페이스
rules:
- apiGroups: [""]                # 핵심 API 그룹
  resources: ["secrets"]         # Secret 리소스에 대한 권한
  resourceNames: ["minio-creds"] # 특정 Secret으로 범위 제한
  verbs: ["get"]                 # 허용할 동작, 읽기만 가능
- apiGroups: [""]                # 핵심 API 그룹
  resources: ["services"]        # Service 리소스에 대한 권한
  verbs: ["get", "list"]         # 허용할 동작, 읽기만 가능
---
apiVersion: rbac.authorization.k8s.io/v1  # RBAC API 그룹의 v1 버전
kind: RoleBinding                # 리소스 종류는 RoleBinding, Role과 ServiceAccount 연결
metadata:
  name: minio-rolebinding        # RoleBinding 이름
  namespace: minio-system        # RoleBinding이 속한 네임스페이스
subjects:
- kind: ServiceAccount           # 권한 부여 대상 종류
  name: minio-sa                 # 권한을 부여할 ServiceAccount 이름
  namespace: minio-system        # ServiceAccount가 속한 네임스페이스
roleRef:
  kind: Role                     # 참조할 권한 종류
  name: minio-role               # 참조할 Role 이름
  apiGroup: rbac.authorization.k8s.io  # Role이 속한 API 그룹

MinIO Deployment에 서비스 계정 적용:

apiVersion: apps/v1              # 앱 API 그룹의 v1 버전
kind: Deployment                 # 리소스 종류는 Deployment
metadata:
  name: minio                    # Deployment 이름
  namespace: minio-system        # Deployment가 속한 네임스페이스
spec:
  # ... 다른 필드 생략 ...
  template:
    spec:
      serviceAccountName: minio-sa  # 사용할 ServiceAccount 지정, 최소 권한 원칙 적용
      # ... 다른 필드 생략 ...

✅ Pod 보안 컨텍스트 설정

Secret을 사용하는 Pod의 보안을 강화하는 방법입니다.

apiVersion: apps/v1              # 앱 API 그룹의 v1 버전
kind: Deployment                 # 리소스 종류는 Deployment
metadata:
  name: minio-secure             # Deployment 이름
  namespace: minio-system        # Deployment가 속한 네임스페이스
spec:
  # ... 다른 필드 생략 ...
  template:
    spec:
      serviceAccountName: minio-sa  # 사용할 ServiceAccount
      securityContext:            # Pod 수준 보안 컨텍스트
        fsGroup: 1000             # 파일 시스템 그룹 ID, 볼륨 마운트 권한 설정
        runAsNonRoot: true        # 루트가 아닌 사용자로 실행
        runAsUser: 1000           # 사용자 ID 1000으로 실행
      containers:
      - name: minio               # 컨테이너 이름
        # ... 다른 필드 생략 ...
        securityContext:          # 컨테이너 수준 보안 컨텍스트
          allowPrivilegeEscalation: false  # 권한 상승 방지
          readOnlyRootFilesystem: true     # 루트 파일시스템 읽기 전용
          capabilities:
            drop: ["ALL"]         # 모든 Linux 기능 제거
        volumeMounts:
        - name: credentials       # 자격 증명 볼륨
          mountPath: /credentials  # 마운트 경로
          readOnly: true          # 읽기 전용 마운트
        - name: data              # 데이터 볼륨
          mountPath: /data        # 마운트 경로
        - name: tmp               # 임시 디렉토리 볼륨
          mountPath: /tmp         # 마운트 경로
      volumes:
      - name: credentials         # 자격 증명 볼륨 정의
        secret:
          secretName: minio-creds  # Secret 이름
      - name: data                # 데이터 볼륨 정의
        persistentVolumeClaim:
          claimName: minio-data   # PVC 이름
      - name: tmp                 # 임시 디렉토리 볼륨 정의
        emptyDir: {}              # 임시 볼륨

📌 Summary

  • Secret은 쿠버네티스에서 민감한 자격 증명을 관리하는 핵심 리소스
  • 환경 변수 또는 볼륨 마운트를 통해 MinIO에 자격 증명 제공 가능
  • etcd 암호화를 통해 저장 데이터 보안 강화 가능
  • RBAC를 활용하여 Secret 접근을 최소 권한 원칙에 따라 제한
  • Sealed Secrets 및 외부 시크릿 관리 도구로 GitOps 워크플로우 보안 강화
  • 자격 증명 순환 전략으로 정기적인 보안 강화 가능
  • 서비스 계정과 보안 컨텍스트를 통해 추가적인 보안 레이어 구축

 

728x90