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

Remove openssl in favor of rustls-tls #401

Merged
merged 1 commit into from Feb 7, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1,045 changes: 427 additions & 618 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 1 addition & 5 deletions Dockerfile
Expand Up @@ -4,11 +4,8 @@ FROM ${BUILDER_IMAGE} as build
ARG UNAME_ARCH
USER root

# We need these environment variables set for building the `openssl-sys` crate
ENV PKG_CONFIG_PATH=/${UNAME_ARCH}-bottlerocket-linux-musl/sys-root/usr/lib/pkgconfig
ENV PKG_CONFIG_ALLOW_CROSS=1
# Required to build in --offline mode
ENV CARGO_HOME=/src/.cargo
ENV OPENSSL_STATIC=true

ADD ./ /src/
RUN cargo install --offline --locked --target ${UNAME_ARCH}-bottlerocket-linux-musl --path /src/agent --root /src/agent && \
Expand Down Expand Up @@ -41,5 +38,4 @@ COPY --from=build /licenses /licenses
COPY --from=build \
/usr/share/licenses/bottlerocket-sdk-musl \
/usr/share/licenses/rust \
/usr/share/licenses/openssl \
/licenses/bottlerocket-sdk/
3 changes: 1 addition & 2 deletions agent/Cargo.toml
Expand Up @@ -18,13 +18,12 @@ tracing-opentelemetry = "0.18"

# k8s-openapi must match the version required by kube and enable a k8s version feature
k8s-openapi = { version = "0.17.0", default-features = false, features = ["v1_20"] }
kube = { version = "0.78.0", default-features = true, features = [ "derive", "runtime", "rustls-tls" ] }
kube = { version = "0.78.0", default-features = false, features = [ "derive", "runtime", "rustls-tls" ] }

semver = { version = "1.0", features = [ "serde" ] }
serde = { version = "1", features = [ "derive" ] }
serde_json = "1"
snafu = "0.7"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }
reqwest = { version = "0.11", features = [ "json" ] }
jpmcb marked this conversation as resolved.
Show resolved Hide resolved
chrono = { version = "0.4.23", features = [ "serde" ] }
tokio-retry = "0.3"
10 changes: 6 additions & 4 deletions apiserver/Cargo.toml
Expand Up @@ -15,10 +15,12 @@ server = []
models = { path = "../models", version = "0.1.0" }

# tracing-actix-web version must align with actix-web version
actix-web = { version = "4", features = ["openssl"] }
actix-web = { version = "4", features = ["rustls"] }
awc = "3"
actix-web-opentelemetry = { version = "0.13", features = ["metrics", "metrics-prometheus"] }
openssl = { version = "0.10" }
rustls = { version = "0.20" }
rustls-pemfile = { version = "1" }
webpki = { version = "0.22.0", features = ["std"] }
opentelemetry = { version = "0.18", features = ["rt-tokio-current-thread"]}
opentelemetry-prometheus = "0.11"
tracing = "0.1"
Expand All @@ -28,14 +30,14 @@ tracing-opentelemetry = "0.18"

# k8s-openapi must match the version required by kube and enable a k8s version feature
k8s-openapi = { version = "0.17.0", default-features = false, features = ["v1_20"] }
kube = { version = "0.78.0", default-features = true, features = [ "derive", "runtime", "rustls-tls" ] }
kube = { version = "0.78.0", default-features = false, features = [ "client", "derive", "runtime", "rustls-tls" ] }

async-trait = "0.1"
futures = "0.3"
lazy_static = "1.4"
log = "0.4"
mockall = { version = "0.11", optional = true }
reqwest = { version = "0.11", features = [ "json", "native-tls" ] }
reqwest = { version = "0.11", default-features = false, features = [ "json", "rustls-tls" ] }
schemars = "0.8.11"
serde = { version = "1", features = [ "derive" ] }
serde_json = "1"
Expand Down
17 changes: 14 additions & 3 deletions apiserver/src/api/error.rs
@@ -1,3 +1,5 @@
use std::io;

use models::node::{error, BottlerocketShadowClientError};

use actix_web::error::ResponseError;
Expand Down Expand Up @@ -44,10 +46,19 @@ pub enum Error {
#[snafu(display("Failed to reload certificate."))]
ReloadCertificateFailed {},

#[snafu(display("Failed to set up SslAcceptorBuilder : {:?}", source))]
SSLError { source: openssl::error::ErrorStack },
#[snafu(display("Failed to open file '{}': {}", path, source))]
FileOpen { path: String, source: io::Error },

#[snafu(display("Failed to extract TLS cert from file {}: {}", path, source))]
CertExtract { path: String, source: io::Error },

#[snafu(display("Failed to add CA to cert store: {}", source))]
CertStore { source: webpki::Error },

#[snafu(display("Failed to build TLS config from loaded certs: {}", source))]
TLSConfigBuild { source: rustls::Error },

#[snafu(display("Failed to serialize Webhook response: {:?}", source))]
#[snafu(display("Failed to serialize Webhook response: {}", source))]
WebhookError { source: serde_json::error::Error },
}

Expand Down
85 changes: 65 additions & 20 deletions apiserver/src/api/mod.rs
Expand Up @@ -34,10 +34,14 @@ use kube::{
runtime::{reflector, watcher::watcher, WatchStreamExt},
ResourceExt,
};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use opentelemetry::global::meter;
use rustls::{
server::AllowAnyAnonymousOrAuthenticatedClient, Certificate, PrivateKey, RootCertStore,
ServerConfig,
};
use rustls_pemfile::{certs, pkcs8_private_keys};
use snafu::{OptionExt, ResultExt};
use std::env;
use std::{env, fs::File, io::BufReader};
use tokio::time::{sleep, Duration};
use tracing::{event, Level};
use tracing_actix_web::TracingLogger;
Expand Down Expand Up @@ -158,23 +162,64 @@ pub async fn run_server<T: 'static + BottlerocketShadowClient>(

event!(Level::DEBUG, ?server_addr, "Server addr localhost.");

let mut builder = SslAcceptor::mozilla_modern_v5(SslMethod::tls()).context(error::SSLSnafu)?;

builder
.set_certificate_chain_file(format!("{}/{}", TLS_KEY_MOUNT_PATH, CA_NAME))
.context(error::SSLSnafu)?;
builder
.set_certificate_file(
format!("{}/{}", TLS_KEY_MOUNT_PATH, PUBLIC_KEY_NAME),
SslFiletype::PEM,
)
.context(error::SSLSnafu)?;
builder
.set_private_key_file(
format!("{}/{}", TLS_KEY_MOUNT_PATH, PRIVATE_KEY_NAME),
SslFiletype::PEM,
)
.context(error::SSLSnafu)?;
// Server public certificate file
let cert_file_path = format!("{}/{}", TLS_KEY_MOUNT_PATH, PUBLIC_KEY_NAME);
let cert_file =
&mut BufReader::new(File::open(&cert_file_path).context(error::FileOpenSnafu {
path: cert_file_path.to_string(),
})?);

// Private key file
let key_file_path = format!("{}/{}", TLS_KEY_MOUNT_PATH, PRIVATE_KEY_NAME);
let key_file =
&mut BufReader::new(File::open(&key_file_path).context(error::FileOpenSnafu {
path: key_file_path.to_string(),
})?);

// Certificate authority file so a client can authenticate the server
let ca_file_path = format!("{}/{}", TLS_KEY_MOUNT_PATH, CA_NAME);
let ca_file = &mut BufReader::new(File::open(&ca_file_path).context(error::FileOpenSnafu {
path: ca_file_path.to_string(),
})?);

// convert files to key/cert objects
let cert_chain = certs(cert_file)
.context(error::CertExtractSnafu {
path: cert_file_path.to_string(),
})?
.into_iter()
.map(Certificate)
.collect();
let mut keys: Vec<PrivateKey> = pkcs8_private_keys(key_file)
.context(error::CertExtractSnafu {
path: key_file_path.to_string(),
})?
.into_iter()
.map(PrivateKey)
.collect();
let cas: Vec<Certificate> = certs(ca_file)
.context(error::CertExtractSnafu {
path: ca_file_path.to_string(),
})?
.into_iter()
.map(Certificate)
.collect();

let mut cert_store = RootCertStore::empty();
for ca in cas {
cert_store.add(&ca).context(error::CertStoreSnafu)?;
}

let verifier = AllowAnyAnonymousOrAuthenticatedClient::new(cert_store);

let tls_config_builder = ServerConfig::builder()
.with_safe_defaults()
.with_client_cert_verifier(verifier);

let tls_config = tls_config_builder
.with_single_cert(cert_chain, keys.remove(0))
.context(error::TLSConfigBuildSnafu)
.unwrap();

