-
Notifications
You must be signed in to change notification settings - Fork 1.8k
pkg/util: add interface for tls util #374
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
pkg/util: add interface for tls util #374
Conversation
0e9b1f3
to
eb32a91
Compare
cc/ @hasbro17 @rithujohn191 PTAL. |
pkg/util/tlsutil/tls.go
Outdated
// Optional CAKey, if user wants to provide custom CA key path. | ||
CAKey string | ||
// Optional CA Certificate, if user wants to provide custom CA cert path. | ||
CACert string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per offline discussion we can have the users specify a CAKeySecretName and CACertConfigmapName that's easier to consume for the operator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a concern that not all CAs are stored in this way. I would think a way to support multiple options by passing in the cert/key via path strings, and the user of the Operator would set up the mounts on the operator deployment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shawn-hurley I would think a way to support multiple options by passing in the cert/key via path strings
.
Do you have a use case that prefers using cert file path on the operator pod over simply retrieving it via secret or ConfigMap. My initial philosophy on designing the operator util is the operator usually deals with Kubernete objects such as Pod, Deployment, Service, and so forth. Then it makes a lot of sense that the tls utility also returns Secret and Configmap so that the operator can just simply consume them without need for converting an external object into to a kubernete object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Offline Comments:
I could also see that someone does not store the ca cert and specifically the key in the cluster and instead uses some other type of volume to store those values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Offline comments:
Could also see that someone does not store the ca cert and specifically the key in the cluster and instead uses some other type of volume to store those values ie. NFS, aws, or azure for presistant storage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hasbro17 I agree with @shawn-hurley on making passing-in CA key and cert a bit more generic instead of forcing user to pass those in as secret/configmap. Suppose that the user mounts a aws volume that contain sensitive CA key, the user might not want to expose the key as secret into the kubernete cluster but simply want to use it to sign the private key and cert. Let me know what you think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Using a secret and configmap would restrict users from accessing the CA through a mounted volume.
Let's just keep CAKey and CACert as mounted filepaths then.
pkg/util/tlsutil/tls.go
Outdated
// namespace: <cr-namespace> | ||
// data: | ||
// ca.key: .. | ||
CACert(cr runtime.Object) (*v1.ConfigMap, *v1.Secret, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove this and change the GenerateCert signature to return the CACert(configmap) and CAKey(secret) for that client/server cert. That's more explicit than the users calling CACert() themselves.
GenerateCert(cr runtime.Object, service *v1.Service, config *CertConfig) (*v1.Secret, v1.ConfigMap, v1.Secret, error)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be better to pass the actual TLS values: key *rsa.PrivateKey, caCert *x509.Certificate This will allow the user to have multiple ways of storing the custom CA per comment above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shawn-hurley CACert()
function is going to be removed. The GenerateCert
is going to return the CA instead.
I think it might be better to pass the actual TLS values
. I have thought about this too and decided it is a bit too low level. I suspect operator developer doesn't really want to dealt with rsa
key and cert. They might simply want a secret that containing the right encryption key and cert to construct their deployment manifest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had some concerns about the being too prescriptive on how a custom CA is stored, thoughts?
pkg/util/tlsutil/tls.go
Outdated
// Optional CAKey, if user wants to provide custom CA key path. | ||
CAKey string | ||
// Optional CA Certificate, if user wants to provide custom CA cert path. | ||
CACert string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a concern that not all CAs are stored in this way. I would think a way to support multiple options by passing in the cert/key via path strings, and the user of the Operator would set up the mounts on the operator deployment?
pkg/util/tlsutil/tls.go
Outdated
// namespace: <cr-namespace> | ||
// data: | ||
// ca.key: .. | ||
CACert(cr runtime.Object) (*v1.ConfigMap, *v1.Secret, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be better to pass the actual TLS values: key *rsa.PrivateKey, caCert *x509.Certificate This will allow the user to have multiple ways of storing the custom CA per comment above.
50321eb
to
553ba2f
Compare
PTAL cc/ @hasbro17 @shawn-hurley |
@fanminshi Just too make sure I am following this, if a custom CA is set, then we create a secret and config map object to return to the user. But we do not create those objects in the cluster? If that is true then LGTM |
@shawn-hurley that's correct! |
pkg/tlsutil/tls.go
Outdated
// | ||
// The passed in "service" represents endpoint(s) of a communicating party. We assume that the | ||
// deployed applications are typically communicated via the Kubernete Service. Therefore, the | ||
// cert is generated to certify the endpoint(s) defined by the "service". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// The passed in "service" represents endpoint(s) of a communicating party. We assume that the
// deployed applications are typically communicated via the Kubernete Service. Therefore, the
// cert is generated to certify the endpoint(s) defined by the "service".
We need to make clearly explain exactly what the Service is being used for.
If I'm not wrong then all we're expecting to do with the passed in Service object is to use it's name and namespace to set the certificate's SAN(DNSName) to the Service FQDN name.namespace.svc.cluster.local
certTmpl := x509.Certificate{
...
DNSNames: []string{fmt.Sprintf("%s.%s.svc.cluster.local", service.Name, service.Namespace)},
...
}
So change this to something like:
// The passed in "service" is used to set the Subject Alternative Names(SAN) for the certificate.
// We assume that the deployed applications are typically communicated with via a Kubernetes Service.
// The SAN is set to the FQDN of the service `<service-name>.<service-namespace>.svc.cluster.local`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, i should make it a bit more explicit.
pkg/tlsutil/tls.go
Outdated
CACert string | ||
} | ||
|
||
// CertGenerator is an operator specific TLS tool that generates TLS assets for the deploying application. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we reword the end of the sentence to for deploying a user application
, since we have not talked about the application anywhere before this.
pkg/tlsutil/tls.go
Outdated
// cert is generated to certify the endpoint(s) defined by the "service". | ||
// | ||
// If CA is not passed in via CertConfig, GenerateCert creates a unique self signed CA | ||
// corresponding to the "cr" for signing the TLS cert and also puts the self signed CA and TLS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sentence is a little vague "and also puts the self signed CA and TLS key and into the Kubernetes cluster". Can we be a little more specific of where it is located or how the user can access it if need be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, i am reworking on it to make it more clear.
pkg/tlsutil/tls.go
Outdated
// key and Certs into the Kubernetes cluster before returning. | ||
// If CA is passed in, GenerateCert use it for signing the TLS cert but | ||
// only puts TLS key and cert into the cluster not the passed in CA; the user has to | ||
// figure out what to do with the returned CA object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when you say "the user has to figure out what to do with the CA object" do you mean they can re-store it where they like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kinda of. since when you pass-in the CA, we return a CA configmap and secret back to you. However, we are not going to puts them into the kubernetes. It is the user's job to figure out whether to put them into kubernete or not.
27dc460
to
97b68ef
Compare
Modify the comments for the interface. PTAL cc/ @hasbro17 @rithujohn191 |
pkg/tlsutil/tls.go
Outdated
// - CA's key is packaged into a Secret as shown below. | ||
// - CA's cert is packaged in a ConfigMap as shown below. | ||
// - The CA Secret and ConfigMap are then put into the Cluster before returning then to | ||
// the user. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slight rephrasing to make it clear exactly where they would be created:
The CA Secret and ConfigMap are created on the k8s cluster in the CR's namespace and returned to the user.
pkg/tlsutil/tls.go
Outdated
// - The CA Secret and ConfigMap are returned to the user without putting them into the | ||
// cluster; the reason behind this is that we don't know how to manage the passed in | ||
// CA. Hence, we simply return them as in Kubernetes Objects, and let the user decides | ||
// what to do such as whether to put them into kubernte or not. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about something a little shorter:
The CA Secret and Configmap are returned but not created on the k8s cluster. The operator does not manage the user specified CA.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can, but i think we should still add a why component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright how about:
// The CA Secret and Configmap are returned but not created on the k8s cluster.
// The operator does not manage the CA because the user controls the lifecycle of the CA.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean that CertGenerator does not manage
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah the CertGenerator is more specific. Even though it is part of the operator.
pkg/tlsutil/tls.go
Outdated
// what to do such as whether to put them into kubernte or not. | ||
// | ||
// TLS Key and Cert Creation and Management: | ||
// - A unique TLS key is generated per CR + CertConfig.CertName. For instance, calling |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you meant A unique TLS cert and key
. Since both are unique to a CR. Not just the key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, that's right.
e2d5068
to
fe5eb4f
Compare
@hasbro17 I add few sentences to stress the point that the CertGenerator manages CA and secret. Let me know what you think. |
pkg/tlsutil/tls.go
Outdated
// | ||
// TLS Key and Cert Creation and Management: | ||
// - A unique TLS cert and key pair is generated per CR + CertConfig.CertName. | ||
// - We use the CA determined from the above to generate and to sign the cert of the TLS key. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the CA is always used(user specified or newly generated) how about we make this more concise:
The CA is used to generate and sign the TLS cert.
Either that or reword CA determined from the above
since it doesn't quite sound right to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, not a problem. I was just trying to be more specific on where the CA is from.
LGTM after nit. |
fe5eb4f
to
4609807
Compare
// - If CA is given: | ||
// - CA's key is packaged into a Secret as shown below. | ||
// - CA's cert is packaged in a ConfigMap as shown below. | ||
// - The CA Secret and ConfigMap are returned but not created in the K8s cluster in the CR's |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this might be a silly question, but did we consider that these returns are nil?
I think that it would be less confusing for a user if they just didn't get those return values?
Also with 4 return values should we consider a wrapper struct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this might be a silly question, but did we consider that these returns are nil?
I have not considered return it as nil because I think it is still quite useful to return the CA Secret and ConfigMap. For instance, I might want to mount the CA Cert ConfigMap to a pod so that we can use that to verify the cert that was generated from this CA. If we just simply return nil, the user has to somehow transfer the passed in cert to the designated pod.
Also with 4 return values should we consider a wrapper struct?
I think the 4 values returned is fine for now; it is still quite clear on what's is returning. If we decided to add more return values, we might want to have a wrapper struct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might want to mount the CA Cert ConfigMap to a pod so that we can use that to verify the cert that was generated from this CA
Sorry, I am little confused, if the ConfigMap is not created in the cluster because the CA was a custom CA, then this would fail right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shawn-hurley If the CA is a custom CA passed in via CertConfig then GenerateCert()
will only package the CA cert up as a Configmap and return that object, but not actually create it on the cluster. So it wouldn't really fail in that case.
In the custom CA case it's up to the users whether or not they should create the CA Configmap and Secret returned by GenerateCert()
since the operator does not mange the lifecycle of the CA.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
…e-ansible-collections OCPBUGS-30095: Bump kubernetes.core to v2.4.2
Add interface and config definition for the tls util.
ref design: #371