Skip to content
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

[HTTP Server] support TLS config hot reload via SIGHUP #171823

Merged
merged 9 commits into from
Nov 24, 2023

Conversation

pgayvallet
Copy link
Contributor

@pgayvallet pgayvallet commented Nov 23, 2023

Summary

Fix #54368

Add support for hot reloading the Kibana server's TLS configuration, using the same SIGHUP-based reload signal, as already implemented for other parts of the Kibana configuration (e.g logging)

Note:

  • hot reloading is only supported for the server TLS configuration (server.ssl), not for the whole server.* config prefix
  • swaping the certificate files (without modifying the kibana config itself) is supported
  • it is not possible to toggle TLS (enabling or disabling) without restarting Kibana
  • hot reloading requires to force the process to reload its configuration by sending a SIGHUP signal

Example / how to test

Before

server.ssl.enabled: true
server.ssl.certificate: /path-to-kibana/packages/kbn-dev-utils/certs/kibana.crt
server.ssl.key: /path-to-kibana/packages/kbn-dev-utils/certs/kibana.key
Screenshot 2023-11-23 at 15 11 28

Changing the config

server.ssl.enabled: true
server.ssl.certificate: /path-to-kibana/packages/kbn-dev-utils/certs/elasticsearch.crt
server.ssl.key: /path-to-kibana/packages/kbn-dev-utils/certs/elasticsearch.key
kill -SIGHUP {KIBANA_PID}
Screenshot 2023-11-23 at 15 18 21

After

Screenshot 2023-11-23 at 15 18 43

Release notes

It is now possible to hot reload Kibana's TLS (server.ssl) configuration by updating it and then sending a SIGHUP signal to the Kibana process.

Note that TLS cannot be toggled (disabled/enabled) that way, and that hot reload only works for the TLS configuration, not other properties of the server config prefix.

@pgayvallet pgayvallet changed the title create base test against raw HAPI server [HTTP Server] support TLS config hot reload via SIGHUP Nov 23, 2023
@pgayvallet pgayvallet added release_note:enhancement Feature:http Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc v8.12.0 labels Nov 23, 2023
Copy link
Contributor Author

@pgayvallet pgayvallet left a comment

Choose a reason for hiding this comment

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

Self-review

