고기 대신 SW 한점/Public Cloud

AWS Secrets Manager 사용하기

지식한점 2023. 3. 8. 09:09
반응형

K8S는 Secrets라는 리소스를 통해서 애플리케이션에 필요로하는 민감한 정보를 저장하고 관리할 수 있는 인터페이스를 제공하고 있습니다. 하지만 Kubernetes의 Secrets는 AWS Secrets Manager와 같은 외부 Secret 관리 system과 연동되지 않기 때문에 외부 Secret관리 System이 가지고 있는 기능들을 활용하지 못한다는 단점이 있습니다. K8s의 External Secrets는 이런 단점을 보완하기 위해 만들어진 System 입니다.

kubernetes-external-secrets

github :  GitHub - external-secrets/kubernetes-external-secrets: Integrate external secret management systems with Kubernetes

 

GitHub - external-secrets/kubernetes-external-secrets: Integrate external secret management systems with Kubernetes

Integrate external secret management systems with Kubernetes - GitHub - external-secrets/kubernetes-external-secrets: Integrate external secret management systems with Kubernetes

github.com

 

Example Architecture

External Secrets System 구성도
  • NodeJS 기반의 ExternalSecrets CRD를 통해 Backend의 Secret 저장소들과 연동
  • AWS Secrets Manager, AWS Parameter Store, Hashicorp Vault, AKS, GKS, Alibaba 등의 Secret Manager와 연동
  • 사용이 간편하며 기존 Secret Object를 사용하는 Pod들의 변경없이 사용 가능
  • IAM Integration
  • AWS 내부 EKS Slack Channel 및 Discussion 사이트 확인 결과 가장 많이 사용되고 있으며 가장 많이추천하고 있었음

External Secrets Controller가 External Secrets Resource에 해당되는 Key를 AWS Secrets Manager로 부터 가져와서 K8s Pod Secrets에 저장합니다. 

 

AWS Secretes Manager

# Check Sample AWS SecretsManager
$ aws secretsmanager list-secrets
{
    "SecretList": [
        {
            "ARN": "arn:aws:secretsmanager:ap-northeast-2:373394553405:secret:db-credential-SSstNC",
            "Name": "db-credential",
            "Description": "RDS Credential",
            "LastChangedDate": "2021-04-04T09:00:01.123000+09:00",
            "LastAccessedDate": "2021-04-04T09:00:00+09:00",
            "Tags": [],
            "SecretVersionsToStages": {
                "48ca88d2-badf-4a6a-bd2a-4ddaab0cc52a": [
                    "AWSCURRENT"
                ]
            }
        }
    ]
}
$ aws secretsmanager get-secret-value --secret-id db-credential
{
    "ARN": "arn:aws:secretsmanager:ap-northeast-2:373394553405:secret:db-credential-SSstNC",
    "Name": "db-credential",
    "VersionId": "48ca88d2-badf-4a6a-bd2a-4ddaab0cc52a",
    "SecretString": "{\"username\":\"admin\",\"password\":\"woowaP@$$w0rd\",\"engine\":\"mysql\",\"host\":\"database-1.cducwci7wujy.ap-northeast-2.rds.amazonaws.com\",\"port\":3306,\"dbInstanceIdentifier\":\"database-1\"}",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": "2021-03-24T15:54:49.662000+09:00"
}

 

 

External Secrets 권한 설정

External Secrets Controller가 Secrets를 가져오고 업데이트하는 등의 동작을 담당하고 있기 때문에 권한을 할당해야 하는 것도 External Secrets Controller의 임무입니다. 어떤 권한을 설정해야 하는지 알아보면, 먼저 접근 권한이 필요합니다. External Secrets에 말입니다. 접근을 해야 가져오고 업데이트를 할 수 있기 때문입니다.

IAM Policy for ServiceAccount

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecretVersionIds",
        "secretsmanager:GetRandomPassword",
        "secretsmanager:ListSecrets"       
      ],
      "Resource": "*"
    },
    {
          "Effect": "Allow",
      "Action": "ssm:GetParameter",
      "Resource": "*"
        }
  ]
}

 

External Secrets Custom Resource 생성

external-secrets-rds-sample.yaml

# Create ExternalSecret with Secrets Manager Backend
apiVersion: "kubernetes-client.io/v1"
kind: ExternalSecret
metadata:
  name: db-credential
spec:
  backendType: secretsManager
  # optional: specify role to assume when retrieving the data
  dataFrom:
    - db-credential
  # optional: specify a template with any additional markup you would like added to the downstream Secret resource.
  # This template will be deep merged without mutating any existing fields. For example: you cannot override metadata.name.
  template:
    metadata:
      annotations:
        type: rds
      labels:
        backend: secretsManager

 

Check Secrets

# Check Kubernetes Secrets
$ kubectl get secrets db-credential -o yaml
apiVersion: v1
data:
  dbInstanceIdentifier: ZGF0YWJhc2UtMQ==
  engine: bXlzcWw=
  host: ZGF0YWJhc2UtMS5jZHVjd2ankuYXAtbm9ydGhlYXN0LTIucmRzLmFtYXpvb=
  password: d29vd2FQQCQkdzByZA==
  port: MzMwNg==
  username: YWRW4=
kind: Secret
metadata:
  annotations:
    type: rds
  creationTimestamp: "2021-04-03T00:24:42Z"
  labels:
    backend: secretsManager
.
.
.
  name: db-credential
  namespace: default
  ownerReferences:
  - apiVersion: kubernetes-client.io/v1
    controller: true
    kind: ExternalSecret
    name: db-credential
type: Opaque

 

External Secrets 사용하기

사용하지 않은 경우에는 일반적으로 Base64 Encoding 되어 있는 값을 코드 리포지토리에 커밋 → 보안적 측면에서 Plain Text를 그대로 커밋하는 것과 차이가 없으나 AWS SecretsManager에 값을 넣어놓고 해당 값을 통해 Kubernetes Secret을 자동 생성하도록 한다.

# Get Env Variables from Secretsmanager to volume
envVariablesFromSecrets:
  - key: rds-credential
    name: DATA_ENDPOINT
    property: host
  - key: rds-credential
    name: DATA_USERNAME
    property: username
  - key: rds-credential
    name: DATA_PASSWORD
    property: password
  - key: rds-credential
    name: DATA_DATABASE
    property: dbname
  - key: shared-kafka-brokers
    name: shared-kafka-brokers
    property: host
  - key: dev-kafka-brokers
    name: dev-kafka-brokers
    property: host

 

 

AWS Secrets Manager에 Secrets 생성

 

  • App Chart에 ExternalSecrets Manifest만 정의하면 Secrets을 자동 생성해줌

배포 후 서비스에서 externalsecret 생성 확인가능함

apiVersion: "kubernetes-client.io/v1"
kind: ExternalSecret
metadata:
  name: {{ include "datasync.fullname" . }}-secrets
spec:
  backendType: secretsManager
  # optional: specify role to assume when retrieving the data
  data:
  {{- toYaml .Values.envVariablesFromSecrets | nindent 4 }}
  # optional: specify a template with any additional markup you would like added to the downstream Secret resource.
  # This template will be deep merged without mutating any existing fields. For example: you cannot override metadata.name.
  template:
    metadata:
      annotations:
        type: StringList
      labels:
        backend: secretsManager
반응형