-
Notifications
You must be signed in to change notification settings - Fork 56
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
tls: generate server TLS cert from CA #2401
Conversation
@@ -63,64 +57,6 @@ func GenerateCertificate(hosts []string, caCert *x509.Certificate, caKey crypto. | |||
return PEMEncodeCertificate(certBytes), keyBytes, nil | |||
} | |||
|
|||
func SelfSignedOrLetsEncryptCert(manager *autocert.Manager) func(hello *tls.ClientHelloInfo) (*tls.Certificate, 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 moved this into internal/server/tls.go
and renamed it to getCertificate
. That's the only place it is used.
@@ -146,39 +77,3 @@ func PEMEncodeCertificate(raw []byte) []byte { | |||
func pemEncodePrivateKey(raw []byte) []byte { | |||
return pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: raw}) | |||
} | |||
|
|||
func newCA() (*x509.Certificate, *rsa.PrivateKey, 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.
No longer used, we'll rely on helm or the user to provide 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.
What implications does this have on the initial deploy (ex: quickstart)?
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.
Right, good question. I added another TODO to the list in the description. We need to generate the CA in helm as part of the deploy. That should make it invisible to the user. They won't have to do anything new, but helm will take care of creating the secret which contains the CA and CA private 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.
I've pushed a commit which does this (generates the CA in helm and stores it in a secret)
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 other implication is that the server can no longer be served outside of a helm install, e.g. docker, compose, or local build, unless the CA is manually created and configured. It'll be nice to keep this to support those use cases but not critical
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.
Ya, that's true. We could keep the ability to generate a CA if none is provided for development and demo purposes. I think in practice no real production use case should have the server generate a CA on first install. The operator really needs to save that CA and private key somewhere, and they aren't going to know it exists or where to find it if it was generated on first start.
I'll see about re-adding this for development.
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.
One of the disadvantages to generating the CA by default is that if the user accidentally mis-configured either ca
or caPrivateKey
. For example, maybe they set only one of the two, or they set primaryKey
instead of caPrimaryKey
. With the changes in this PR they will get a nice error and know how to fix it.
If we always generate things for them by default then it won't fail, and they'll have a harder time debugging.
I think it might be better to require these are set ahead of starting the server. For dev maybe we could add a --dev
flag and do some setup in the CLI before starting the server.
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.
Either Helm or infra can exit error if only one of ca
or caPrivateKey
is supplied since both are required. It'll reduce the impact of the scenario you're suggesting. Either way, it can be addressed in a future change
@@ -299,63 +299,6 @@ type routine struct { | |||
stop func() | |||
} | |||
|
|||
func tlsConfigFromOptions( |
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.
Moved to internal/server/tls.go
} | ||
|
||
func getCertificate(cache autocert.Cache, opts TLSOptions) func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { | ||
var lock sync.RWMutex |
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 lock should fix #2067
83bd672
to
50d1125
Compare
871965b
to
cb26d63
Compare
if err := manager.Cache.Put(ctx, serverName+".crt", certBytes); err != nil { | ||
return nil, err | ||
} | ||
hosts := []string{"127.0.0.1", "::1", serverName} |
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 changed this to always include localhost in the list of valid IP SANs since it's common for a cert to be used on localhost as well.
cb26d63
to
b7b5ecd
Compare
b7b5ecd
to
e10b58f
Compare
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 PR should be ready for review now
@@ -26,21 +23,47 @@ func tlsConfigFromOptions( | |||
tlsCacheDir string, | |||
opts TLSOptions, | |||
) (*tls.Config, error) { | |||
// TODO: print CA fingerprint when the client can trust that fingerprint | |||
// TODO: how can we test this? |
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.
Not really sure how to test the ACME integration, but it wasn't tested before and it's still not documented as a supported feature, so probably not a requirement for this PR.
{{- get $secret.data "ca.key" | b64dec | nindent 4 }} | ||
|
||
{{- else }} | ||
{{- $ca := genCA "Infra Server" 3650 }} |
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 is the name people will see in the Subject line of the certificate. Should we use "Infra" , or "Infra Server" ?
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.
"Infra Server" seems fine to me 👍
These function will be modified in the next commit. Moving them now so that changes are more obvious.
2a51a80
to
8d63f54
Compare
@@ -36,6 +36,12 @@ data: | |||
{{- end }} | |||
{{- end }} | |||
|
|||
{{- if (not .Values.server.config.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.
Don't need parenthesis around the not
@@ -146,39 +77,3 @@ func PEMEncodeCertificate(raw []byte) []byte { | |||
func pemEncodePrivateKey(raw []byte) []byte { | |||
return pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: raw}) | |||
} | |||
|
|||
func newCA() (*x509.Certificate, *rsa.PrivateKey, 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.
The other implication is that the server can no longer be served outside of a helm install, e.g. docker, compose, or local build, unless the CA is manually created and configured. It'll be nice to keep this to support those use cases but not critical
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.
looks reasonable. no concerns at this point
With this commit, a user has 3 options for configuring TLS: 1. set tls.ACME=true, to use ACME to create a publicly trusted certificate 2. set tls.ca and tls.caPrivateKey, which will be used to generate a TLS ceritifcate for any hostname the client requests 3. set tls.certificate and tls.privateKey to use that certificate for TLS
The certificate is specified from opts instead of populating the cache.
8d63f54
to
4dc9598
Compare
Summary
The first commit moves some functions to
tls.go
, so best viewed by individual commit.With the changes in this PR, a user has 3 options for configuring TLS:
tls.ACME=true
, to use ACME to create a publicly trusted certificatetls.ca
andtls.caPrivateKey
, which will be used to generate a TLS ceritifcate for any hostname the client requests.tls.certificate
andtls.privateKey
to use that certificate for TLSWe plan on setting a CA as part of the helm deploy, so the default for any user that uses our helm charts will be to specify nothing and use option 2.
ACME is no longer the default option. It has to be explicitly enabled, which is probably better because currently every single TLS request could make an ACME API request, even when it should never be used.
Resolves #2067
And addresses parts 1 and 2 of #2362
TODO: