Skip to content

fix(stackable-webhook): Move certificate generation to the blocking thread #815

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

Merged
merged 3 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/stackable-webhook/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ All notable changes to this project will be documented in this file.
the `Host` info (data about the server) in the `AxumTraceLayer`. This was
previously not extracted correctly and thus not included in the OpenTelemetry
compatible traces ([#806]).
- Spawn blocking code on a blocking thread ([#815]).

[#806]: https://github.com/stackabletech/operator-rs/pull/806
[#811]: https://github.com/stackabletech/operator-rs/pull/811
[#815]: https://github.com/stackabletech/operator-rs/pull/815

## [0.3.0] - 2024-05-08

Expand Down
75 changes: 45 additions & 30 deletions crates/stackable-webhook/src/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ pub enum Error {

#[snafu(display("failed to set safe TLS protocol versions"))]
SetSafeTlsProtocolVersions { source: tokio_rustls::rustls::Error },

#[snafu(display("failed to run task in blocking thread"))]
TokioSpawnBlocking { source: tokio::task::JoinError },
}

/// Custom implementation of [`std::cmp::PartialEq`] because some inner types
Expand Down Expand Up @@ -94,37 +97,49 @@ pub struct TlsServer {
impl TlsServer {
#[instrument(name = "create_tls_server", skip(router))]
pub async fn new(socket_addr: SocketAddr, router: Router) -> Result<Self> {
let mut certificate_authority =
CertificateAuthority::new_rsa().context(CreateCertificateAuthoritySnafu)?;

let leaf_certificate = certificate_authority
.generate_rsa_leaf_certificate("Leaf", "webhook", Duration::from_secs(3600))
.context(GenerateLeafCertificateSnafu)?;

let certificate_der = leaf_certificate
.certificate_der()
.context(EncodeCertificateDerSnafu)?;

let private_key_der = leaf_certificate
.private_key_der()
.context(EncodePrivateKeyDerSnafu)?;

let tls_provider = default_provider();
let mut config = ServerConfig::builder_with_provider(tls_provider.into())
.with_protocol_versions(&[&TLS12, &TLS13])
.context(SetSafeTlsProtocolVersionsSnafu)?
.with_no_client_auth()
.with_single_cert(vec![certificate_der], private_key_der)
.context(InvalidTlsPrivateKeySnafu)?;

config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
let config = Arc::new(config);

Ok(Self {
socket_addr,
config,
router,
// NOTE(@NickLarsenNZ): This code is not async, and does take some
// non-negligable amount of time to complete (moreso in debug ).
// We run this in a thread reserved for blocking code so that the Tokio
// executor is able to make progress on other futures instead of being
// blocked.
// See https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html
let task = tokio::task::spawn_blocking(move || {
let mut certificate_authority =
CertificateAuthority::new_rsa().context(CreateCertificateAuthoritySnafu)?;

let leaf_certificate = certificate_authority
.generate_rsa_leaf_certificate("Leaf", "webhook", Duration::from_secs(3600))
.context(GenerateLeafCertificateSnafu)?;

let certificate_der = leaf_certificate
.certificate_der()
.context(EncodeCertificateDerSnafu)?;

let private_key_der = leaf_certificate
.private_key_der()
.context(EncodePrivateKeyDerSnafu)?;

let tls_provider = default_provider();
let mut config = ServerConfig::builder_with_provider(tls_provider.into())
.with_protocol_versions(&[&TLS12, &TLS13])
.context(SetSafeTlsProtocolVersionsSnafu)?
.with_no_client_auth()
.with_single_cert(vec![certificate_der], private_key_der)
.context(InvalidTlsPrivateKeySnafu)?;

config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
let config = Arc::new(config);

Ok(Self {
socket_addr,
config,
router,
})
})
.await
.context(TokioSpawnBlockingSnafu)??;

Ok(task)
}

/// Runs the TLS server by listening for incoming TCP connections on the
Expand Down
Loading