From 89543a20000ee02293eedbb551e886da87258745 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Wed, 29 Oct 2025 10:50:27 +0100 Subject: [PATCH 1/3] feat: OPA TLS support --- rust/operator-binary/src/authorization/opa.rs | 18 +++++++++ rust/operator-binary/src/controller.rs | 40 +++++++++++++++++++ .../opa-authorization/10-install-opa.yaml.j2 | 15 +++++++ 3 files changed, 73 insertions(+) diff --git a/rust/operator-binary/src/authorization/opa.rs b/rust/operator-binary/src/authorization/opa.rs index b42280b5..ef8b8b26 100644 --- a/rust/operator-binary/src/authorization/opa.rs +++ b/rust/operator-binary/src/authorization/opa.rs @@ -3,6 +3,8 @@ use std::collections::BTreeMap; use stackable_operator::{ client::Client, commons::opa::{OpaApiVersion, OpaConfig}, + k8s_openapi::api::core::v1::ConfigMap, + kube::ResourceExt, }; use crate::crd::v1alpha1::TrinoCluster; @@ -28,6 +30,10 @@ pub struct TrinoOpaConfig { /// such operations, they will be bulk allowed or denied depending /// on this setting pub(crate) allow_permission_management_operations: bool, + /// Optional TLS secret class for OPA communication. + /// If set, the CA certificate from this secret class will be added + /// to Trino's truststore to make it trust OPA's TLS certificate. + pub(crate) tls_secret_class: Option, } impl TrinoOpaConfig { @@ -66,12 +72,24 @@ impl TrinoOpaConfig { OpaApiVersion::V1, ) .await?; + + let tls_secret_class = client + .get::( + &opa_config.config_map_name, + trino.namespace().as_deref().unwrap_or("default"), + ) + .await + .ok() + .and_then(|cm| cm.data) + .and_then(|mut data| data.remove("OPA_SECRET_CLASS")); + Ok(TrinoOpaConfig { non_batched_connection_string, batched_connection_string, row_filters_connection_string: Some(row_filters_connection_string), column_masking_connection_string: Some(column_masking_connection_string), allow_permission_management_operations: true, + tls_secret_class, }) } diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index fc9a88e2..407bab2e 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -123,6 +123,7 @@ pub const MAX_PREPARE_LOG_FILE_SIZE: MemoryQuantity = MemoryQuantity { }; const DOCKER_IMAGE_BASE_NAME: &str = "trino"; +const OPA_TLS_VOLUME_NAME: &str = "opa-tls"; #[derive(Snafu, Debug, EnumDiscriminants)] #[strum_discriminants(derive(IntoStaticStr))] @@ -630,6 +631,7 @@ pub async fn reconcile_trino( &rbac_sa.name_any(), &resolved_fte_config, &resolved_client_protocol_config, + &trino_opa_config, )?; cluster_resources @@ -1037,6 +1039,7 @@ fn build_rolegroup_statefulset( sa_name: &str, resolved_fte_config: &Option, resolved_spooling_config: &Option, + trino_opa_config: &Option, ) -> Result { let role = trino .role(trino_role) @@ -1140,6 +1143,7 @@ fn build_rolegroup_statefulset( &requested_secret_lifetime, resolved_fte_config, resolved_spooling_config, + trino_opa_config, )?; let mut prepare_args = vec![]; @@ -1165,6 +1169,18 @@ fn build_rolegroup_statefulset( prepare_args .extend(trino_authentication_config.commands(&TrinoRole::Coordinator, &Container::Prepare)); + // Add OPA TLS certificate to truststore if configured + if trino_opa_config + .as_ref() + .and_then(|c| c.tls_secret_class.as_ref()) + .is_some() + { + prepare_args.extend(command::add_cert_to_truststore( + &format!("/stackable/secrets/{OPA_TLS_VOLUME_NAME}/ca.crt"), + STACKABLE_CLIENT_TLS_DIR, + )); + } + let container_prepare = cb_prepare .image_from_product_image(resolved_product_image) .command(vec![ @@ -1710,6 +1726,7 @@ fn tls_volume_mounts( requested_secret_lifetime: &Duration, resolved_fte_config: &Option, resolved_spooling_config: &Option, + trino_opa_config: &Option, ) -> Result<()> { if let Some(server_tls) = trino.get_server_tls() { cb_prepare @@ -1789,6 +1806,28 @@ fn tls_volume_mounts( .context(AddVolumeSnafu)?; } + if let Some(opa_config) = trino_opa_config { + if let Some(opa_tls_secret_class) = &opa_config.tls_secret_class { + let opa_tls_mount_path = format!("/stackable/secrets/{OPA_TLS_VOLUME_NAME}"); + + cb_prepare + .add_volume_mount(OPA_TLS_VOLUME_NAME, &opa_tls_mount_path) + .context(AddVolumeMountSnafu)?; + + let opa_tls_volume = VolumeBuilder::new(OPA_TLS_VOLUME_NAME) + .ephemeral( + SecretOperatorVolumeSourceBuilder::new(opa_tls_secret_class) + .build() + .context(TlsCertSecretClassVolumeBuildSnafu)?, + ) + .build(); + + pod_builder + .add_volume(opa_tls_volume) + .context(AddVolumeSnafu)?; + } + } + // fault tolerant execution S3 credentials and other resources if let Some(resolved_fte) = resolved_fte_config { cb_prepare @@ -2028,6 +2067,7 @@ mod tests { .to_string(), ), allow_permission_management_operations: true, + tls_secret_class: None, }); let resolved_fte_config = match &trino.spec.cluster_config.fault_tolerant_execution { Some(fault_tolerant_execution) => Some( diff --git a/tests/templates/kuttl/opa-authorization/10-install-opa.yaml.j2 b/tests/templates/kuttl/opa-authorization/10-install-opa.yaml.j2 index 62686c39..afcb1c66 100644 --- a/tests/templates/kuttl/opa-authorization/10-install-opa.yaml.j2 +++ b/tests/templates/kuttl/opa-authorization/10-install-opa.yaml.j2 @@ -5,6 +5,19 @@ commands: - script: | kubectl apply -n $NAMESPACE -f - < Date: Wed, 29 Oct 2025 21:33:14 +0100 Subject: [PATCH 2/3] chore: changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5502a30..d6e7197a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. - Add support for Trino 477 ([#801]). - Add support for Hive 4.1.0 ([#805]). - Add `prometheus.io/path|port|scheme` annotations to metrics service ([#807]). +- Add support for OPA with TLS enabled ([#812]). ### Changed @@ -45,6 +46,7 @@ All notable changes to this project will be documented in this file. [#805]: https://github.com/stackabletech/trino-operator/pull/805 [#807]: https://github.com/stackabletech/trino-operator/pull/807 [#810]: https://github.com/stackabletech/trino-operator/pull/810 +[#812]: https://github.com/stackabletech/trino-operator/pull/812 ## [25.7.0] - 2025-07-23 From 261b6025a0495a8e80f017fa00705ec64e601b61 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Fri, 31 Oct 2025 19:18:32 +0100 Subject: [PATCH 3/3] recfactor: OPA tls mount helper method --- rust/operator-binary/src/authorization/opa.rs | 8 +++ rust/operator-binary/src/controller.rs | 54 ++++++++++--------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/rust/operator-binary/src/authorization/opa.rs b/rust/operator-binary/src/authorization/opa.rs index ef8b8b26..1bd9cd41 100644 --- a/rust/operator-binary/src/authorization/opa.rs +++ b/rust/operator-binary/src/authorization/opa.rs @@ -9,6 +9,8 @@ use stackable_operator::{ use crate::crd::v1alpha1::TrinoCluster; +pub const OPA_TLS_VOLUME_NAME: &str = "opa-tls"; + pub struct TrinoOpaConfig { /// URI for OPA policies, e.g. /// `http://localhost:8081/v1/data/trino/allow` @@ -125,4 +127,10 @@ impl TrinoOpaConfig { } config } + + pub fn tls_mount_path(&self) -> Option { + self.tls_secret_class + .as_ref() + .map(|_| format!("/stackable/secrets/{OPA_TLS_VOLUME_NAME}")) + } } diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 407bab2e..d8ddea6a 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -76,10 +76,10 @@ use strum::{EnumDiscriminants, IntoStaticStr}; use crate::{ authentication::{TrinoAuthenticationConfig, TrinoAuthenticationTypes}, - authorization::opa::TrinoOpaConfig, + authorization::opa::{OPA_TLS_VOLUME_NAME, TrinoOpaConfig}, catalog::{FromTrinoCatalogError, config::CatalogConfig}, - command, config, - config::{client_protocol, fault_tolerant_execution}, + command, + config::{self, client_protocol, fault_tolerant_execution}, crd::{ ACCESS_CONTROL_PROPERTIES, APP_NAME, CONFIG_DIR_NAME, CONFIG_PROPERTIES, Container, DISCOVERY_URI, ENV_INTERNAL_SECRET, ENV_SPOOLING_SECRET, EXCHANGE_MANAGER_PROPERTIES, @@ -123,7 +123,6 @@ pub const MAX_PREPARE_LOG_FILE_SIZE: MemoryQuantity = MemoryQuantity { }; const DOCKER_IMAGE_BASE_NAME: &str = "trino"; -const OPA_TLS_VOLUME_NAME: &str = "opa-tls"; #[derive(Snafu, Debug, EnumDiscriminants)] #[strum_discriminants(derive(IntoStaticStr))] @@ -1170,13 +1169,12 @@ fn build_rolegroup_statefulset( .extend(trino_authentication_config.commands(&TrinoRole::Coordinator, &Container::Prepare)); // Add OPA TLS certificate to truststore if configured - if trino_opa_config + if let Some(tls_mount_path) = trino_opa_config .as_ref() - .and_then(|c| c.tls_secret_class.as_ref()) - .is_some() + .and_then(|opa_config| opa_config.tls_mount_path()) { prepare_args.extend(command::add_cert_to_truststore( - &format!("/stackable/secrets/{OPA_TLS_VOLUME_NAME}/ca.crt"), + format!("{}/ca.crt", tls_mount_path).as_str(), STACKABLE_CLIENT_TLS_DIR, )); } @@ -1806,26 +1804,30 @@ fn tls_volume_mounts( .context(AddVolumeSnafu)?; } - if let Some(opa_config) = trino_opa_config { - if let Some(opa_tls_secret_class) = &opa_config.tls_secret_class { - let opa_tls_mount_path = format!("/stackable/secrets/{OPA_TLS_VOLUME_NAME}"); - - cb_prepare - .add_volume_mount(OPA_TLS_VOLUME_NAME, &opa_tls_mount_path) - .context(AddVolumeMountSnafu)?; + // Add OPA TLS certs if configured + if let Some((tls_secret_class, tls_mount_path)) = + trino_opa_config.as_ref().and_then(|opa_config| { + opa_config + .tls_secret_class + .as_ref() + .zip(opa_config.tls_mount_path()) + }) + { + cb_prepare + .add_volume_mount(OPA_TLS_VOLUME_NAME, &tls_mount_path) + .context(AddVolumeMountSnafu)?; - let opa_tls_volume = VolumeBuilder::new(OPA_TLS_VOLUME_NAME) - .ephemeral( - SecretOperatorVolumeSourceBuilder::new(opa_tls_secret_class) - .build() - .context(TlsCertSecretClassVolumeBuildSnafu)?, - ) - .build(); + let opa_tls_volume = VolumeBuilder::new(OPA_TLS_VOLUME_NAME) + .ephemeral( + SecretOperatorVolumeSourceBuilder::new(tls_secret_class) + .build() + .context(TlsCertSecretClassVolumeBuildSnafu)?, + ) + .build(); - pod_builder - .add_volume(opa_tls_volume) - .context(AddVolumeSnafu)?; - } + pod_builder + .add_volume(opa_tls_volume) + .context(AddVolumeSnafu)?; } // fault tolerant execution S3 credentials and other resources