澄清在 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。
我正在调查一个完全独立的问题,然后遇到了这个问题,引起了一些担忧:
我正在做一些非常相似的事情。我正在使用 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。