I cannot seem to generate grpc-server certificates using "golang.org/x/crypto/acme/autocert" with the "tls-alpn-01" challenge type. The reason is most likely just grpc-go overwriting my supplied NextProtocols-list here: https://github.com/grpc/grpc-go/blob/master/credentials/credentials.go#L214.
Can we do something about this?
master
go version)?1.12 darwin/amd64
MacOSX
manager = &autocert.Manager{
Prompt: autocert.AcceptTOS,
Cache: autocert.DirCache(cacheDir),
HostPolicy: autocert.HostWhitelist(domains...),
Email: email,
}
opts = append(opts, grpc.Creds(credentials.NewTLS(manager.TLSConfig())))
Certificates being created as expected.
Nothing. No new certificate. Challenge type tls-alpn-01 cannot work if the "acme-tls/1" protocol isn't available. Overridden here: https://github.com/grpc/grpc-go/blob/master/credentials/credentials.go#L214
I have a tentative fix in #2744. Please take a look and give it a try. Thanks!
I answered in the pull request:
I can confirm that this solves my problem in issue #2729 . It neatly block requests from a grpc client while it creates the certificate in the background and as soon as it is ready it completes the request. This works flawlessly with only port 443 opened.
Based on a discussion this morning, I'm a little concerned we may not have solved this correctly, and that the right solution is to have a custom handshaker if Let's Encrypt is needed. @menghanl is going to look into this more.
@kristoiv could you elaborate on how you made this work?. I Have only managed to make this work partially and wondering if it's me or this is not really working for gRPC.
My gRPC service is on port 50051 while at the same time I listen on 443 for HTTPs request for the challenge. The code looks roughly like this.
manager := autocert.Manager{
Prompt: autocert.AcceptTOS,
Cache: autocert.DirCache("golang-autocert"),
HostPolicy: autocert.HostWhitelist("test.nleiva.com"),
}
opts = grpc.Creds(credentials.NewTLS(manager.TLSConfig()))
s := grpc.NewServer(opts...)
// ... register gRPC services ...
go http.Serve(autocert.NewListener("test.nleiva.com"), newMux())
lis, _ := net.Listen("tcp", ":50051")
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
I see I got the certs, in fact I can serve HTTPs in port 443 with them (https://test.nleiva.com works).
~/.cache$ sudo ls -la golang-autocert/
total 16
drwx------ 2 root root 4096 Jul 3 14:43 .
drwx------ 4 ubuntu ubuntu 4096 Jul 3 14:41 ..
-rw------- 1 root root 227 Jul 3 14:43 acme_account+key
-rw------- 1 root root 3509 Jul 3 14:43 test.nleiva.com
However, when I try to reach the gRPC services at 50051 it fails:
2019/07/03 14:52:12 http: TLS handshake error from [2600:3000:1511:200::1d]:52584: acme/autocert: no token cert for "test.nleiva.com"
2019/07/03 14:52:12 http: TLS handshake error from 64.78.149.164:41708: acme/autocert: no token cert for "test.nleiva.com"
EDIT: Interestingly enough, this works just fine if both the HTTPs and gRPC servers listen on the same port 443.
@nleiva I only tested with everything on 443, the thinking being that I would want everything on a single port.
I wanted to chime in, as a Let's Encrypt engineer, to mention that for gRPC applications, Let's Encrypt (or any other publicly trusted CA) is usually not the right choice. It's generally better to use an internal CA. That doesn't have to be complicated - you can make one in ten minutes with minica.
Using a public CA makes sense when you need a lot of unrelated clients to trust your service without any prior manual configuration - for instance, browsers visiting a web site. For most RPC clients, there's a fair amount of configuration going into their TLS setup, so it makes sense to configure your clients to use an internal CA, and get the benefits (simplicity, tighter security scope).
I don't see any problems with this particular approach, or with making gRPC compatible with tls-alpn-01, but wanted to leave this comment here for future visitors looking for information on how to configure TLS for their gRPC.
This issue is labeled as requiring an update from the reporter, and no update has been received after 7 days. If no update is provided in the next 7 days, this issue will be automatically closed.
@kristoiv could you elaborate on how you made this work?. I Have only managed to make this work partially and wondering if it's me or this is not really working for gRPC.
@nleiva It may be required to be on the same port, not sure. But I notice that in your code you do not actually serve port 443 with your manager but instead a generic one returned by NewListener(). That will create a generic manager for itself with a different cache directory etc. So this would probably never work?
You are correct @kristoiv. I documented the final version of my test code here, using manager.Listener() instead.
func grpcHandlerFunc(g *grpc.Server, h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ct := r.Header.Get("Content-Type")
if r.ProtoMajor == 2 && strings.Contains(ct, "application/grpc") {
g.ServeHTTP(w, r)
} else {
h.ServeHTTP(w, r)
}
})
}
...
// Listener
lis = manager.Listener()
if err = http.Serve(lis, grpcHandlerFunc(s, httpsHandler())); err != nil {
log.Fatalf("failed to serve: %v", err))
}
Most helpful comment
I wanted to chime in, as a Let's Encrypt engineer, to mention that for gRPC applications, Let's Encrypt (or any other publicly trusted CA) is usually not the right choice. It's generally better to use an internal CA. That doesn't have to be complicated - you can make one in ten minutes with minica.
Using a public CA makes sense when you need a lot of unrelated clients to trust your service without any prior manual configuration - for instance, browsers visiting a web site. For most RPC clients, there's a fair amount of configuration going into their TLS setup, so it makes sense to configure your clients to use an internal CA, and get the benefits (simplicity, tighter security scope).
I don't see any problems with this particular approach, or with making gRPC compatible with tls-alpn-01, but wanted to leave this comment here for future visitors looking for information on how to configure TLS for their gRPC.