อยากใช้ secrets จาก AWS Secrets Manager ใน Kubernetes Cluster มีเครื่องมืออะไรน่าสนใจบ้าง?
Interesting tools for syncing secrets from AWS Secrets Manager into the Kubernetes Cluster
ผู้ใช้งาน Kubernetes ส่วนใหญ่มักจะมีข้อกังวลในการจัดเก็บ Kubernetes Secret configs ที่มีการ encode secret เป็น base64 ใน repository เนื่องจากสามารถ decode secret กลับมาได้โดยง่าย และด้วย Kubernetes by default ไม่รองรับการ encrypt secret ด้วย Custom managed key ปัจจุบันจึงมี solutions มากมายเกิดขึ้น เพื่อเพิ่มความปลอดภัยให้ Kubernetes Secret configs
บาง solution จะใช้เครื่องมือเข้ามาช่วยในการ encrypt secret ใน configs และใช้เครื่องมือดังกล่าว decrypt secret เมื่อมีการสร้าง Kubernetes Secret resource เช่น Sealed Secrets เป็นต้น ซึ่งช่วยให้มีความมั่นใจในจัดเก็บ configs มากขึ้น
อย่างไรก็ตามหากใช้ AWS อยู่แล้ว การย้าย secrets มาเก็บใน AWS Secrets Manager ถือเป็น solution ที่น่าสนใจมาก เพราะนอกจากจะช่วยให้ secrets ได้รับการจัดเก็บอย่างปลอดภัยและเชื่อถือได้แล้ว ยังสามารถจัดการ access ตรวจสอบ logs และไม่ต้องจัดเก็บ Kubernetes Secret configs อีกด้วย (แต่เก็บอย่างอื่นที่ไม่ sensitive แทน)
แล้วจะใช้ secrets จาก AWS Secrets Manager ใน Kubernetes Cluster ยังไง?
ในบล็อกนี้จะเล่าถึงเครื่องมือที่น่าสนใจ 2 ตัว คือ External Secrets Operator และ AWS Secrets and Configuration Provider ที่ช่วยให้สามารถใช้ secrets จาก AWS Secrets Managerใน Kubernetes Cluster ว่ามีแนวคิดและหลักการทำงานยังไงบ้าง และทำไมถึงน่าสนใจ
1. External Secrets Operator (ESO)
ESO เป็น Kubernetes Operator ที่เกิดจากการ merged กันของโปรเจกต์จาก GoDaddy’s และโปรเจกต์ต่าง ๆ ที่มีจุดมุ่งหมายเดียวกัน คือ sync secrets จาก external secret providers มาที่ Kubernetes Secrets โดยรองรับทั้ง AWS Secrets Manager, AWS Systems Manager Parameter Store และอื่น ๆ
แนวคิด
ESO ประกอบไปด้วย Custom Resources Definitions (CRDs) หลัก ๆ คือ
- SecretStore สำหรับระบุวิธีการ authenticate และ access external secret provider
# SecretStore example
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: secretstore-sample
spec:
provider:
aws:
service: SecretsManager
region: ap-southeast-1
auth:
secretRef:
accessKeyIDSecretRef:
name: awssm-secret
key: access-key
secretAccessKeySecretRef:
name: awssm-secret
key: secret-access-key
- ExternalSecret (template) สำหรับระบุรายละเอียดของ Kubernetes Secret ที่ต้องการสร้างและ secrets ที่ต้องการ fetch
# ExternalSecret example
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: example
spec:
refreshInterval: 1h
secretStoreRef:
name: secretstore-sample
kind: SecretStore
target:
name: secret-to-be-created
dataFrom:
- extract:
key: remote-key-in-the-provider
เมื่อสร้าง resources ของ SecretStore
และ ExternalSecret
แล้ว ESO จะทำการ fetch secrets จาก external secret provider (AWS Secrets Manager)โดยใช้วิธีการ authenticate และ access ตามที่ระบุไว้ใน SecretStore
แล้วสร้างเป็น Kubernetes Secret ตามรายละเอียดใน ExternalSecret
สำหรับ AWS provider สามารถเลือกใช้ authentication ใน SecretStore
ได้ 3 แบบ ดังนี้
- Controller’s Pod Identity
- Access Key ID and Secret Access Key
- EKS Service Account credentials
ความน่าสนใจ
- เมื่อ values บน Secrets Manager มีการเปลี่ยนแปลง ESO จะอัปเดต Kubernetes Secret ให้อัตโนมัติ ตามรอบ
refreshInterval
- Kubernetes Secret จะถูกสร้างและลบตาม
ExternalSecret
- ไม่ต้องปรับ container configs
2. AWS Secrets and Configuration Provider (ASCP)
ASCP เป็น plug-in เสริมของ Secrets Store CSI Driver จาก Kubernetes Special Interest Groups (SIGs) สำหรับ mount secrets จาก AWS provider มาที่ container’s file system ใน Kubernetes Pod ผ่าน Container Storage Interface (CSI) volume โดยรองรับทั้ง AWS Secrets Manager และ AWS Systems Manager Parameter Store
แนวคิด
Secrets Store CSI Driver มี Custom Resources Definitions (CRDs) หลัก คือ
- SecretProviderClass สำหรับระบุที่อยู่ของ external secrets และรายละเอียดของ secrets ที่ต้องการ fetch
# SecretProviderClass example
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
name: basic-test-mount-spc
spec:
provider: aws
parameters:
objects: |
- objectName: password-secret
objectType: secretsmanager
ในส่วนของ Kubernetes Pod container ที่ต้องการใช้ secrets จำเป็นต้องเพิ่ม volume configs สำหรับเขียน secrets ดังนี้
# Pod example
apiVersion: v1
kind: Pod
...
spec:
containers:
- ...
volumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets-store"
readOnly: true
volumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: basic-test-mount-spc
...
เมื่อ Kubernetes Pod มีการ start หรือ restart, Secrets Store CSI Driver และ ASCP จะสื่อสารไปยัง external secret provider (AWS Secrets Manager) เพื่อทำการ fetch secrets ตามที่ระบุไว้ใน SecretProviderClass
จากนั้น mount secrets เป็น file ไปที่ Kubernetes Pod volume
นอกจากนี้ หากต้องการสร้าง Kubernetes Secret เพื่อ mirror secrets ใน Kubernetes Pod volume สามารถกำหนดรายละเอียดของ Kubernetes Secret ด้วยการเพิ่ม secretObjects
field ใน SecretProviderClass
การสร้าง Kubernetes Secret จำเป็นต้องมีการ mount volume สำหรับ mirror secrets ไปที่ Kubernetes Secrets! (ไม่ mount volume ได้ไหม?)
# SecretProviderClass secretObjects example
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
...
spec:
...
secretObjects:
- secretName: basic-test-mount-secret
type: Opaque
data:
- objectName: password-secret
key: password
ความน่าสนใจ
- อัปเดต Kubernetes Pod volume และ Kubernetes Secret อัตโนมัติ เมื่อ external secrets มีการเปลี่ยนแปลง
- Kubernetes Secret จะถูกสร้างเฉพาะเมื่อต้องการใช้งานจริง ๆ
สิ่งที่ต้องพิจารณา
- ต้องเพิ่ม volume configs ใน Kubernetes Pod container
จะเห็นได้ว่าเครื่องมือทั้ง 2 ตัว มีจุดมุ่งหมายในทางเดียวกัน แต่มีแนวคิด หลักการทำงาน และความน่าสนใจที่แตกต่างกันไป เครื่องมือเหล่านี้เป็นเพียงส่วนหนึ่งของเครื่องมือที่ช่วย support การใช้ secrets จาก external providers ใน Kubernetes Cluster การเลือกใช้อาจจะต้องพิจารณาจากหลาย ๆ ปัจจัยร่วมกัน ไม่จำเป็นต้องเลือกใช้เครื่องมือที่ดีที่สุด ให้เลือกใช้เครื่องมือที่เหมาะกับเรา ณ เวลานั้นที่สุด
Use the right tool at the right time :)