-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
introduce SecretTemplate to allow to "shape" secrets #54
Comments
We're interested in helping with this feature and putting together a PR. However along with the use cases above we also have the following additional usecases:
So this SecretTemplate would become more flexible to support a wider range of inputs. Based on the combination of these requirements we have sketched out what a resource could look like. This Resource allows arbitrary input resources and allows either jsonpath or ytt style templating. ---
apiVersion: secretgen.k14s.io/v1alpha1
kind: SecretTemplate
metadata:
name: generated-secret
spec:
# ServiceAccount whose identity is used to `get` inputResources. This would only
# require the RBAC to get a resource and its status. Other RBAC necessary for this
# controller but not associated with the input resources will be supplied a-priori to
# the controller e.g. the RBAC necessary to create and update the templated Secret.
serviceAccountName: my-resource-reader
# An array of resources which have values on their API pertinent to creation of the
# final Secret.
inputResources:
# The name of the key used to refer to this input resource in other jsonpath syntax
# occurrences seen in a) other input resources in this array or b) in the Secret
# .spec.template.
- name: rds
ref:
apiVersion: rds.services.k8s.aws/v1alpha1
kind: DBInstance
# Possibly optional if selector is present.
name: my-rds-instance
# Optional. Possible extension. Allows reading of resources across namespaces.
# May have repercussions due to SecretTemplate creator being able to read arbitrary
# resources across all namespaces, but this is mitigated if we ensure that the
# reading of input resources uses .spec.serviceAccountName’s permissions.
namespace: rds-services
# Optional. Possible extension. Allows resource selection via Labels (or
# fields), will fail if the number of matches != 1.
selector:
matchLabels:
type: ha
- name: creds
ref:
apiVersion: v1
kind: Secret
# Possible extension. The name of a input resource could be provided via the value
# of a path on another resource. Allowing acyclic graphs of resource dependencies
# to be expressed. Cyclic references e.g. rds -> creds -> rds would be prevented
# or recognised and causing an error. A suggested way is to require that any
# referenced input resource must precede the current input resource. That way it's
# impossible to create cycles and the logical flow is also more clear.
name: {.rds.masterPassword.name}
namespace: rds-services
# Secret template for the Secret this CR will create. Optional, either template OR ytt must be defined.
template:
# Possible extension. Metadata exposed to allow the templating in of the name of the
# Secret. This would also allow the exposure of label/annotation setting which could
# be useful when specifying Secrets as claimable.
metadata:
name: db-instance-secret
labels:
services-type: aws-rds
# Use jsonpath syntax for referencing values on the input resources, otherwise it is
# static.
stringData:
type: postgresql
port: {.rds.status.endpoint.port}
database: {.rds.spec.dbName}
host: {.rds.status.endpoint.address}
username: {.rds.spec.masterUsername}
# Data would be used to set base64 encoded data.
data:
password: {.creds.data.password}
# Possible extension, allows the templating
# of a Secret using ytt. Optional either template OR ytt must be defined. Would enable more complex use cases such as: dynamic loading
# of keys from another resource (to access in a Secret), defaulting, and assertions.
ytt: |
#@ load("@ytt:data", "data")
# Store the input resource as data values with the key being
# the specified reference name.
#@ rds = data.values.rds
#@ creds = data.values.creds
#@ endpoint = rds.status.endpoint
metadata:
name: db-instance-secret
stringData:
type: postgresql
database: #@ rds.spec.dbName
port: #@ endpoint.port
host: #@ endpoint.address
# Example of defaulting.
username: #@ rds.spec.masterUsername if rds.spec.masterUsername != "" else "admin"
data:
# Example of dynamic key loading.
password: #@ creds.data[rds.masterUserPassword.get("key")]
status:
createdSecret:
name: db-instance-secret
conditions:
# All input resources exist
- lastTransitionTime: 2019-10-22T16:29:24Z
status: True
type: InputResourcesFound
# Templating has succeeded
- lastTransitionTime: 2019-10-22T16:29:24Z
status: True
type: TemplateSucceeded
# The Secret is created with templated values
- lastTransitionTime: 2019-10-22T16:30:24Z
status: True
type: SecretCreated
- lastTransitionTime: 2019-10-22T16:31:24Z
status: True
type: Ready Some thoughts/questions we still have:
Future enhancements:
If folks are generally happy with the approach we will start working on a PR. |
i would recommend going with more "familiar" syntax of
for simplicitly sake i would favor name that matches name of the SecretTemplate. what are use cases where generated secret needs to have a different name from the template cr?
my gut feeling says no since it would be reconciled with changes over time.
adding ytt support should be fairly trivial (probably would want to do a quick follow). we have done this in a few places within carvel tools themselves. feel free to file a PR just with jsonpath support.
for general secretgen users majority of use cases would be covered by "without service account". for more advanced cases you have, we would definitely need "service account" support. i think we should follow the same methodology as with jsonpath (+ ytt for advanced). no-service-account for general use, with-service-account for advanced cases.
sounds good.
any example to share for this? i could see how it might be useful, but cant think of a concrete example ive seen out there. |
@Samze - Knowing the more specific use case you/we have in mind for
|
Thanks for the input @cppforlife / @st3v .
Yeah makes sense. Will update.
I think this is linked with the decision on whether this should produce immutable secrets with For our use case we care about the secret being immutable so that when injected into a pod through something like https://github.com/k8s-service-bindings/spec and the secret is updated, the pod remounts a new secret to pick up the new details. If the secret is just updated in place then it is down to the application to "hot reload" the secrets contents. Thinking about this more I'm not sure this is right place to handle immutability. In this case since we are reading dynamic input sources we must to handle updates. So there seem to be three strategies:
Both options 2 and 3 seem a strange usecase for immutable secrets since we're not keeping the old secret around - we're effectively doing an update. So beyond our usecase that I described above I'm not sure there is any practical advantage of immutability here. For us, perhaps we should address the immutability issue elsewhere in the stack. Thoughts @st3v @gmrodgers ?
This could be an option, have an
We don't have any concrete usecases for this today but I think it makes sense to design the inputResource block with the possibility of defining a
Ah yeah, I knew I missed an open question! This is up for discussion. I think if we decide to make the secret name dynamic (e.g. it is immutable or allow the user to configure the name) then having However, if the name is known (e.g. the same as the SecretTemplate) and the secret is updated in place, then we can just refer to it via a Direct Secret Reference. |
It seems like there are some outstanding details to be figured out but the agreement on the general approach so unless there are any strong objections we will start work on a PR. |
Thanks for the writeup @Samze!
I think we should consider only supporting a subset of the jsonpath syntax. That subset may not include the () option and therefore the need for a closing )$ is mitigated. Service Bindings went down this path, see Fixed JSONPath.
For me, I think the Secret immutability is a forcing function for us changing the Secret name on an update. Immutability is not necessary for us to do it! We could just delete a mutable Secret and create a new one with a different name.
We could possibly enable rotation of Secret name here as well as a static name. If name is specified in .spec.template it is always used, else a name is generated and the status updated each time. From first glance, it would look like that either the Applications consuming Secrets would have to know to check for Secret contents updates or every link in the Secret chain (Password then this SecretTemplate then maybe SecretImportExport) would have to support transmitting updates to the Secret.
I think, as you implied, we can move ahead with an agnostic .status.createdSecret.name for now and then make an additive .status.binding.name later if we decide it is appropriate! |
Describe the problem/challenge you have
Use cases:
Describe the solution you'd like
introduce SecretTemplate CR that is able to read one or more secrets and produce another secret.
for example:
TBD:
Anything else you would like to add:
[Additional information that will assist in solving the issue.]
Vote on this request
This is an invitation to the community to vote on issues, to help us prioritize our backlog. Use the "smiley face" up to the right of this comment to vote.
👍 "I would like to see this addressed as soon as possible"
👎 "There are other more important things to focus on right now"
We are also happy to receive and review Pull Requests if you would like to work on this issue.
The text was updated successfully, but these errors were encountered: