티스토리 뷰

728x90

회사에서 ECS -> EKS 전환을 추진하면서 EKS 스터디를 하고 있습니다

현재 DB정보 등 보안데이터를 AWS Secrets Manager에서 사용하고 있는데요

이번에 EKS의 Pod에서 AWS Secrets Manager로의 연동을 시도해봤습니다

 

이런저런 시행착오를 많이 겪었고 새로 알게된 개념이 많습니다

그냥 흘려보내기 아쉬워 한번 정리해봤습니다


 

과정

전체적인 구조와 흐름

 

1. Secrets Store CSI Driver 설치

Secrets Store CSI Driver는 Kubernetes에서 민감한 정보를 안전하게 관리하기 위해 외부 비밀 저장소(AWS Secrets Manager 등)와 연동하는 드라이버입니다. 이를 통해 Pod에 직접 시크릿을 마운트할 수 있어 애플리케이션이 필요한 정보를 안전하게 불러올 수 있습니다. Kubernetes는 시크릿 데이터가 관리되는 방식에 대해 신경 쓰지 않아도 되고, 민감한 정보가 AWS Secrets Manager와 같은 외부 시스템에서 관리되므로 보안성을 높일 수 있습니다.

https://github.com/aws/secrets-store-csi-driver-provider-aws

 

(테라폼이나 ArgoCD에서도 가능. 이번엔 CLI로 직접 수행)

helm repo add secrets-store-csi-driver <https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts>
helm repo update
helm install csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver --namespace kube-system --set syncSecret.enabled=true

# 설치 확인
kubectl --namespace=kube-system get pods -l "app=secrets-store-csi-driver"

Kubernetes Secret 리소스를 자동으로 생성하기 위해서는 syncSecret.enabled=true 꼭 설정해줘야 합니다

 

2. AWS Secrets Manager Provider 설치

AWS Secrets Manager Provider는 Kubernetes 클러스터에서 AWS 시크릿 매니저를 활용하기 위한 구성 요소입니다. Kubernetes의 Secrets Store CSI Driver와 함께 사용되어, AWS Secrets Manager에 저장된 비밀 정보를 Kubernetes의 Secret 리소스로 변환하여 자동으로 마운트할 수 있습니다.

kubectl --namespace=kube-system get pods -l "app=secrets-store-csi-driver"

 

3. IRSA 설정

IRSA(IAM Roles for Service Accounts)는 AWS와 Kubernetes를 연동하여, 클러스터 내의 Pod가 필요한 AWS 리소스에 안전하게 접근할 수 있도록 해주는 기능입니다. 이를 통해 각 Pod에 별도의 IAM 사용자 자격 증명을 사용하지 않고도 AWS 자원 접근 권한을 부여할 수 있습니다.

  • IAM (AWS Identity and Access Management): AWS 리소스에 접근할 수 있는 권한을 설정하는 AWS의 인증 및 권한 관리 서비스입니다.
  • 역할 (Role): IAM에서 특정 권한을 가진 역할을 정의하여 사용자가 아닌 서비스가 임시로 해당 역할을 사용할 수 있게 합니다.
  • 신뢰 관계 (Trust Relationship): 역할을 사용할 수 있는 주체를 정의합니다. IRSA에서는 Kubernetes의 ServiceAccount가 IAM 역할을 사용할 수 있도록 신뢰 관계를 설정합니다.
  • ServiceAccount: Kubernetes 내 리소스로, 각 Pod에 할당되어 AWS와의 권한 연동을 가능하게 합니다. 이를 통해 Pod가 AWS 리소스에 안전하게 접근할 수 있습니다.
  • OIDC (OpenID Connect): AWS는 Kubernetes 클러스터에서 OIDC를 사용해 Pod가 IAM 역할을 요청할 수 있도록 합니다. IRSA는 OIDC 제공자로서 클러스터의 인증을 AWS에 통합하여, Kubernetes의 ServiceAccount와 IAM 역할을 연결해주는 방식으로 작동합니다.
// IAM role 생성
aws iam create-role --role-name <롤 이름> --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "pods.eks.amazonaws.com" // EKS Pod 서비스가 이 롤을 사용할 수 있도록 설정
            },
            "Action": [
                "sts:AssumeRole", // Pod가 이 Role을 가져와서 부여된 권한을 사용할 수 있음
                "sts:TagSession" // 각 요청에 태그를 추가할 수 있음
            ]
        },
        { 
            "Effect": "Allow",
            "Principal": { // Pod 서비스에 대한 접근 권한을 부여
                "Federated": "arn:aws:iam::<계정 ID>:oidc-provider/oidc.eks.<리전>.amazonaws.com/id/<OIDC 식별자>"
                // oidc 프로바이더 지정
            },
            "Action": "sts:AssumeRoleWithWebIdentity", // oidc 토큰을 사용한 Role Assumption이 가능하도록 설정
            "Condition": { // 네임스페이스 별 접근 범위 제한
                "StringLike": {
                    "oidc.eks.<리전>.amazonaws.com/id/<OIDC 식별자>:sub": "system:serviceaccount:<네임스페이스>:*"
                }
            }
        }
    ]
}'

// 시크릿매니저 조회 권한 추가
aws iam put-role-policy --role-name <롤 이름> --policy-name SecretsManagerAccess --policy-document '{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "secretsmanager:GetSecretValue", // 시크릿 조회 권한 부여
      "Resource": "arn:aws:secretsmanager:<리전>:<계정 ID>:secret:<시크릿 이름>" // 접근하려는 시크릿의 ARN
    }
  ]
}'

(테라폼이나 aws 콘솔에서도 가능)

 