let server = HttpServer::new(move || {
App::new()
Expand Down Expand Up @@ -225,7 +270,7 @@ pub async fn run_server<T: 'static + BottlerocketShadowClient>(
web::get().to(ping::health_check),
)
})
.bind_openssl(server_addr, builder)
.bind_rustls(server_addr, tls_config)
.context(error::HttpServerSnafu)?
.run();

Expand Down
3 changes: 2 additions & 1 deletion clarify.toml
Expand Up @@ -69,10 +69,11 @@ license-files = [
#
# zstd's README file states:
# "Zstandard is dual-licensed under BSD and GPLv2."
expression = "(MIT OR Apache-2.0) AND (BSD-2-Clause OR GPL-2.0)"
expression = "(MIT OR Apache-2.0) AND (BSD-3-Clause OR GPL-2.0)"
license-files = [
{ path = "LICENSE", hash = 0x742401ae },
{ path = "LICENSE.Apache-2.0", hash = 0x7b466be4 },
{ path = "LICENSE.BSD-3-Clause", hash = 0xc9f5c4f6},
{ path = "LICENSE.Mit", hash = 0xa237d234 },
{ path = "zstd/COPYING", hash = 0x96841aa4 },
{ path = "zstd/LICENSE", hash = 0x79cda15 },
Expand Down
2 changes: 1 addition & 1 deletion controller/Cargo.toml
Expand Up @@ -14,7 +14,7 @@ maplit = "1.0"
semver = "1.0"
# k8s-openapi must match the version required by kube and enable a k8s version feature
k8s-openapi = { version = "0.17.0", default-features = false, features = ["v1_20"] }
kube = { version = "0.78.0", default-features = true, features = [ "derive", "runtime", "rustls-tls" ] }
kube = { version = "0.78.0", default-features = false, features = [ "derive", "runtime", "rustls-tls" ] }
models = { path = "../models", version = "0.1.0" }
opentelemetry = { version = "0.18", features = ["rt-tokio-current-thread"] }
opentelemetry-prometheus = "0.11"
Expand Down
2 changes: 2 additions & 0 deletions deny.toml
Expand Up @@ -23,6 +23,8 @@ allow = [
]

exceptions = [
# Explicitly allows MPL-2 being pulled in through reqwest's and actix's rustls dependency chain (which uses webpki)
{ name = "webpki-roots", allow = ["MPL-2.0"], version = "*" },
jpmcb marked this conversation as resolved.
Show resolved Hide resolved
{ name = "unicode-ident", version = "1.0.2", allow = ["MIT", "Apache-2.0", "Unicode-DFS-2016"] },
]

Expand Down
2 changes: 1 addition & 1 deletion integ/Cargo.toml
Expand Up @@ -35,7 +35,7 @@ uuid = { version = "0.8", default-features = false, features = ["serde", "v4"] }

# k8s-openapi must match the version required by kube and enable a k8s version feature
k8s-openapi = { version = "0.17.0", default-features = false, features = ["v1_20"] }
kube = { version = "0.78", default-features = true, features = [ "derive", "runtime" ] }
kube = { version = "0.78", default-features = false, features = [ "derive", "runtime" ] }


[dev-dependencies]
Expand Down
4 changes: 2 additions & 2 deletions models/Cargo.toml
Expand Up @@ -11,13 +11,13 @@ chrono = "0.4"
futures = "0.3"
# k8s-openapi must match the version required by kube and enable a k8s version feature
k8s-openapi = { version = "0.17.0", default-features = false, features = ["v1_20"] }
kube = { version = "0.78.0", default-features = true, features = [ "derive", "runtime" ] }
kube = { version = "0.78.0", default-features = false, features = [ "client", "derive", "runtime" ] }

lazy_static = "1.4"
maplit = "1.0"
mockall = { version = "0.11", optional = true }
regex = "1.7"
reqwest = "0.11"
reqwest = { version = "0.11", default-features = false, features = [ "json" ] }
schemars = "0.8.11"
semver = "1.0"
serde = { version = "1", features = [ "derive" ] }
Expand Down
2 changes: 1 addition & 1 deletion yamlgen/Cargo.toml
Expand Up @@ -8,5 +8,5 @@ license = "Apache-2.0 OR MIT"
[build-dependencies]
models = { path = "../models", version = "0.1.0" }
dotenv = "0.15"
kube = { version = "0.78.0", default-features = true, features = [ "derive", "runtime" ] }
kube = { version = "0.78.0", default-features = false, features = [ "derive", "runtime" ] }
serde_yaml = "0.9"