티스토리 뷰
목표
쿠버네티스에서 external secret operator를 사용하여 계정 정보와 같은 시크릿 정보들을 GCP secret manager에 저장해두고 어플리케이션에서 접근하여 사용할 수 있도록 한다.
Install external-secret
- external secret과 관련된 리소스를 사용하기 위해서는 external-secrets 헬름 차트를 먼저 설치해야한다.
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets
external-secrets/external-secrets \
-n external-secrets \
--create-namespace
helm templates 작성
externalsecret.yaml
external secret은 어떤 데이터를 가져와야 하는지 데이터를 어떻게 secret으로 저장할지 지정한다.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
{{- with $.Values.secret }}
name: {{ .externalSecret.name }}
namespace: {{ $.Values.namespace }}
spec:
refreshInterval: 1m
secretStoreRef:
kind: SecretStore
name: {{ .secretStore.name }}
target:
name: {{ .externalSecret.target }}
data:
- secretKey: {{ .externalSecret.data.secretKey }}
remoteRef:
key: {{ .externalSecret.data.remoteRefKey }}
{{- end }}
- refreshInterval: 시크릿을 리프레시 하는 주기를 설정한다. 변경 주기를 고려하여 설정한다. 기본은 한시간(1h)으로 되어있다.
- secretStoreRef: 참조할 시크릿 저장소를 지정한다. 아래의
secretstroe.yaml
에서 생성된다. - target: 쿠버네티스에 생성할 시크릿 객체의 이름(kubectl get secrets에서 확인되는 이름)
- data
- secretKey: 시크릿으로 저장될 파일의 이름
- remoteRef: google cloud secret manager에 저장된 시크릿의 name
secretstore.yaml
secret store는 외부 API에 엑세스하는 방법을 지정한다.
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: {{ .Values.secret.secretStore.name }}
namespace: {{ .Values.namespace }}
spec:
provider:
gcpsm:
projectID: {{ .Values.secret.secretStore.projectID }}
auth:
workloadIdentity:
{{- with .Values.secret.secretStore.workloadIdentity }}
clusterLocation: {{ .clusterZone }}
clusterName: {{ .clusterName }}
clusterProjectID: {{ .clusterProjectID}}
{{- end }}
serviceAccountRef:
name: {{ .Values.serviceAccount.ksaName }}
- provider: gcpsm은
GCP Secret Manager
를 의미한다. - projectID: secret manager를 사용할 프로젝트 이름
- auth: 인증 방식을 선택한다. 여기서는 workloadIdentity로 선택했다. workloadIdentity를 생성하지 않은 상태라면 생성이 필요하다(공식문서 참고). service account를 직접 기재하는 방법도 있다.
- cluster*: service account로 인증할 클러스터의 정보(service account가 존재하는 프로젝트 명)
- serviceAccountRef: Kubernetes 서비스 계정의 이름
serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
{{- with $.Values.serviceAccount }}
annotations:
iam.gke.io/gcp-service-account: {{ .gsaName }}@{{ .projectID }}.iam.gserviceaccount.com
name: {{ .ksaName }}
namespace: {{ $.Values.namespace }}
{{- end }}
annotations: GCP에 생성한 service account를 기재한다. 해당 서비스 어카운트에는
Secret manager Secret Accessor
,Service Account Token Creator
Role이 부여되어 있어야한다.name: Kubernetes 서비스 계정의 이름. 위에 기재한 서비스 어카운트를 쿠버네티스에서 어떤 이름으로 사용할지 지정한다.
Service Account Role Binding
참고했던 글에서는 위의 과정만으로 인증이 되었다고 써있었는데 나는 추가적으로 role binding을 해준 후에야 제대로 인증이 되었다.
Workload Identity User Role
gcloud iam service-accounts add-iam-policy-binding {gsaName}@{projectID}.iam.gserviceaccount.com \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:{projectID}.svc.id.goog[{namespace}/{ksaName}]"
Token Creator Role
gcloud iam service-accounts add-iam-policy-binding {gsaName}@{projectID}.iam.gserviceaccount.com \ --role roles/iam.serviceAccountTokenCreator \ --member "serviceAccount:{projectID}.svc.id.goog[{namespace}/{ksaName}]"
리소스 확인
각 resource를 배포하거나, helm install을 통해서 배포하면 kuebetl get 명령어를 통해 리소스가 생성된 것을 확인할 수 있다.
❯ kubectl get externalsecret -n {namespace}
NAME STORE REFRESH INTERVAL STATUS READY
gcp-external-secret gcp-backend 1m SecretSynced True
❯ kubectl get secretstore -n {namespace}
NAME AGE STATUS CAPABILITIES READY
gcp-backend 30d Valid ReadWrite True
또한 external secret을 연결하여 생성된 secret도 생성된 것을 확인할 수 있다.
❯ kubectl get secrets -n {namespace}
NAME TYPE DATA AGE
secret-target Opaque 1 30d
kubectl describe
명령어를 사용하면 세부적인 설정 값들을 확인할 수 있다.
Secret Test Pod 띄워보기
생성된 시크릿을 제대로 접근해서 사용할 수 있는지 test용 pod을 띄워서 확인한다.
# secret-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-test
namespace: hl-test
spec:
containers:
- image: nginx
name: nginx
command: ["sleep","infinity"]
volumeMounts:
- mountPath: /data
name: secret-volume
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: {secret object name}
volumes:
secret-volume
이라는 볼륨을 생성하고, external secret에서 target으로 지정한 이름(생성된 secret의 이름)을 적어준다.containers.volumeMounts: 생성한 볼륨에서 마운트할 경로를 지정해준다.
테스트
kubectl apply -f secret-test.yaml
kubectl exec -it secret-test --namespace NAMESPACE -- /bin/bash
로 접속하여/data
에 지정한 시크릿이 있는지 확인
마무리
external secret을 사용하여 외부에서 시크릿을 관리하게 되면 시크릿이 클러스터 내에서 노출될 위험이 줄기 때문에 보안 측면에서 장점이 존재한다. 또한 시크릿을 관리하는 주체를 통합할 수 있기때문에 관리 측면에서도 용이하고 여러 쿠버네티스 클러스터 및 여러 애플리케이션 간에 시크릿을 공유하고 재사용 수 있어 확장성도 향상된다는 장점이 있다.
쿠베 새싹이 이리저리 두드려보면서 한거라 잘한건지는 모르겠지만,, 헬름 차트를 처음 작성해보면서 정리해두고 싶은 내용이라 정리해보았다. (혹시나 틀린 내용이 있다면 댓글로 알려주시면 감사하겠습니다🙏)
참고
https://blog.container-solutions.com/tutorial-how-to-set-external-secrets-with-gcp-secret-manager
https://external-secrets.io/latest/introduction/getting-started/
https://nangman14.tistory.com/76
'k8s' 카테고리의 다른 글
[Helm] Quickstart - Helm Install, Uninstall, Rollback (0) | 2023.08.24 |
---|---|
Kubernetes NGINX Ingress Controller 설치 (0) | 2023.08.12 |