AWS Secrets Manager 뿐 아니라 RDS 등의 AWS 리소스들을 사용하신다면 알맞는 권한 설정이 중요합니다

여기서부터 아주 애를 먹었습니다 🥲

 

 

4. Service Account 설정

서비스 어카운트(Service Account)는 Kubernetes 클러스터 내에서 애플리케이션, 파드(Pod), 또는 기타 시스템 간의 인증을 처리하는 특수한 종류의 사용자 계정입니다. 서비스 어카운트는 사람이 아닌 시스템을 위한 계정으로, 일반적으로 애플리케이션이 클러스터 리소스에 접근할 때 사용됩니다. 이 계정은 쿠버네티스 클러스터에서 인증과 권한 부여를 위해 사용되며, 기본적으로 클러스터 내에서 동작하는 애플리케이션이나 서비스가 클러스터 리소스를 안전하게 액세스할 수 있도록 도와줍니다.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account
  namespace: test
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/<IAM Role name>
    # iam 역할을 k8s 서비스어카운트에 연결

 

IAM role을 만들었는데 Service Account는 또 뭐지?? 하고 아주 헷갈렸습니다

IAM role은 AWS의 역할, Service Account는 쿠버네티스의 리소스입니다.

쿠버네티스 클러스터에서 AWS의 리소스에 접근하고 싶을 경우 Service Account를 IAM Role에 연결시켜주어야 합니다.

 

 

5. Secret Provider Class 설정

SecretProviderClass는 Secrets Store CSI Driver가 사용할 시크릿 객체의 구성을 정의하는 Kubernetes 리소스입니다. 이 리소스를 사용하여 시크릿을 어떻게 가져올 것인지, 어떤 저장소에서 가져올 것인지 등을 설정합니다.

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: my-service-secret-provider
  namespace: test
spec:
  provider: aws # aws, gcp, azure 등의 제공자
  parameters:
    region: <aws-region>
    objects: |
      - objectName: "<secret-name>" # aws secrets manager 이름
        objectType: "secretsmanager"
        jmesPath: # json형태의 secrets 데이터를 jmesPath로 조회
        - path: "SPRING_DATASOURCE_PASSWORD" # 보안정보 가져올 필드
          objectAlias: "SPRING_DATASOURCE_PASSWORD" # k8s 시크릿 오브젝트에서 사용할 별칭
        - path: '"SPRING_DATASOURCE_JDBC-URL"' # 경로에 대시(-)가 포함된 경우 이스케이프 처리 필요 (작은따옴표로 감싸기)
          objectAlias: '"SPRING_DATASOURCE_JDBC-URL"'

  secretObjects: # k8s 시크릿 객체 정의
    - secretName: my-service-secrets
      type: Opaque
      data:
        - key: "SPRING_DATASOURCE_PASSWORD" # k8s 시크릿에서 사용할 키
          objectName: "SPRING_DATASOURCE_PASSWORD" # aws secrets manager에서 가져올 필드
        - key: "SPRING_DATASOURCE_JDBC-URL" # 여기는 이스케이프 없어도 됨
          objectName: '"SPRING_DATASOURCE_JDBC-URL"'

 

여기서 가장 고생을 많이 했는데요

jmesPath 문법에 맞지 않게 작성할 경우 k8s secret 리소스가 생성되지 않아서 Pod가 정상적으로 생성되지 않습니다

저의 경우 시크릿매니저에 등록된 특정 키에 대시(-)가 있었는습니다. jmesPath는 대시를 사용할때 작은따옴표로 감싸줘야 했는데 그걸 몰랐어서 문법오류로 시크릿이 생성되지 않았었습니다.

이 부분을 찾아내느라 아주 애를 먹었습니다 ㅠㅠ

 

6. Pod 설정

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      serviceAccountName: my-service-account # service account 지정
      containers:
        - name: my-container
          image: my-image:v1
          imagePullPolicy: Always
          ports:
            - name: tcp
              containerPort: 8080
          volumeMounts: # secrets volume mount
            - mountPath: "/mnt/secrets"
              name: secrets-store
              readOnly: true
          envFrom:
            - secretRef: # secret provicer class에서 생성한 secret에서 env 가져오기
                name: my-service-secrets
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: develop

      volumes:
        - name: secrets-store
          csi:
            driver: secrets-store.csi.k8s.io
            readOnly: true
            volumeAttributes:
              secretProviderClass: "my-service-secret-provider" # 볼륨에서 secret provide class 지정

 

 

# secret 잘 생성됐나 확인
kubectl get secrets -n <namespace>

# pod 잘 생성됐나 확인
kubectl get pods -n <namespace>

# secrets store csi driver 로그 조회
kubectl logs -n kube-system -l app=secrets-store-csi-drive

# pod 생성 실패할 경우 로그 조회
kubectl describe pod <pod-name> -n <namespace>

 

 

IAM, 신뢰관계, oidc, service account 등등 모르는 개념이 너무 많았어서 참 어려웠습니다

동료분들이나 팀장님이 도와주시고 같이 이것저것 시도해주셔서 어찌저찌 연동엔 성공한 것 같네요

 

다음엔 이런 작업들을 해보려고 합니다

1. 시크릿매니저에 등록된 키를 전부 수동으로 정의해줘야 하는데, 등록된 모든 키를 자동으로 넣을 수 있는 방법 모색해보기

2. 시크릿매니저에서 키가 자동으로 변경됐을 때 이미 띄워진 pod의 env에도 바뀐 값이 적용되는지, 혹은 배포가 필요한지 테스트 해보기

 

728x90
댓글
300x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함