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
Updating credentials of a running server #7209
Comments
Hi @TalLerner, a possible solution is to implement your own TransportCredentials that delegates to TLS credentials created using one of the available constructors. Your custom TransportCredentials can provide the option to switch the delegate during runtime. An example of such a type DynamicCreds struct {
delegate credentials.TransportCredentials
rwMutex sync.RWMutex
}
func (d *DynamicCreds) ClientHandshake(ctx context.Context, host string, conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
d.rwMutex.RLock()
defer d.rwMutex.RUnlock()
return d.delegate.ClientHandshake(ctx, host, conn)
}
func (d *DynamicCreds) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
d.rwMutex.RLock()
defer d.rwMutex.RUnlock()
return d.delegate.ServerHandshake(conn)
}
func (d *DynamicCreds) Info() credentials.ProtocolInfo {
d.rwMutex.RLock()
defer d.rwMutex.RUnlock()
return d.delegate.Info()
}
func (d *DynamicCreds) Clone() credentials.TransportCredentials {
d.rwMutex.RLock()
defer d.rwMutex.RUnlock()
return NewDynamicCreds(d.delegate.Clone())
}
func (d *DynamicCreds) OverrideServerName(name string) error {
d.rwMutex.RLock()
defer d.rwMutex.RUnlock()
return d.delegate.OverrideServerName(name)
}
func (d *DynamicCreds) UpdateDelegate(newCreds credentials.TransportCredentials) {
d.rwMutex.Lock()
defer d.rwMutex.Unlock()
if newCreds == d {
fmt.Printf("Can't point to self!")
return
}
d.delegate = newCreds
}
func NewDynamicCreds(delegate credentials.TransportCredentials) *DynamicCreds {
return &DynamicCreds{
delegate: delegate,
rwMutex: sync.RWMutex{},
}
} You can then create serverCertFile := data.Path("x509/server_cert.pem")
serverKeyFile := data.Path("x509/server_key.pem")
serverCreds, err := credentials.NewServerTLSFromFile(serverCertFile, serverKeyFile)
if err != nil {
log.Fatalf("Failed to generate credentials: %v", err)
}
dynCreds := NewDynamicCreds(serverCreds)
opts = []grpc.ServerOption{grpc.Creds(dynCreds)}
grpcServer := grpc.NewServer(opts...) When you want to change the delegate, you can call I tried this out in arjan-bal/routeguide@b7b0608 which has a server that switches it's TLS certs every 5 seconds. Let me know if this works for you. |
Another option suggested by @atollena is to create a tls.Config with empty Use this tls.Config to create gRPC transport credentials by calling the constructor. |
This issue is labeled as requiring an update from the reporter, and no update has been received after 6 days. If no update is provided in the next 7 days, this issue will be automatically closed. |
Thank you, Arjan, for your reply!
I am in the process of applying and testing your proposal.
I will update you on the results soon.
Kind Regards,
Tal Lerner
From: Arjan Singh Bal ***@***.***>
Date: Wednesday, 8 May 2024 at 20:41
To: grpc/grpc-go ***@***.***>
Cc: Tal Lerner ***@***.***>, Mention ***@***.***>
Subject: Re: [grpc/grpc-go] Updating credentials of a running server (Issue #7209)
Hi @TalLerner<https://github.com/TalLerner>, a possible solution is to implement your own TransportCredentials<https://pkg.go.dev/google.golang.org/grpc/credentials#TransportCredentials> that delegates to TLS credentials created using one of the available constructors<https://pkg.go.dev/google.golang.org/grpc/credentials#TransportCredentials>. Your custom TransportCredentials can provide the option to switch the delegate during runtime. An example of such a TransportCredentials implementation is as follows:
type DynamicCreds struct {
delegate credentials.TransportCredentials
rwMutex sync.RWMutex
}
func (d *DynamicCreds) ClientHandshake(ctx context.Context, host string, conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
d.rwMutex.RLock()
defer d.rwMutex.RUnlock()
return d.delegate.ClientHandshake(ctx, host, conn)
}
func (d *DynamicCreds) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
d.rwMutex.RLock()
defer d.rwMutex.RUnlock()
return d.delegate.ServerHandshake(conn)
}
func (d *DynamicCreds) Info() credentials.ProtocolInfo {
d.rwMutex.RLock()
defer d.rwMutex.RUnlock()
return d.delegate.Info()
}
func (d *DynamicCreds) Clone() credentials.TransportCredentials {
d.rwMutex.RLock()
defer d.rwMutex.RUnlock()
return NewDynamicCreds(d.delegate.Clone())
}
func (d *DynamicCreds) OverrideServerName(name string) error {
d.rwMutex.RLock()
defer d.rwMutex.RUnlock()
return d.delegate.OverrideServerName(name)
}
func (d *DynamicCreds) UpdateDelegate(newCreds credentials.TransportCredentials) {
d.rwMutex.Lock()
defer d.rwMutex.Unlock()
if newCreds == d {
fmt.Printf("Can't point to self!")
return
}
d.delegate = newCreds
}
func NewDynamicCreds(delegate credentials.TransportCredentials) *DynamicCreds {
return &DynamicCreds{
delegate: delegate,
rwMutex: sync.RWMutex{},
}
}
You can then create DynamicCreds and use them while starting your server as follows:
serverCertFile := data.Path("x509/server_cert.pem")
serverKeyFile := data.Path("x509/server_key.pem")
serverCreds, err := credentials.NewServerTLSFromFile(serverCertFile, serverKeyFile)
if err != nil {
log.Fatalf("Failed to generate credentials: %v", err)
}
dynCreds := NewDynamicCreds(serverCreds)
opts = []grpc.ServerOption{grpc.Creds(dynCreds)}
grpcServer := grpc.NewServer(opts...)
When you want to change the delegate, you can call dynCreds.UpdateDelegate() while passing in the new credentials. This way you gain the ability to change only the transport credentials without updating the server options.
I tried this out in ***@***.***<arjan-bal/routeguide@b7b0608> which has a server that switches it's TLS certs every 5 seconds.
Let me know if this works for you.
—
Reply to this email directly, view it on GitHub<#7209 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AUS3O5TQMHPKNQKQCDXU363ZBJPS5AVCNFSM6AAAAABHLRBKOCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMBRGA4DKMJWGY>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Please see the FAQ in our main README.md before submitting your issue.
Use case(s) - what problem will this feature solve?
When using server certificates, while the server is running new certificates are created. The new certificate must be updated in the server's options. Currently this is not possible without restarting the server and disconnecting the clients.
Proposed Solution
If the options can be updated while the server is running this problem can be resolved.
Alternatives Considered
I didn't find any alternatives. Do you have any suggestions?
Additional Context
The text was updated successfully, but these errors were encountered: