Skip to content
This repository has been archived by the owner on May 1, 2021. It is now read-only.

Proposals of semantics for Secrets & Tags in Azure KeyVault #6

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

asnowfix
Copy link
Contributor

@asnowfix asnowfix commented Mar 5, 2021

Proposed CRD spec detailled explanation for Azure to feed the discussion in #4

@moolen
Copy link
Member

moolen commented Mar 6, 2021

Hey, first of all thank you for taking the time for writing a detailed write-up!

I took a closer look at the docs and found that Azure KV allows a user to store three different kinds of object-types:

  1. a key which is simply a JWK (docs)
  2. a secret which is just a binary blob without a predefined content-type and has attributes like expiry etc. docs
  3. the certificate API is a composition of a key (private key), a secret (exportable pubic key - the cert) and a certificate object that contains metadata (cert policies, exp, nbf...). When a certificate is created all three object-types have the same name.
  4. (there's actually a 4th one to manage storage account keys which i haven't looked deeper into)

I think it is important to make it explicit which object-type or better: which API to use when fetching the secret. We can not infer that from the ExternalSecret. We have a similar issue with AWS System Manager Parameter Store vs AWS Secrets Manager (see here)

I'd propose a similar semantic here, too:

apiVerson: external-secrets.io/v1alpha1
kind: SecretStore # or ClusterSecretStore
metadata:
  name: azure
spec:
  provider:
    # renamed this from `azurekv` to make it more generic
    azure: 
      # same as in the curren spec including tenantId etc.
      auth: {} 
      # we might want to add other services later on that use the same auth struct from above
      # e.g. for azure AppConfiguration 
      keyVault: 
        vaultUri: https://my-vault09.vault.azure.net/
        objectType: Secret # or Key or Certificate

Once it's clear what object-type to fetch we can do the bit of ✨ to extract cert bundles, properties etc.

Co-authored-by: Markus Maga <[email protected]>
@asnowfix
Copy link
Contributor Author

Thanks @moolen for the suggestion & thanks for the link to the JWK doc.

The Azure Secret type (TLS/ other) is not per Key Vault, but really per Secret, so putting this attribute in the SecretStore does not seem to make sense: If explicit, then it has to be somehow in the ExternalSecret CRD. That being said, looking at the GoLang API documentation, one see that the Secret type only comes as a output, not as as API type we can / should be making use of:

  1. https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/services/keyvault/v7.0/keyvault#BaseClient.GetSecret
  2. https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/services/keyvault/v7.0/keyvault#SecretBundle --> Content-Type gives whether the Secret is a TLS one (PKCS12) or something else.

Consequently, property type: in the earlier proposal is not appropriated. What we want to achieve here is really some type of post-processing (extract) depending on the secret-type as found in the SecretBundle properties. In particular, we want to make sure that we can generate ready-to-use TLS-type of K8s Secrets.

Here is an updated proposal:

    - secretKey: tls.cert
      # The reference to the certificate bundle in Azure Secret
      remoteRef:
        # The Azure Secret object name
        key: a-tls-secret-azure-name
        # How much of the secret bundle we want to get: one of "tls.key" | "tls.cert" | "none" (default, keep everything)
        extract: tls.key

Hopefully, this is getting closer to the AWS implementation, although this other one gives extraction instructions at SecretStore level.

@moolen
Copy link
Member

moolen commented Mar 16, 2021

Hey, i think we have a misunderstanding here (naming is really hard!): Azure KV lets you store three different kinds of objects: Key, Secret and Certificate:

The names of these objects can collide: you can have a secret with name foo, aswell as a key with name foo.

When designing the CRD (ExternalSecret and/or SecretStore) we need to be explicit what kind of object we want to fetch: secret, key or certificate - because these are three different API calls.

@ahmedmus-1A
Copy link

Hi @moolen

@moolen
Copy link
Member

moolen commented Mar 17, 2021

@ahmedmus21 i agree on the second point / the certificate!

About the key/secret thing: I triple-checked that you can have different objects with different types (key, secret) to have the same name (with the exception of the certificate). The azure documentation you mentioned says the name is unique. It doesn't tell you it's unique per object-type. I manually clicked that configuration in the Azure UI. Doesn't that configuration work for you, too?

@ahmedmus-1A
Copy link

yes you are correct , when I checked the first time , I checked the duplication between secrets and certificates and i didn't look into the keys.

may be because the implementation suggested here was assuming the keys are shipped within the certificate object and not a separate object

@moolen
Copy link
Member

moolen commented Mar 23, 2021

How should we proceed with the Store Spec? What do you think, should we (1) put the object-type into the store spec or (2) use a prefix in the key of an ExternalSecret or do you have other ideas?

(1) put object-type at store level

  • downside: a use would need to create three different SecretStore objects to operate on all object-types
  • upside: the logic how to fetch a secret is encapsulated in the SecretStore (its intended by design)
apiVerson: external-secrets.io/v1alpha1
kind: SecretStore # or ClusterSecretStore
metadata:
  name: azure
spec:
  provider:
    # renamed this from `azurekv` to make it more generic
    azure: 
      # same as in the curren spec including tenantId etc.
      auth: {} 
      # we might want to add other services later on that use the same auth struct from above
      # e.g. for azure AppConfiguration 
      keyVault: 
        vaultUri: https://my-vault09.vault.azure.net/
        objectType: Secret # or Key or Certificate

(2) use prefix to signify the object-type

  • upside: simpler to use, just setup 1 SecretStore
  • downside: implicit logic in the remoteRef.key
    # the store is generic and doesn't care about the object type
    # this way a user wouldn't need different `SecretStores` to access diferent object-types
    - secretKey: foo
       remoteRef:
         key: secret/some-secret # use .GetSecret() call
    - secretKey: bar
       remoteRef:
         key: key/my-key # .GetKey() to fetch jwks
    # same for certificate

The pkcs12 key/cert extraction part is generic enough to put that functionality into the template. I would consider this as out of scope for the azure kv provider.

For that particular use-case i prototyped a proposal here: external-secrets/external-secrets#69:
You could fetch a secret from any provider and decode & extract the key (or certificate) from it and encode it as PEM:

data:
  key: "{{ .secret | pkcs12key | pemPrivateKey }}"
  cert: "{{ .secret | pkcs12cert | pemCertificate }}"

There's still a bit of stuff missing to handle jwks, rsa, x509, ecdsa etc.

@ahmedmus-1A
Copy link

Sorry for not being active the last couple of weeks .

IMO , I'd prefer going with solution 2 . The object type is more a feature related to the secret itself and not to the back end.

I like the proposal of implementing the certificate/keys extraction and decoding in the template implementation . based on that , I will remove the certificate management code from here external-secrets/22 and let the operator return only the raw data.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants