Skip to content

Conversation

@gwossum
Copy link
Member

@gwossum gwossum commented Nov 24, 2025

Add TLS certificate reloading on SIGHUP. For httpd service certificates, the configuration is reloaded and certificate and key file locations are updated accordingly. For opentsdb service certificates, certificates and keys at the existing locations are reloaded. If reloading a certificate fails, the currently loaded certificate continues to be used.

Also adds file permission checking for TLS certificates and private keys.

Add TLS certificate reloading on SIGHUP. For httpd service certificates,
the configuration is reloaded and certificate and key file locations are
updated accordingly. For opentsdb service certificates, certificates and
keys at the existing locations are reloaded. If reloading a certificate
fails, the currently loaded certificate continues to be used.

Also adds file permission checking for TLS certificates and private
keys.
Rewrite some tests so that tricks are not used to get a hold of the TLS
certificate in-use. Instead, an HTTP client is used to get the
certificate presented by the http service.
Comment on lines 334 to 337
// VerifyLoad verifies that the certificate at certPath and keyPath will load without error.
// If the certificate can be loaded, a function that will apply the certificate reload is
// returned. Otherwise, an error is returned.
func (cl *TLSCertLoader) VerifyLoad(certPath, keyPath string) (func() error, error) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced VerifyLoad is the best name for this method. The name does make sense, because it is used on config reload to verify that that the new configuration and/or certificate will load properly before it is applied. The name is seems off, though, when you consider that it also returns a closure that will apply the change. Maybe something like PrepareReload would be a better name?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MakeReloadFunc ??

// VerifyReloadTLSCertificate verifies that the configured TLS certificate can be reloaded.
// If so, then a function that will apply the reloaded certificate is returned. If no reload
// action is necessary, then nil is returned for the reload function.
func (s *Service) VerifyReloadTLSCertificate() (func() error, error) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing as CertLoader.VerifyReload. Is this the best name for the method?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MakeTlsCertLoaderFunc??? Just a suggestion.

Copy link
Contributor

@davidby-influx davidby-influx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few suggestions, questions, comments...


cmd.Logger.Info("Signal received, initializing clean shutdown...")
if sig == syscall.SIGTERM && cmd.Server.LogQueriesOnTermination() {
if logQueries && cmd.Server.LogQueriesOnTermination() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the logQueries variable? Is there a case where we get here with a signal on shutdownCh that is not a SIGTERM?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shutdownCh will also get SIGINT (os.Interrupt) signals. We only log the queries on SIGTERM. Changes in the logic now that we are handling SIGHUP were easier (and clearer) by adding logQueries.

pkg/file/file.go Outdated

// VerifyFilePermissivenessF checks if permissions on f are as restrictive
// or more restrictive than maxPerms. if not, then an error is returned.
// For security reasons, there is no VerifyFilePermissiveness functino
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"functino"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed in next commit.


f, err := os.Open(tmpFile)
require.NoError(t, err)
defer f.Close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrap in a require.NoError?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed in next commit.


f, err := os.Open(tmpFile)
require.NoError(t, err)
defer f.Close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

require.NoError?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Next commit.

HTTPSEnabled: false,
}
applyFunc, err := s.VerifyReloadedConfig(newConfig)
require.Error(t, err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This differs from usage elsewhere in this PR. Does require.ErrorContains imply require.Error? Or do you need to add require.Error to the other places?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary require.Error will be removed in next commit.

HTTPSPrivateKey: ss.KeyPath,
}
applyFunc, err := s.VerifyReloadedConfig(newConfig)
require.Error(t, err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in next commit.


// Open service to initialize certLoader
require.NoError(t, s.Open())
defer s.Close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any possible error?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in next commit.


// Open service to initialize certLoader
require.NoError(t, s.Open())
defer s.Close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any possible error?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in next commit.

// VerifyReloadTLSCertificate verifies that the configured TLS certificate can be reloaded.
// If so, then a function that will apply the reloaded certificate is returned. If no reload
// action is necessary, then nil is returned for the reload function.
func (s *Service) VerifyReloadTLSCertificate() (func() error, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MakeTlsCertLoaderFunc??? Just a suggestion.

- Correct race conditions present in httpd.Service.
- Improve error messages.
- Rename some methods for clarity.
- Fix issues in tests.
- Fix comments.
Copy link
Contributor

@davidby-influx davidby-influx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

I like the spelling corrections...

config, err := cmd.ParseConfig(configPath)
if err != nil {
return fail(fmt.Errorf("error parsing config file: %s", err))
return fail(fmt.Errorf("error parsing config file (%q): %s", configPath, err))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet!

if err := cl.setCertificate(loadedCert); err != nil {
// There shouldn't be a way to get here.
log.Error("error setting certificate after load")
log.Error("error setting certificate after load", zap.Error(err))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

@gwossum gwossum merged commit 8c9b850 into master-1.x Dec 23, 2025
9 checks passed
@gwossum gwossum deleted the gw/tls_cert_omnibus branch December 23, 2025 20:29
gwossum added a commit that referenced this pull request Dec 23, 2025
Add TLS certificate reloading on SIGHUP. For httpd service certificates,
the configuration is reloaded and certificate and key file locations are
updated accordingly. For opentsdb service certificates, certificates and
keys at the existing locations are reloaded. If reloading a certificate
fails, the currently loaded certificate continues to be used.

Also adds file permission checking for TLS certificates and private
keys.

Clean cherry-pick of #26994 to 1.12.

Closes: #27056

(cherry picked from commit 8c9b850)
gwossum added a commit that referenced this pull request Dec 23, 2025
Add TLS certificate reloading on SIGHUP. For httpd service certificates,
the configuration is reloaded and certificate and key file locations are
updated accordingly. For opentsdb service certificates, certificates and
keys at the existing locations are reloaded. If reloading a certificate
fails, the currently loaded certificate continues to be used.

Also adds file permission checking for TLS certificates and private
keys.

Clean cherry-pick of #26994 to 1.12.

Closes: #27056

(cherry picked from commit 8c9b850)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants