kubernetes-sigs / kustomize

Customization of kubernetes YAML configurations
Apache License 2.0
11.02k stars 2.25k forks source link

secretGenerator to generate Secret with stringData manifest #5142

Open valerytschopp opened 1 year ago

valerytschopp commented 1 year ago

Eschewed features

What would you like to have added?

The secretGenerator should be able to generate Secret manifest with unencoded stringData.

We understand that kustomize eschews parameterization, but the resulting manifest is valid YAML, and can be processed by various tools (envsubst, flux post-build variable substitution, ...). Therefore we ask the Kustomize SIG to consider this feature.

Example:

cat<<EOF> secret-values.yaml
# Helm values
---
db:
  auth:
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
  host: ${DB_HOST}
EOF
cat<<EOF> kustomization.yaml
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- name: secret-values
  files:
  - values.yaml=secret-values.yaml
generatorOptions:
  disableNameSuffixHash: true
  stringData: true
EOF
kustomize build .
apiVersion: v1
kind: Secret
metadata:
  name: secret-secret-values
stringData:
  values.yaml: |-
    db:
      auth:
        username: ${DB_USERNAME}
        password: ${DB_PASSWORD}
      host: ${DB_HOST}

Why is this needed?

We are doing GitOps with Flux's post-build variable substitution which currently requires stringData in the secret. Base64 encoded values would not be able to be substitued.

Can you accomplish the motivating task without this feature, and if so, how?

Create the Secret by hand with stringData:

---
apiVersion: v1
kind: Secret
metadata:
    name: secret-secret-values
stringData:
  values.yaml: |-
    db:
      auth:
        username: ${DB_USERNAME}
        password: ${DB_PASSWORD}
      host: ${DB_HOST}

But this negate the usefulness of Kustomize generators.

What other solutions have you considered?

Don't use secretGenerator for Helm secret values

Anything else we should know?

No response

Feature ownership

valerytschopp commented 1 year ago

This old issue https://github.com/kubernetes-sigs/kustomize/issues/1444 was simply closed without being commented, or addressed.

seh commented 1 year ago

We are doing GitOps with Flux's post-build variable substitution which currently requires stringData in the secret.

To clarify, post-build substitution does not require use of the "stringData" field in a candidate manifest, but you want to use that field to sidestep the Base64 encoding, which masks the content you wish to replace.

Flux doesn't pay any attention to field names in the manifests. It serializes them as YAML, and runs envsubst over the bytes.

valerytschopp commented 1 year ago

The Flux's post-build variable substitution documentation clearly states:

Note: For substituting variables in a secret, .spec.stringData field must be used i.e:

---
apiVersion: v1
kind: Secret
metadata:
  name: secret
  namespace: flux-system
type: Opaque
stringData:
  token: ${token}
seh commented 1 year ago

Yes, that's the documentation clarifying a common situation in which post-build substitution cannot see the content you'd like it to act upon. You have the same problem editing comments in PEM-encoded X.509 certificate bundles that occur in a (Valida|Muta)tingWebhookConfiguration's "webhooks[*].clientConfig.caBundle" field, which is also Base64-encoded.

The Flux documentation is correct, but not complete. I was explaining why you need to use the Secret "stringData" field here.

simion commented 1 year ago

We also need this, we're using envsubst and it does not work on Secret/data. We need stringData option :D

seh commented 1 year ago

I could see implementing this, accepting an option in the "secretGenerator[*].options" field, though that field is of type api/types/GeneratorOptions, which means that it's shared with other generators. Alternately, we could lift such an option up into api/types/SecretArgs which already bears the Secret-specific "type" field.

The api/internal/generators.MakeSecret function appears to be the place to handle such a change.

annasong20 commented 1 year ago

Hi @valerytschopp, thank you for explaining your use case and providing an example in your description. Thanks @seh for investigating.

Yes, we believe it is a reasonable use case to specify the secretGenerator add the data under a stringData field. This may also apply to the binaryData field for ConfigMaps. Can whoever wants to contribute to this feature write a mini-KEP aka kustomize proposal? We will start PR reviews for this feature once that KEP has been approved.

/triage accepted

filedeploy commented 1 year ago

Edit: Doesn't work - secretGenerator base64 encodes the values, but stringData expects plaintext.

This also works in the meantime:

secretGenerator:
  - name: my-secret
    ...details...

patches:
  # Patch the above secret `data` -> `stringData` because secretGenerator doesn't support `stringData`
  - patch: |-
      - op: move
        from: /data
        path: /stringData
    target:
      kind: Secret
      name: my-secret
seh commented 1 year ago

This also works in the meantime:

What about the Base64 encoding of the "data" field's value?

filedeploy commented 1 year ago

You're right, it still gets Base64 encoded. No dice.

bossm8 commented 9 months ago

Thanks to @filedeploy I found an ugly workaround which works at least for environment variables for pods, which we use with generators so that deployments get restarted once the values change (although this probably doesn't work as well for files):

secretGenerator:
  - name: my-secret
    namespace: my-namespace
    literals: []

patches:
  - patch: |-
      - op: move
        from: /data
        path: /stringData
      - op: add
        path: /stringData
        value:
          API_KEY: ${API_KEY}
          SECRET: ${SECRET_KEY}
    target:
      kind: Secret
      name: my-secret

EDIT: Just found out that the secret suffix does not change anymore with this approach, so this is not really a solution either.