Comment on lines +240 to +261
// only hot-reloading TLS config - don't need to subscribe if TLS is initially disabled,
// given we can't hot-switch from/to enabled/disabled.
if (config.ssl.enabled) {
const configSubscription = config$
.pipe(pairwise())
.subscribe(([{ ssl: prevSslConfig }, { ssl: newSslConfig }]) => {
if (prevSslConfig.enabled !== newSslConfig.enabled) {
this.log.warn(
'Incompatible TLS config change detected - TLS cannot be toggled without a full server reboot.'
);
return;
}

const sameConfig = newSslConfig.isEqualTo(prevSslConfig);

if (!sameConfig) {
this.log.info('TLS configuration change detected - reloading TLS configuration.');
setTlsConfig(this.server!, newSslConfig);
}
});
this.subscriptions.push(configSubscription);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The main addition / entry point of the PR. The HTTP server now has access to the config observable (instead of the config object) and listen to changes to check if the SSL config was updated. If so, we propagate the changes to the underlying tls server

Comment on lines +15 to +17
function isServerTLS(server: HttpServer): server is TlsServer {
return 'setSecureContext' in server;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

NIT: I could probably have used server instanceof TlsServer instead, but tbh this works and is easier to stub for testing.

Comment on lines +166 to +171
public isEqualTo(otherConfig: SslConfig) {
if (this === otherConfig) {
return true;
}
return isEqual(this, otherConfig);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Had to implement a comparison func on the SslConfig class. Wasn't strictly necessary, but it allows to know when the SSL config really changed to avoid propagating the changes on every SIGHUP (and also to have better logging given we only output an info message when the config really changed)

Comment on lines +25 to +27
describe('setTlsConfig', () => {
const CSP_CONFIG = cspConfig.schema.validate({});
const EXTERNAL_URL_CONFIG = externalUrlConfig.schema.validate({});
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Integration test against a vanilla HAPI server

Comment on lines +28 to +30
describe('HttpServer - TLS config', () => {
let server: HttpServer;
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Integration test against our HttpServer.

@pgayvallet pgayvallet marked this pull request as ready for review November 23, 2023 20:33
@pgayvallet pgayvallet requested a review from a team as a code owner November 23, 2023 20:33
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-core (Team:Core)

@pgayvallet pgayvallet added the backport:prev-minor Backport to (8.x) the previous minor version (i.e. one version back from main) label Nov 23, 2023
@kibana-ci
Copy link
Collaborator

💚 Build Succeeded

Metrics [docs]

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
@kbn/core-http-server-internal 53 52 -1
@kbn/server-http-tools 51 57 +6
total +5

Public APIs missing exports

Total count of every type that is part of your API that should be exported but is not. This will cause broken links in the API documentation system. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats exports for more detailed information.

id before after diff
@kbn/core-http-server-internal 8 9 +1
Unknown metric groups

API count

id before after diff
@kbn/core-http-server-internal 59 58 -1
@kbn/server-http-tools 54 61 +7
total +6

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

Copy link
Contributor

@TinaHeiligers TinaHeiligers left a comment

Choose a reason for hiding this comment

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

I pulle and ran the code and it works as intended. The implementation looks fine too.

One question that came to mind is making the change to SSL more noticeable. ATM, the info logs might get lost in a sea of debug logs. If we changed logging to warn on SSL certs updates, it might be more prevalent.

.pipe(pairwise())
.subscribe(([{ ssl: prevSslConfig }, { ssl: newSslConfig }]) => {
if (prevSslConfig.enabled !== newSslConfig.enabled) {
this.log.warn(
Copy link
Contributor

Choose a reason for hiding this comment

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

If someone's debugging why an update to their certs "isn't working", they might be tempted to enable debug logging. Warning logs can get lost in those.

I wonder if we shouldn't make the warning more prominent 🤔

const sameConfig = newSslConfig.isEqualTo(prevSslConfig);

if (!sameConfig) {
this.log.info('TLS configuration change detected - reloading TLS configuration.');
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should also be a warning log: If someone's intentionally making a change/update they'll know to ignore the log line. If, however, something's gone wrong and we're using logs to figure out what happened, we'd be less likely to ignore a warning log entry than an info-level one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The whole SIGHUP reload chain's logging is INFO based (which is the correct level ihmo, it's informative), so I think I'd rather keep that consistent.

return this.config$.pipe(
map((config) => config.get(path)),
distinctUntilChanged(isEqual),
ignoreUnchanged ? distinctUntilChanged(isEqual) : identity,
Copy link
Contributor

Choose a reason for hiding this comment

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

you made me look identity up 😉

@pgayvallet pgayvallet merged commit 87213e7 into elastic:main Nov 24, 2023
28 checks passed
@kibanamachine
Copy link
Contributor

💔 All backports failed

Status Branch Result
8.11 Backport failed because of merge conflicts

Manual backport

To create the backport manually run:

node scripts/backport --pr 171823

Questions ?

Please refer to the Backport tool documentation

pgayvallet added a commit to pgayvallet/kibana that referenced this pull request Nov 24, 2023
)

## Summary

Fix elastic#54368

Add support for hot reloading the Kibana server's TLS configuration,
using the same `SIGHUP`-based reload signal, as already implemented for
other parts of the Kibana configuration (e.g `logging`)

**Note:**
- hot reloading is only supported for the server TLS configuration
(`server.ssl`), not for the whole `server.*` config prefix
- swaping the certificate files (without modifying the kibana config
itself) is supported
- it is not possible to toggle TLS (enabling or disabling) without
restarting Kibana
- hot reloading requires to force the process to reload its
configuration by sending a `SIGHUP` signal

### Example / how to test

#### Before

```yaml
server.ssl.enabled: true
server.ssl.certificate: /path-to-kibana/packages/kbn-dev-utils/certs/kibana.crt
server.ssl.key: /path-to-kibana/packages/kbn-dev-utils/certs/kibana.key
```

<img width="550" alt="Screenshot 2023-11-23 at 15 11 28"
src="https://github.com/elastic/kibana/assets/1532934/1226d161-a9f2-4d62-a3de-37161829f187">

#### Changing the config

```yaml
server.ssl.enabled: true
server.ssl.certificate: /path-to-kibana/packages/kbn-dev-utils/certs/elasticsearch.crt
server.ssl.key: /path-to-kibana/packages/kbn-dev-utils/certs/elasticsearch.key
```

```bash
kill -SIGHUP {KIBANA_PID}
```

<img width="865" alt="Screenshot 2023-11-23 at 15 18 21"
src="https://github.com/elastic/kibana/assets/1532934/c9412b2e-d70e-4cf0-8eaf-4db70a45af60">

#### After

<img width="547" alt="Screenshot 2023-11-23 at 15 18 43"
src="https://github.com/elastic/kibana/assets/1532934/c839f04f-4adb-456d-a174-4f0ebd5c234c">

## Release notes

It is now possible to hot reload Kibana's TLS (`server.ssl`)
configuration by updating it and then sending a `SIGHUP` signal to the
Kibana process.

Note that TLS cannot be toggled (disabled/enabled) that way, and that
hot reload only works for the TLS configuration, not other properties of
the `server` config prefix.

---------

Co-authored-by: kibanamachine <[email protected]>
(cherry picked from commit 87213e7)

# Conflicts:
#	src/core/tsconfig.json
@pgayvallet
Copy link
Contributor Author

💚 All backports created successfully

Status Branch Result
8.11

Note: Successful backport PRs will be merged automatically after passing CI.

Questions ?

Please refer to the Backport tool documentation

kibanamachine pushed a commit to kibanamachine/kibana that referenced this pull request Nov 24, 2023
…tic#171823) (elastic#171907)

# Backport

This will backport the following commits from `main` to `8.11`:
- [[HTTP Server] support TLS config hot reload via `SIGHUP`
(elastic#171823)](elastic#171823)

<!--- Backport version: 8.9.8 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Pierre
Gayvallet","email":"[email protected]"},"sourceCommit":{"committedDate":"2023-11-24T09:05:27Z","message":"[HTTP
Server] support TLS config hot reload via `SIGHUP` (elastic#171823)\n\n##
Summary\r\n\r\nFix
https://github.com/elastic/kibana/issues/54368\r\n\r\nAdd support for
hot reloading the Kibana server's TLS configuration,\r\nusing the same
`SIGHUP`-based reload signal, as already implemented for\r\nother parts
of the Kibana configuration (e.g `logging`)\r\n\r\n**Note:**\r\n- hot
reloading is only supported for the server TLS
configuration\r\n(`server.ssl`), not for the whole `server.*` config
prefix\r\n- swaping the certificate files (without modifying the kibana
config\r\nitself) is supported\r\n- it is not possible to toggle TLS
(enabling or disabling) without\r\nrestarting Kibana\r\n- hot reloading
requires to force the process to reload its\r\nconfiguration by sending
a `SIGHUP` signal\r\n\r\n### Example / how to test\r\n\r\n####
Before\r\n\r\n```yaml\r\nserver.ssl.enabled:
true\r\nserver.ssl.certificate:
/path-to-kibana/packages/kbn-dev-utils/certs/kibana.crt\r\nserver.ssl.key:
/path-to-kibana/packages/kbn-dev-utils/certs/kibana.key\r\n```\r\n\r\n<img
width=\"550\" alt=\"Screenshot 2023-11-23 at 15 11
28\"\r\nsrc=\"https://github.com/elastic/kibana/assets/1532934/1226d161-a9f2-4d62-a3de-37161829f187\">\r\n\r\n####
Changing the config\r\n\r\n```yaml\r\nserver.ssl.enabled:
true\r\nserver.ssl.certificate:
/path-to-kibana/packages/kbn-dev-utils/certs/elasticsearch.crt\r\nserver.ssl.key:
/path-to-kibana/packages/kbn-dev-utils/certs/elasticsearch.key\r\n```\r\n\r\n```bash\r\nkill
-SIGHUP {KIBANA_PID}\r\n```\r\n\r\n<img width=\"865\" alt=\"Screenshot
2023-11-23 at 15 18
21\"\r\nsrc=\"https://github.com/elastic/kibana/assets/1532934/c9412b2e-d70e-4cf0-8eaf-4db70a45af60\">\r\n\r\n####
After\r\n\r\n<img width=\"547\" alt=\"Screenshot 2023-11-23 at 15 18
43\"\r\nsrc=\"https://github.com/elastic/kibana/assets/1532934/c839f04f-4adb-456d-a174-4f0ebd5c234c\">\r\n\r\n##
Release notes\r\n\r\nIt is now possible to hot reload Kibana's TLS
(`server.ssl`)\r\nconfiguration by updating it and then sending a
`SIGHUP` signal to the\r\nKibana process.\r\n\r\nNote that TLS cannot be
toggled (disabled/enabled) that way, and that\r\nhot reload only works
for the TLS configuration, not other properties of\r\nthe `server`
config prefix.\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<[email protected]>","sha":"87213e7efe4420b0edf72d471056fe78cbd9df60","branchLabelMapping":{"^v8.12.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:enhancement","Feature:http","Team:Core","backport:prev-minor","v8.12.0"],"number":171823,"url":"https://github.com/elastic/kibana/pull/171823","mergeCommit":{"message":"[HTTP
Server] support TLS config hot reload via `SIGHUP` (elastic#171823)\n\n##
Summary\r\n\r\nFix
https://github.com/elastic/kibana/issues/54368\r\n\r\nAdd support for
hot reloading the Kibana server's TLS configuration,\r\nusing the same
`SIGHUP`-based reload signal, as already implemented for\r\nother parts
of the Kibana configuration (e.g `logging`)\r\n\r\n**Note:**\r\n- hot
reloading is only supported for the server TLS
configuration\r\n(`server.ssl`), not for the whole `server.*` config
prefix\r\n- swaping the certificate files (without modifying the kibana
config\r\nitself) is supported\r\n- it is not possible to toggle TLS
(enabling or disabling) without\r\nrestarting Kibana\r\n- hot reloading
requires to force the process to reload its\r\nconfiguration by sending
a `SIGHUP` signal\r\n\r\n### Example / how to test\r\n\r\n####
Before\r\n\r\n```yaml\r\nserver.ssl.enabled:
true\r\nserver.ssl.certificate:
/path-to-kibana/packages/kbn-dev-utils/certs/kibana.crt\r\nserver.ssl.key:
/path-to-kibana/packages/kbn-dev-utils/certs/kibana.key\r\n```\r\n\r\n<img
width=\"550\" alt=\"Screenshot 2023-11-23 at 15 11
28\"\r\nsrc=\"https://github.com/elastic/kibana/assets/1532934/1226d161-a9f2-4d62-a3de-37161829f187\">\r\n\r\n####
Changing the config\r\n\r\n```yaml\r\nserver.ssl.enabled:
true\r\nserver.ssl.certificate:
/path-to-kibana/packages/kbn-dev-utils/certs/elasticsearch.crt\r\nserver.ssl.key:
/path-to-kibana/packages/kbn-dev-utils/certs/elasticsearch.key\r\n```\r\n\r\n```bash\r\nkill
-SIGHUP {KIBANA_PID}\r\n```\r\n\r\n<img width=\"865\" alt=\"Screenshot
2023-11-23 at 15 18
21\"\r\nsrc=\"https://github.com/elastic/kibana/assets/1532934/c9412b2e-d70e-4cf0-8eaf-4db70a45af60\">\r\n\r\n####
After\r\n\r\n<img width=\"547\" alt=\"Screenshot 2023-11-23 at 15 18
43\"\r\nsrc=\"https://github.com/elastic/kibana/assets/1532934/c839f04f-4adb-456d-a174-4f0ebd5c234c\">\r\n\r\n##
Release notes\r\n\r\nIt is now possible to hot reload Kibana's TLS
(`server.ssl`)\r\nconfiguration by updating it and then sending a
`SIGHUP` signal to the\r\nKibana process.\r\n\r\nNote that TLS cannot be
toggled (disabled/enabled) that way, and that\r\nhot reload only works
for the TLS configuration, not other properties of\r\nthe `server`
config prefix.\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<[email protected]>","sha":"87213e7efe4420b0edf72d471056fe78cbd9df60"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v8.12.0","labelRegex":"^v8.12.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/171823","number":171823,"mergeCommit":{"message":"[HTTP
Server] support TLS config hot reload via `SIGHUP` (elastic#171823)\n\n##
Summary\r\n\r\nFix
https://github.com/elastic/kibana/issues/54368\r\n\r\nAdd support for
hot reloading the Kibana server's TLS configuration,\r\nusing the same
`SIGHUP`-based reload signal, as already implemented for\r\nother parts
of the Kibana configuration (e.g `logging`)\r\n\r\n**Note:**\r\n- hot
reloading is only supported for the server TLS
configuration\r\n(`server.ssl`), not for the whole `server.*` config
prefix\r\n- swaping the certificate files (without modifying the kibana
config\r\nitself) is supported\r\n- it is not possible to toggle TLS
(enabling or disabling) without\r\nrestarting Kibana\r\n- hot reloading
requires to force the process to reload its\r\nconfiguration by sending
a `SIGHUP` signal\r\n\r\n### Example / how to test\r\n\r\n####
Before\r\n\r\n```yaml\r\nserver.ssl.enabled:
true\r\nserver.ssl.certificate:
/path-to-kibana/packages/kbn-dev-utils/certs/kibana.crt\r\nserver.ssl.key:
/path-to-kibana/packages/kbn-dev-utils/certs/kibana.key\r\n```\r\n\r\n<img
width=\"550\" alt=\"Screenshot 2023-11-23 at 15 11
28\"\r\nsrc=\"https://github.com/elastic/kibana/assets/1532934/1226d161-a9f2-4d62-a3de-37161829f187\">\r\n\r\n####
Changing the config\r\n\r\n```yaml\r\nserver.ssl.enabled:
true\r\nserver.ssl.certificate:
/path-to-kibana/packages/kbn-dev-utils/certs/elasticsearch.crt\r\nserver.ssl.key:
/path-to-kibana/packages/kbn-dev-utils/certs/elasticsearch.key\r\n```\r\n\r\n```bash\r\nkill
-SIGHUP {KIBANA_PID}\r\n```\r\n\r\n<img width=\"865\" alt=\"Screenshot
2023-11-23 at 15 18
21\"\r\nsrc=\"https://github.com/elastic/kibana/assets/1532934/c9412b2e-d70e-4cf0-8eaf-4db70a45af60\">\r\n\r\n####
After\r\n\r\n<img width=\"547\" alt=\"Screenshot 2023-11-23 at 15 18
43\"\r\nsrc=\"https://github.com/elastic/kibana/assets/1532934/c839f04f-4adb-456d-a174-4f0ebd5c234c\">\r\n\r\n##
Release notes\r\n\r\nIt is now possible to hot reload Kibana's TLS
(`server.ssl`)\r\nconfiguration by updating it and then sending a
`SIGHUP` signal to the\r\nKibana process.\r\n\r\nNote that TLS cannot be
toggled (disabled/enabled) that way, and that\r\nhot reload only works
for the TLS configuration, not other properties of\r\nthe `server`
config prefix.\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<[email protected]>","sha":"87213e7efe4420b0edf72d471056fe78cbd9df60"}}]}]
BACKPORT-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:prev-minor Backport to (8.x) the previous minor version (i.e. one version back from main) Feature:http release_note:enhancement Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc v8.11.2 v8.12.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FEATURE]: Kibana to watch certificate changes and reload them on-the-fly
5 participants