diff --git a/vector.yaml b/vector.yaml index b9b254a110c..0a7a266fd3b 100644 --- a/vector.yaml +++ b/vector.yaml @@ -1,6 +1,6 @@ package: name: vector - version: "0.51.1" + version: "0.52.0" epoch: 0 description: End-to-end observability data pipeline copyright: @@ -14,6 +14,7 @@ environment: packages: - bash - build-base + - clang-21 - cyrus-sasl-dev - gcc-14-default - librdkafka @@ -31,14 +32,7 @@ pipeline: with: repository: https://github.com/vectordotdev/vector tag: v${{package.version}} - expected-commit: 44c8f1cfd64bdedb924034c946f639d09890fc53 - - # NOTE: Patch not applied upstream just yet, but is required to actually keep - # the package FIPS-able. Let's keep an eye out for upstream movement there. - # https://github.com/vectordotdev/vector/pull/23146 - - uses: patch - with: - patches: rework-TlsSettings-to-carry-PEM-based-objects.patch + expected-commit: ca5bf2690ffcfc2c95d320cf7156b1df1b28a080 - runs: | sed -i '7s/deny/allow/' src/lib.rs diff --git a/vector/rework-TlsSettings-to-carry-PEM-based-objects.patch b/vector/rework-TlsSettings-to-carry-PEM-based-objects.patch deleted file mode 100644 index 94ce5e08431..00000000000 --- a/vector/rework-TlsSettings-to-carry-PEM-based-objects.patch +++ /dev/null @@ -1,255 +0,0 @@ -From c757406e2f3174fdc93fac327780ee7bf0bb1a1a Mon Sep 17 00:00:00 2001 -From: ben -Date: Mon, 2 Jun 2025 03:24:10 -0700 -Subject: internal(tlssettings tlsconfig): rework TlsSettings and - TlsConfig to use PEM files instead of PKCS12 for FIPS compatibility - -TlsSettings used a PKCS12 archive to store the TLS identity information. PKCS12 is not -Federal Information Processing Standard (FIPS) compliant, and there is significant interest -to use vector in such environments. - -This change makes PEM based certs & keys the format stored in TlsSettings. For compatibility -when a PKCS12 (DER) archive is presented in the configuration, the code will extract the -components into X509 at load time. This conversion is not FIPS compliant and should be avoided -there. In pratice, most use cases do not use FIPS, so this is perfectly fine to use. - -This change was tested on a regular machine, and on a FIPS enabled kernel where we compiled -vector to dynamically link to the system provided OpenSSL. Only the 'fips' and 'base' providers -were configured to be available. - -RUSTFLAGS="-C prefer-dynamic" OPENSSL_NO_VENDOR=1 OPENSSL_STATIC=0 \ - cargo build -j8 --release --target x86_64-unknown-linux-gnu \ - --no-default-features --features target-x86_64-unknown-linux-gnu - -Key changes: -* IdentityStore now keeps a name, cert, private key, and an optional list of ca certs -* PKCS12 configuration will convert to IdentityStore on load -* TlsSettings::identity() returns the IdentityStore instead of a PKCS12 archive. This - avoids the need to convert to PCKS12 and thus avoids the FIPS incompatibility for - future uses - -Relevant pull request: https://github.com/vectordotdev/vector/pull/23146 -Patch has been modified to removed unneeded changes. ---- - -diff --git a/lib/vector-core/src/tls/settings.rs b/lib/vector-core/src/tls/settings.rs -index 999972b05ad9c..498ae122827d4 100644 ---- a/lib/vector-core/src/tls/settings.rs -+++ b/lib/vector-core/src/tls/settings.rs -@@ -5,10 +5,16 @@ use std::{ - path::{Path, PathBuf}, - }; - -+use super::{ -+ AddCertToStoreSnafu, AddExtraChainCertSnafu, CaStackPushSnafu, EncodeAlpnProtocolsSnafu, -+ FileOpenFailedSnafu, FileReadFailedSnafu, MaybeTls, NewCaStackSnafu, NewStoreBuilderSnafu, -+ ParsePkcs12Snafu, PrivateKeyParseSnafu, Result, SetAlpnProtocolsSnafu, SetCertificateSnafu, -+ SetPrivateKeySnafu, SetVerifyCertSnafu, TlsError, X509ParseSnafu, -+}; - use cfg_if::cfg_if; - use lookup::lookup_v2::OptionalValuePath; - use openssl::{ -- pkcs12::{ParsedPkcs12_2, Pkcs12}, -+ pkcs12::Pkcs12, - pkey::{PKey, Private}, - ssl::{AlpnError, ConnectConfiguration, SslContextBuilder, SslVerifyMode, select_next_proto}, - stack::Stack, -@@ -17,14 +23,6 @@ use openssl::{ - use snafu::ResultExt; - use vector_config::configurable_component; - --use super::{ -- AddCertToStoreSnafu, AddExtraChainCertSnafu, CaStackPushSnafu, DerExportSnafu, -- EncodeAlpnProtocolsSnafu, FileOpenFailedSnafu, FileReadFailedSnafu, MaybeTls, NewCaStackSnafu, -- NewStoreBuilderSnafu, ParsePkcs12Snafu, Pkcs12Snafu, PrivateKeyParseSnafu, Result, -- SetAlpnProtocolsSnafu, SetCertificateSnafu, SetPrivateKeySnafu, SetVerifyCertSnafu, TlsError, -- TlsIdentitySnafu, X509ParseSnafu, --}; -- - pub const PEM_START_MARKER: &str = "-----BEGIN "; - - pub const TEST_PEM_CA_PATH: &str = "tests/data/ca/certs/ca.cert.pem"; -@@ -177,13 +175,18 @@ pub struct TlsSettings { - verify_certificate: bool, - pub(super) verify_hostname: bool, - authorities: Vec, -- pub(super) identity: Option, // openssl::pkcs12::ParsedPkcs12 doesn't impl Clone yet -+ pub(super) identity: Option, - alpn_protocols: Option>, - server_name: Option, - } - -+/// Identity store in PEM format - #[derive(Clone)] --pub(super) struct IdentityStore(Vec, String); -+pub(super) struct IdentityStore { -+ cert: X509, -+ key: PKey, -+ ca: Option>, -+} - - impl TlsSettings { - /// Generate a filled out settings struct from the given optional -@@ -220,37 +223,17 @@ impl TlsSettings { - }) - } - -- /// Returns the identity as PKCS12 -- /// -- /// # Panics -- /// -- /// Panics if the identity is invalid. -- fn identity(&self) -> Option { -- // This data was test-built previously, so we can just use it -- // here and expect the results will not fail. This can all be -- // reworked when `openssl::pkcs12::ParsedPkcs12` gains the Clone -- // impl. -- self.identity.as_ref().map(|identity| { -- Pkcs12::from_der(&identity.0) -- .expect("Could not build PKCS#12 archive from parsed data") -- .parse2(&identity.1) -- .expect("Could not parse stored PKCS#12 archive") -- }) -- } -- -- /// Returns the identity as PEM data -+ /// Returns the identity as PEM encoded byte arrays - /// - /// # Panics - /// - /// Panics if the identity is missing, invalid, or the authorities to chain are invalid. - pub fn identity_pem(&self) -> Option<(Vec, Vec)> { -- self.identity().map(|identity| { -- let mut cert = identity -- .cert -- .expect("Identity required") -- .to_pem() -- .expect("Invalid stored identity"); -- if let Some(chain) = identity.ca { -+ self.identity.as_ref().map(|identity| { -+ // we have verified correct formatting at ingest time -+ let mut cert = identity.cert.to_pem().expect("Invalid stored identity"); -+ let key = identity.key.private_key_to_pem_pkcs8().expect("Invalid stored identity"); -+ if let Some(chain) = identity.ca.as_ref() { - for authority in chain { - cert.extend( - authority -@@ -259,11 +242,6 @@ impl TlsSettings { - ); - } - } -- let key = identity -- .pkey -- .expect("Private key required") -- .private_key_to_pem_pkcs8() -- .expect("Invalid stored private key"); - (cert, key) - }) - } -@@ -295,18 +273,18 @@ impl TlsSettings { - } else { - SslVerifyMode::NONE - }); -- if let Some(identity) = self.identity() { -- if let Some(cert) = &identity.cert { -- context.set_certificate(cert).context(SetCertificateSnafu)?; -- } -- if let Some(pkey) = &identity.pkey { -- context.set_private_key(pkey).context(SetPrivateKeySnafu)?; -- } -+ if let Some(identity) = &self.identity { -+ context -+ .set_certificate(&identity.cert) -+ .context(SetCertificateSnafu)?; -+ context -+ .set_private_key(&identity.key) -+ .context(SetPrivateKeySnafu)?; - -- if let Some(chain) = identity.ca { -+ if let Some(chain) = &identity.ca { - for cert in chain { - context -- .add_extra_chain_cert(cert) -+ .add_extra_chain_cert(cert.clone()) - .context(AddExtraChainCertSnafu)?; - } - } -@@ -401,7 +379,7 @@ impl TlsConfig { - let (data, filename) = open_read(filename, "certificate")?; - der_or_pem( - data, -- |der| self.parse_pkcs12_identity(der), -+ |der| self.parse_pkcs12_identity(&der), - |pem| self.parse_pem_identity(&pem, &filename), - ) - } -@@ -430,45 +408,47 @@ impl TlsConfig { - match &self.key_file { - None => Err(TlsError::MissingKey), - Some(key_file) => { -- let name = crt_file.to_string_lossy().to_string(); - let mut crt_stack = X509::stack_from_pem(pem.as_bytes()) - .with_context(|_| X509ParseSnafu { filename: crt_file })? - .into_iter(); - -- let crt = crt_stack.next().ok_or(TlsError::MissingCertificate)?; -+ let cert = crt_stack.next().ok_or(TlsError::MissingCertificate)?; - let key = load_key(key_file.as_path(), self.key_pass.as_ref())?; - - let mut ca_stack = Stack::new().context(NewCaStackSnafu)?; - for intermediate in crt_stack { - ca_stack.push(intermediate).context(CaStackPushSnafu)?; - } -- -- let pkcs12 = Pkcs12::builder() -- .ca(ca_stack) -- .name(&name) -- .pkey(&key) -- .cert(&crt) -- .build2("") -- .context(Pkcs12Snafu)?; -- let identity = pkcs12.to_der().context(DerExportSnafu)?; -- -- // Build the resulting parsed PKCS#12 archive, -- // but don't store it, as it cannot be cloned. -- // This is just for error checking. -- pkcs12.parse2("").context(TlsIdentitySnafu)?; -- -- Ok(Some(IdentityStore(identity, String::new()))) -+ let ca: Vec = ca_stack.iter().map(std::borrow::ToOwned::to_owned).collect(); -+ Ok(Some(IdentityStore { -+ cert, -+ key, -+ ca: Some(ca), -+ })) - } - } - } - - /// Parse identity from a DER encoded PKCS#12 archive -- fn parse_pkcs12_identity(&self, der: Vec) -> Result> { -- let pkcs12 = Pkcs12::from_der(&der).context(ParsePkcs12Snafu)?; -+ fn parse_pkcs12_identity( -+ &self, -+ der: &[u8], -+ ) -> Result> { -+ let pkcs12 = Pkcs12::from_der(der).context(ParsePkcs12Snafu)?; - // Verify password - let key_pass = self.key_pass.as_deref().unwrap_or(""); -- pkcs12.parse2(key_pass).context(ParsePkcs12Snafu)?; -- Ok(Some(IdentityStore(der, key_pass.to_string()))) -+ let parsed = pkcs12.parse2(key_pass).context(ParsePkcs12Snafu)?; -+ // extract cert, key and ca and store as PEM sow e can return an IdentityStore -+ let cert = parsed.cert.ok_or(TlsError::MissingCertificate)?; -+ let key = parsed.pkey.ok_or(TlsError::MissingKey)?; -+ let ca: Option> = parsed -+ .ca -+ .map(|stack| stack.iter().map(std::borrow::ToOwned::to_owned).collect()); -+ Ok(Some(IdentityStore { -+ cert, -+ key, -+ ca, -+ })) - } - } -