澄清在 Kubernetes 清单中使用 secretKeyRef 的安全性

Clarification on the security of using secretKeyRef in Kubernetes manifest

我正在调查一个完全独立的问题,然后遇到了这个问题,引起了一些担忧:

我正在做一些非常相似的事情。我正在使用 Azure 的 CSI Driver 将 Azure Kubernetes 服务与 Azure Key Vault 集成。我的集成清单是这样的:

apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentity
metadata:
  name: aks-akv-identity
  namespace: prod
spec:
  type: 0                                 
  resourceID: $identityResourceId
  clientID: $identityClientId
---
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentityBinding
metadata:
  name: aks-akv-identity-binding
  namespace: prod
spec:
  azureIdentity: aks-akv-identity
  selector: aks-akv-identity-binding-selector
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
  name: aks-akv-secret-provider
  namespace: prod
spec:
  provider: azure
  secretObjects:
  - secretName: ${resourcePrefix}-prod-secrets
    type: Opaque
    data:
    - objectName: PROD-PGDATABASE
      key: PGDATABASE
    - objectName: PROD-PGHOST
      key: PGHOST
    - objectName: PROD-PGPORT
      key: PGPORT
    - objectName: PROD-PGUSER
      key: PGUSER
    - objectName: PROD-PGPASSWORD
      key: PGPASSWORD
  parameters:
    usePodIdentity: "true"                                        
    keyvaultName: ${resourceGroupName}akv
    cloudName: ""                               
    objects: |
      array:
            objectName: PROD-PGDATABASE             
            objectType: secret                 
            objectVersion: ""
        - |
            objectName: PROD-PGHOST             
            objectType: secret                 
            objectVersion: ""
        - |
            objectName: PROD-PGPORT             
            objectType: secret                 
            objectVersion: ""
        - |
            objectName: PROD-PGUSER             
            objectType: secret                 
            objectVersion: ""
        - |
            objectName: PROD-PGPASSWORD             
            objectType: secret                 
            objectVersion: ""
    tenantId: $tenantId

然后在微服务清单中:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment-prod
  namespace: prod
spec:
  replicas: 3
  selector:
    matchLabels:
      component: api
  template:
    metadata:
      labels:
        component: api
        aadpodidbinding: aks-akv-identity-binding-selector
    spec:
      containers:
        - name: api
          image: appacr.azurecr.io/app-api
          ports:
            - containerPort: 5000
          env:
            - name: PGDATABASE
              valueFrom:
                secretKeyRef:
                  name: app-prod-secrets
                  key: PGDATABASE
            - name: PGHOST
              value: postgres-cluster-ip-service-prod
            - name: PGPORT
              valueFrom:
                secretKeyRef:
                  name: app-prod-secrets
                  key: PGPORT
            - name: PGUSER
              valueFrom:
                secretKeyRef:
                  name: app-prod-secrets
                  key: PGUSER
            - name: PGPASSWORD
              valueFrom:
                secretKeyRef:
                  name: app-prod-secrets
                  key: PGPASSWORD
          volumeMounts:
            - name: secrets-store01-inline
              mountPath: /mnt/secrets-store
              readOnly: true
      volumes:
        - name: secrets-store01-inline
          csi:
            driver: secrets-store.csi.k8s.io
            readOnly: true
            volumeAttributes:
              secretProviderClass: aks-akv-secret-provider
---
apiVersion: v1
kind: Service
metadata:
  name: api-cluster-ip-service-prod
  namespace: prod
spec:
  type: ClusterIP
  selector:
    component: api
  ports:
    - port: 5000
      targetPort: 5000

然后在我的申请中settings.py:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ['PGDATABASE'],
        'USER': os.environ['PGUSER'],
        'PASSWORD': os.environ['PGPASSWORD'],
        'HOST': os.environ['PGHOST'],
        'PORT': os.environ['PGPORT'],
    }
}

我的 Dockerfile 中没有任何内容涉及这些变量,只是 Django 微服务代码。

根据 link,其中一条评论是:

current best practices advise against doing this exactly. secrets managed through environment variables in docker are easily viewed and should not be considered secure.

所以我第二次猜测这种方法。

我需要考虑修改这里的内容吗?

link 中的建议是将 os.environ[] 与对从密钥保管库中提取凭据的方法的调用放在一起......但是即使访问密钥保管库的凭据也会需要保密...所以我看不出它有什么不同。


注意: 我注意到的一件事是 env: 的使用,将机密安装到卷是多余的。后者是根据 the documentation 集成完成的,但它使秘密可从 /mnt/secrets-store 获得,因此您可以执行类似 cat /mnt/secrets-store/PROD-PGUSER 的操作。 os.environ[] 并不是真正必要的,我认为 env: 也不是因为你可以从 Pod 中的那个位置提取秘密。

至少像下面这样打印出秘密值:

kubectl exec -it $(kubectl get pods -l component=api -o custom-columns=:metadata.name -n prod) -n prod -- cat /mnt/secrets-store/PROD-PGUSER

对您链接的答案的评论不正确。我留下了一张纸条来解释混乱。你所拥有的很好,如果可能过度构建 :) 与直接使用 Kubernetes Secrets 相比,你实际上并没有获得任何安全性,但如果你更喜欢围绕 AKV 的工作流程,那么这看起来不错。你可能想看看 externalsecrets 而不是 CSI 东西的这个奇怪的侧面特征? CSI 驱动程序更适合将内容公开为文件而不是外部->Secret->envvar。