diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fcaa0c3..89935b7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. ### Added - Default stackableVersion to operator version. It is recommended to remove `spec.image.stackableVersion` from your custom resources ([#493]). +- Configuration overrides for the JVM security properties, such as DNS caching ([#497]). ### Changed @@ -15,6 +16,7 @@ All notable changes to this project will be documented in this file. [#493]: https://github.com/stackabletech/nifi-operator/pull/493 [#494]: https://github.com/stackabletech/nifi-operator/pull/494 +[#497]: https://github.com/stackabletech/nifi-operator/pull/497 ## [23.7.0] - 2023-07-14 diff --git a/deploy/config-spec/properties.yaml b/deploy/config-spec/properties.yaml index 6c969f50..1fcb04f3 100644 --- a/deploy/config-spec/properties.yaml +++ b/deploy/config-spec/properties.yaml @@ -2,4 +2,41 @@ version: 0.1.0 spec: units: [] -properties: [] +properties: + - property: + propertyNames: + - name: "networkaddress.cache.ttl" + kind: + type: "file" + file: "security.properties" + datatype: + type: "integer" + min: "0" + recommendedValues: + - fromVersion: "0.0.0" + value: "30" + roles: + - name: "node" + required: true + asOfVersion: "0.0.0" + comment: "TTL for successfully resolved domain names." + description: "TTL for successfully resolved domain names." + + - property: + propertyNames: + - name: "networkaddress.cache.negative.ttl" + kind: + type: "file" + file: "security.properties" + datatype: + type: "integer" + min: "0" + recommendedValues: + - fromVersion: "0.0.0" + value: "0" + roles: + - name: "node" + required: true + asOfVersion: "0.0.0" + comment: "TTL for host names that cannot be resolved." + description: "TTL for host names that cannot be resolved." diff --git a/deploy/helm/nifi-operator/configs/properties.yaml b/deploy/helm/nifi-operator/configs/properties.yaml index 6c969f50..1fcb04f3 100644 --- a/deploy/helm/nifi-operator/configs/properties.yaml +++ b/deploy/helm/nifi-operator/configs/properties.yaml @@ -2,4 +2,41 @@ version: 0.1.0 spec: units: [] -properties: [] +properties: + - property: + propertyNames: + - name: "networkaddress.cache.ttl" + kind: + type: "file" + file: "security.properties" + datatype: + type: "integer" + min: "0" + recommendedValues: + - fromVersion: "0.0.0" + value: "30" + roles: + - name: "node" + required: true + asOfVersion: "0.0.0" + comment: "TTL for successfully resolved domain names." + description: "TTL for successfully resolved domain names." + + - property: + propertyNames: + - name: "networkaddress.cache.negative.ttl" + kind: + type: "file" + file: "security.properties" + datatype: + type: "integer" + min: "0" + recommendedValues: + - fromVersion: "0.0.0" + value: "0" + roles: + - name: "node" + required: true + asOfVersion: "0.0.0" + comment: "TTL for host names that cannot be resolved." + description: "TTL for host names that cannot be resolved." diff --git a/docs/modules/nifi/pages/usage_guide/configuration-environment-overrides.adoc b/docs/modules/nifi/pages/usage_guide/configuration-environment-overrides.adoc index 41847013..7c342d99 100644 --- a/docs/modules/nifi/pages/usage_guide/configuration-environment-overrides.adoc +++ b/docs/modules/nifi/pages/usage_guide/configuration-environment-overrides.adoc @@ -7,23 +7,49 @@ This will lead to cluster malfunction. == Configuration Overrides -Apache NiFi runtime configuration is stored in the files bootstrap.conf and nifi.properties. -The `configOverrides` block enables you to customize parameters in these files. +Apache NiFi runtime configuration is stored in several files listed below. The `configOverrides` block enables you to customize parameters in these files. The complete list of the configuration options can be found in the https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#system_properties[Apache NiFi documentation]. -Overrides are key, value pairs defined under a NiFi configuration file such as `bootstrap.conf` or `nifi.properties`. They must match the names values as expected by NiFi. In the example below, a property `nifi.flow.configuration.archive.enabled` is being explicitly set to 'false', overriding the default value. +The following files can be edited directly via the `configOverrides` mechanism: + +- `bootstrap.conf` +- `nifi.properties` +- `state-management.xml` +- `security.properties` + +Overrides are key, value pairs defined under one of the configuration files from the list above. They must match the names values as expected by NiFi. In the example below, a property `nifi.flow.configuration.archive.enabled` is being explicitly set to 'false', overriding the default value. The following snippet shows how to disable workflow file backups in the NifiCluster definition: [source,yaml] ---- -configOverrides: - nifi.properties: - nifi.flow.configuration.archive.enabled: false + nodes: + configOverrides: + nifi.properties: + nifi.flow.configuration.archive.enabled: false ---- WARNING: Please be aware that by overriding config settings in this section you have a very high risk of breaking things, because the product does not behave the way the Stackable Operator for Apache NiFi expects it to behave anymore. +=== The security.properties file + +The `security.properties` file is used to configure JVM security properties. It is very seldom that users need to tweak any of these, but there is one use-case that stands out, and that users need to be aware of: the JVM DNS cache. + +The JVM manages it's own cache of successfully resolved host names as well as a cache of host names that cannot be resolved. Some products of the Stackable platform are very sensible to the contents of these caches and their performance is heavily affected by them. As of version 1.21.0 Apache Nifi performs poorly if the positive cache is disabled. To cache resolved host names, and thus increase the performance your Nifi cluster, you can configure the TTL of entries in the positive cache like this: + +[source,yaml] +---- + nodes: + configOverrides: + security.properties: + networkaddress.cache.ttl: "30" + networkaddress.cache.negative.ttl: "0" +---- + +NOTE: The operator configures DNS caching by default as shown in the example above. + +For details on the JVM security see https://docs.oracle.com/en/java/javase/11/security/java-security-overview1.html + == Environment Variables Environment variables can be (over)written by adding the `envOverrides` property. diff --git a/rust/operator-binary/src/config.rs b/rust/operator-binary/src/config.rs index f4480ab4..07663c7a 100644 --- a/rust/operator-binary/src/config.rs +++ b/rust/operator-binary/src/config.rs @@ -19,9 +19,12 @@ use std::{ }; use strum::{Display, EnumIter}; +pub const NIFI_CONFIG_DIRECTORY: &str = "/stackable/nifi/conf"; + pub const NIFI_BOOTSTRAP_CONF: &str = "bootstrap.conf"; pub const NIFI_PROPERTIES: &str = "nifi.properties"; pub const NIFI_STATE_MANAGEMENT_XML: &str = "state-management.xml"; +pub const JVM_SECURITY_PROPERTIES_FILE: &str = "security.properties"; // Keep some overhead for NiFi volumes, since cleanup is an asynchronous process that can stall active jobs const STORAGE_PROVENANCE_UTILIZATION_FACTOR: f32 = 0.9; @@ -143,6 +146,11 @@ pub fn build_bootstrap_conf( // Please see https://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_adminserver_config for configuration options. java_args.push("-Dzookeeper.admin.enableServer=false".to_string()); + // JVM security properties include especially TTL values for the positive and negative DNS caches. + java_args.push(format!( + "-Djava.security.properties={NIFI_CONFIG_DIRECTORY}/{JVM_SECURITY_PROPERTIES_FILE}" + )); + // add java args bootstrap.extend( java_args @@ -626,6 +634,7 @@ pub fn validated_product_config( PropertyNameKind::File(NIFI_BOOTSTRAP_CONF.to_string()), PropertyNameKind::File(NIFI_PROPERTIES.to_string()), PropertyNameKind::File(NIFI_STATE_MANAGEMENT_XML.to_string()), + PropertyNameKind::File(JVM_SECURITY_PROPERTIES_FILE.to_string()), PropertyNameKind::Env, ], role.clone(), diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index a90d86b6..1d664066 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -38,7 +38,9 @@ use stackable_operator::{ }, labels::{role_group_selector_labels, role_selector_labels, ObjectLabels}, logging::controller::ReconcilerError, - product_config::{types::PropertyNameKind, ProductConfigManager}, + product_config::{ + types::PropertyNameKind, writer::to_java_properties_string, ProductConfigManager, + }, product_logging::{ self, spec::{ @@ -65,8 +67,8 @@ use stackable_nifi_crd::{ use crate::config::{ build_bootstrap_conf, build_nifi_properties, build_state_management_xml, - validated_product_config, NifiRepository, NIFI_BOOTSTRAP_CONF, NIFI_PROPERTIES, - NIFI_STATE_MANAGEMENT_XML, + validated_product_config, NifiRepository, JVM_SECURITY_PROPERTIES_FILE, NIFI_BOOTSTRAP_CONF, + NIFI_CONFIG_DIRECTORY, NIFI_PROPERTIES, NIFI_STATE_MANAGEMENT_XML, }; use crate::product_logging::{extend_role_group_config_map, resolve_vector_aggregator_address}; use crate::{config, OPERATOR_NAME}; @@ -214,6 +216,14 @@ pub enum Error { BuildRbacResources { source: stackable_operator::error::Error, }, + #[snafu(display( + "failed to serialize [{JVM_SECURITY_PROPERTIES_FILE}] for {}", + rolegroup + ))] + JvmSecurityPoperties { + source: stackable_operator::product_config::writer::PropertiesWriterError, + rolegroup: String, + }, } type Result = std::result::Result; @@ -571,6 +581,16 @@ async fn build_node_rolegroup_config_map( let (login_identity_provider_xml, authorizers_xml) = resolved_auth_conf.get_auth_config(); + let jvm_sec_props: BTreeMap> = rolegroup_config + .get(&PropertyNameKind::File( + JVM_SECURITY_PROPERTIES_FILE.to_string(), + )) + .cloned() + .unwrap_or_default() + .into_iter() + .map(|(k, v)| (k, Some(v))) + .collect(); + let mut cm_builder = ConfigMapBuilder::new(); cm_builder @@ -620,7 +640,15 @@ async fn build_node_rolegroup_config_map( ) .add_data(NIFI_STATE_MANAGEMENT_XML, build_state_management_xml()) .add_data("login-identity-providers.xml", login_identity_provider_xml) - .add_data("authorizers.xml", authorizers_xml); + .add_data("authorizers.xml", authorizers_xml) + .add_data( + JVM_SECURITY_PROPERTIES_FILE, + to_java_properties_string(jvm_sec_props.iter()).with_context(|_| { + JvmSecurityPopertiesSnafu { + rolegroup: rolegroup.role_group.clone(), + } + })?, + ); extend_role_group_config_map( rolegroup, @@ -857,7 +885,7 @@ async fn build_node_rolegroup_statefulset( ) .add_volume_mount("conf", "/conf") .add_volume_mount(KEYSTORE_VOLUME_NAME, KEYSTORE_NIFI_CONTAINER_MOUNT) - .add_volume_mount("activeconf", "/stackable/nifi/conf") + .add_volume_mount("activeconf", NIFI_CONFIG_DIRECTORY) .add_volume_mount("sensitiveproperty", "/stackable/sensitiveproperty") .add_volume_mount("log", STACKABLE_LOG_DIR) .resources( @@ -902,7 +930,7 @@ async fn build_node_rolegroup_statefulset( &NifiRepository::State.repository(), &NifiRepository::State.mount_path(), ) - .add_volume_mount("activeconf", "/stackable/nifi/conf") + .add_volume_mount("activeconf", NIFI_CONFIG_DIRECTORY) .add_volume_mount("log-config", STACKABLE_LOG_CONFIG_DIR) .add_volume_mount("log", STACKABLE_LOG_DIR) .add_container_port(HTTPS_PORT_NAME, HTTPS_PORT.into())