secrets-store-csi-driver-provider-azure icon indicating copy to clipboard operation
secrets-store-csi-driver-provider-azure copied to clipboard

Mount Objects/Sync Secrets By Regex Pattern From Key Vault

Open rkapoor028 opened this issue 4 years ago • 7 comments

Describe the solution you'd like [A clear and concise description of what you want to happen.]

Mount objects from Key Vault following a regex pattern. Could not find an existing way to do this.

Also can't find anyone asking this but it will be a useful feature if we can add Secrets using the regex pattern as well.

Is there a way to mount secrets, keys, certificate by specifying wildcards in the SecretProviderClass instead. It will help in case we need to mount many secrets from the Key Vault but all(secrets,keys,certs) follow a specific pattern eg:- frontend-msvc-* , backend-msvc-* etc. It will mount everything with that pattern in the volume from Key Vault.

Secrets by Regex Pattern

secretObjects:

  • secretName: frontend-msvc-* type: kubernetes.io/tls data:
    • objectName: frontend-msvc-* key: tls.key
    • objectName: frontend-msvc-* key: tls.crt

Objects by Regex Pattern

objects:  |
  array:
    - |
      objectName: frontend-msvc-*
      objectAlias: frontend-msvc-* 
      objectType: secret  
      objectVersion: "" 

Azure App Configuration Supports something similar by loading Secrets from KeyVault, Configuration from App Configuration following a greedy mode.

https://docs.microsoft.com/en-us/aspnet/config-builder#mode

Would love to hear thoughts on this?

Environment:

  • Secrets Store CSI Driver version: (use the image tag):mcr.microsoft.com/oss/kubernetes-csi/csi-node-driver-registrar:v2.0.1
  • Azure Key Vault provider version: (use the image tag):mcr.microsoft.com/oss/azure/secrets-store/provider-azure:0.0.10
  • Kubernetes version: (use kubectl version): 1.19.X
  • Cluster type: (e.g. AKS, aks-engine, etc): AKS

rkapoor028 avatar Jan 05 '21 20:01 rkapoor028

@rkapoor028 Thank you for opening the issue. This issue was initially created to get user consensus on this requirement: https://github.com/Azure/secrets-store-csi-driver-provider-azure/issues/61.

  1. Adding this feature would mean the service principal/managed identity used for auth would require list access for secrets/keys/certificates in key vault. Today, we only require get permissions.
  2. The regex if supported will only be for fetching the objects from key vault and writing it to the mount. For secretObjects to sync as K8s secrets it'll still require individual object names. A single k8s secret data field can't hold multiple values combined and the name being non deterministic is probably not a good approach.

aramase avatar Jan 06 '21 17:01 aramase

@aramase This would really be very useful, instead of defining repetitive objects bloating the SecretProviderClass file we can just match objects from KeyVault via a certain pattern.

For 2) Another approach can be that we define the name of the k8s secrectObject(msvc-frontend-secrets) that will be created/synced, and specify a pattern(msvc-frontend-*) based on which the Objects will be matched and loaded from the Keyvault as a Key/Value pair inside the secret. Keys inside the secretObject(msvc-frontend-secrets) can be set as the exact object name(msvc-frontend-secret1) in Keyvault so its pre-determined what the name of the key will be. For example

spec:
  provider: azure
  secretObjects:
  - secretName: msvc-frontend-secrets
    data:
      objectName: msvc-frontend-*
      objectType: Regex
    type: Opaque

Would sync the secret as below:-

kind: Secret
apiVersion: v1
metadata:
  name: msvc-frontend-secrets
  labels:
    secrets-store.csi.k8s.io/managed: 'true'
data:
  msvc-frontend-secret1: XXXXXXXXXXXXXXX
  msvc-frontend-secret2: XXXXXXXXXXXXXX
  msvc-frontend-secret3: XXXXXXXXXXXXXX
type: Opaque

Not sure, how much feasible it is.

rkapoor028 avatar Jan 10 '21 02:01 rkapoor028

For 2) Another approach can be that we define the name of the k8s secrectObject(msvc-frontend-secrets) that will be created/synced, and specify a pattern(msvc-frontend-*) based on which the Objects will be matched and loaded from the Keyvault as a Key/Value pair inside the secret. Keys inside the secretObject(msvc-frontend-secrets) can be set as the exact object name(msvc-frontend-secret1) in Keyvault so its pre-determined what the name of the key will be. For example

@rkapoor028 How are you consuming the content from Kubernetes secrets? Are you using the Kubernetes secret to configure as environment variables or actually reading the Kubernetes secret? I'm curious because if you use regex for secret data names, then the data keys aren't deterministic unless they're hardcoded in the yaml manifests for the env var/in the code.

aramase avatar Jan 11 '21 18:01 aramase

Yes, so in above approach, the secret data keys are the AKV secrets(msvc-frontend-secret1,msvc-frontend-secret2,msvc-frontend-secret3 so on..). We are referring those AKV secret name by the same name in the Deployment Yaml Manifests as the secret data key name(key: msvc-frontend-secret1, key: msvc-frontend-secret2, key: msvc-frontend-secret3 and so on...).

          env:          
          - name: BlobTableConnectionString1
            valueFrom:
              secretKeyRef:
                name: msvc-frontend-secrets
                key: msvc-frontend-secret1
          - name: BlobTableConnectionString2
            valueFrom:
              secretKeyRef:
                name: msvc-frontend-secrets
                key: msvc-frontend-secret2
          - name: BlobTableConnectionString3
            valueFrom:
              secretKeyRef:
                name: msvc-frontend-secrets
                key: msvc-frontend-secret3

So they are deterministic in the above approach. So the env variables BlobTableConnectionString1, BlobTableConnectionString2, BlobTableConnectionString3 etc. is what the app is expecting to be present and we are loading their values from k8s secret's appropriate data key.

rkapoor028 avatar Jan 11 '21 19:01 rkapoor028

This also might allow the drive to load all of the matching items via a single call to the provider where as today it has to perform a separate API call to get the value of each secret. Loading them one by one seems to be very resource intensive, where as the load used by the Configuration class Key vault extension loads them all in a few milliseconds.

trhumphries avatar Aug 10 '21 13:08 trhumphries

This also might allow the drive to load all of the matching items via a single call to the provider where as today it has to perform a separate API call to get the value of each secret. Loading them one by one seems to be very resource intensive, where as the load used by the Configuration class Key vault extension loads them all in a few milliseconds.

@trhumphries AFAIK the list API in keyvault only providers the metadata about the secrets/certs/keys. It doesn't return the actual secret value. To get the secret value it has to be a GET call on the individual secret. With regex, the provider would still need to list all secrets, perform client side filtering to find secrets that match regex and make a GET call for each secret.

aramase avatar Aug 10 '21 16:08 aramase

Well the AddAzureKeyVault extension to the Microsoft.Extensions.Configuration loads all of the secrets from a Key Vault several times faster than the CSI Driver does.

trhumphries avatar Aug 10 '21 17:08 trhumphries