diff --git a/CHANGELOG.md b/CHANGELOG.md index 9175fbe..da7495e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,16 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added + +- Support hot-reloading of security configuration files ([#130]). + ### Changed - Document Helm deployed RBAC permissions and remove unnecessary permissions ([#129]). [#129]: https://github.com/stackabletech/opensearch-operator/pull/129 +[#130]: https://github.com/stackabletech/opensearch-operator/pull/130 ## [26.3.0] - 2026-03-16 diff --git a/docs/modules/opensearch/examples/getting_started/opensearch-security-config.yaml b/docs/modules/opensearch/examples/getting_started/opensearch-security-config.yaml deleted file mode 100644 index dde39f1..0000000 --- a/docs/modules/opensearch/examples/getting_started/opensearch-security-config.yaml +++ /dev/null @@ -1,87 +0,0 @@ ---- -apiVersion: v1 -kind: Secret -metadata: - name: opensearch-security-config -stringData: - action_groups.yml: | - --- - _meta: - type: actiongroups - config_version: 2 - allowlist.yml: | - --- - _meta: - type: allowlist - config_version: 2 - config: - enabled: false - audit.yml: | - --- - _meta: - type: audit - config_version: 2 - config: - enabled: false - config.yml: | - --- - _meta: - type: config - config_version: 2 - config: - dynamic: - authc: - basic_internal_auth_domain: - description: Authenticate via HTTP Basic against internal users database - http_enabled: true - transport_enabled: true - order: 1 - http_authenticator: - type: basic - challenge: true - authentication_backend: - type: intern - authz: {} - internal_users.yml: | - --- - _meta: - type: internalusers - config_version: 2 - admin: - hash: $2y$10$xRtHZFJ9QhG9GcYhRpAGpufCZYsk//nxsuel5URh0GWEBgmiI4Q/e - reserved: true - backend_roles: - - admin - description: OpenSearch admin user - kibanaserver: - hash: $2y$10$vPgQ/6ilKDM5utawBqxoR.7euhVQ0qeGl8mPTeKhmFT475WUDrfQS - reserved: true - description: OpenSearch Dashboards user - nodes_dn.yml: | - --- - _meta: - type: nodesdn - config_version: 2 - roles.yml: | - --- - _meta: - type: roles - config_version: 2 - roles_mapping.yml: | - --- - _meta: - type: rolesmapping - config_version: 2 - all_access: - reserved: false - backend_roles: - - admin - kibana_server: - reserved: true - users: - - kibanaserver - tenants.yml: | - --- - _meta: - type: tenants - config_version: 2 diff --git a/docs/modules/opensearch/pages/usage-guide/monitoring.adoc b/docs/modules/opensearch/pages/usage-guide/monitoring.adoc index c628c44..b741e2b 100644 --- a/docs/modules/opensearch/pages/usage-guide/monitoring.adoc +++ b/docs/modules/opensearch/pages/usage-guide/monitoring.adoc @@ -29,10 +29,10 @@ To make the metrics accessible for all users, especially Prometheus, anonymous a ---- --- apiVersion: v1 -kind: Secret +kind: ConfigMap metadata: - name: opensearch-security-config -stringData: + name: custom-opensearch-security-config +data: config.yml: | --- _meta: diff --git a/docs/modules/opensearch/pages/usage-guide/security.adoc b/docs/modules/opensearch/pages/usage-guide/security.adoc index ab8076e..0fa1007 100644 --- a/docs/modules/opensearch/pages/usage-guide/security.adoc +++ b/docs/modules/opensearch/pages/usage-guide/security.adoc @@ -144,6 +144,8 @@ spec: If this role group is not defined, it will be created by the operator. +Settings managed by the operator are hot-reloaded when changed, i.e. without pod restarts. + == TLS TLS is also managed by the OpenSearch security plugin, therefore TLS is only available if the security plugin was not disabled. diff --git a/docs/modules/opensearch/pages/usage-guide/upgrade.adoc b/docs/modules/opensearch/pages/usage-guide/upgrade.adoc index 2b8485f..bb3adb3 100644 --- a/docs/modules/opensearch/pages/usage-guide/upgrade.adoc +++ b/docs/modules/opensearch/pages/usage-guide/upgrade.adoc @@ -1,6 +1,14 @@ = SDP upgrade notes :description: Instructions for upgrading the SDP versions. +== Upgrade from SDP 26.3 to 26.7 + +=== Dedicated ConfigMap for security settings + +The security settings defined in the cluster specification are now stored in a separate ConfigMap named `-security-config`. +If you used this name for your custom security configuration, then you must rename it. +Otherwise the operator will override it. + == Upgrade from SDP 25.11 to 26.3 When upgrading the OpenSearch operator from SDP 25.11 to 26.3, you may encounter several warnings and errors in the operator logs. diff --git a/rust/operator-binary/src/controller/build.rs b/rust/operator-binary/src/controller/build.rs index 5be50f3..479decc 100644 --- a/rust/operator-binary/src/controller/build.rs +++ b/rust/operator-binary/src/controller/build.rs @@ -33,9 +33,12 @@ pub fn build(names: &ContextNames, cluster: ValidatedCluster) -> KubernetesResou listeners.push(role_group_builder.build_listener()); } - if let Some(discovery_config_map) = role_builder.build_discovery_config_map() { + if let Some(discovery_config_map) = role_builder.build_maybe_discovery_config_map() { config_maps.push(discovery_config_map); } + if let Some(security_config_map) = role_builder.build_maybe_security_config_map() { + config_maps.push(security_config_map); + } services.push(role_builder.build_seed_nodes_service()); listeners.push(role_builder.build_discovery_service_listener()); @@ -90,7 +93,7 @@ mod tests { role_utils::GenericProductSpecificCommonConfig, types::{ common::Port, - kubernetes::{Hostname, ListenerClassName, NamespaceName}, + kubernetes::{Hostname, ListenerClassName, NamespaceName, SecretClassName}, operator::{ ClusterName, ControllerName, OperatorName, ProductName, ProductVersion, RoleGroupName, @@ -134,7 +137,8 @@ mod tests { "my-opensearch", "my-opensearch-nodes-cluster-manager", "my-opensearch-nodes-coordinating", - "my-opensearch-nodes-data" + "my-opensearch-nodes-data", + "my-opensearch-security-config" ], extract_resource_names(&resources.config_maps) ); @@ -209,7 +213,11 @@ mod tests { ), ] .into(), - ValidatedSecurity::Disabled, + ValidatedSecurity::ManagedByApi { + settings: v1alpha1::SecuritySettings::default(), + tls_server_secret_class: None, + tls_internal_secret_class: SecretClassName::from_str_unsafe("tls"), + }, vec![], Some(ValidatedDiscoveryEndpoint { hostname: Hostname::from_str_unsafe("1.2.3.4"), diff --git a/rust/operator-binary/src/controller/build/role_builder.rs b/rust/operator-binary/src/controller/build/role_builder.rs index 385e0fc..2c470f5 100644 --- a/rust/operator-binary/src/controller/build/role_builder.rs +++ b/rust/operator-binary/src/controller/build/role_builder.rs @@ -1,6 +1,6 @@ //! Builder for role resources -use std::str::FromStr; +use std::{collections::BTreeMap, str::FromStr}; use stackable_operator::{ builder::meta::ObjectMetaBuilder, @@ -23,8 +23,9 @@ use stackable_operator::{ use crate::{ controller::{ ContextNames, HTTP_PORT, HTTP_PORT_NAME, TRANSPORT_PORT, TRANSPORT_PORT_NAME, - ValidatedCluster, build::role_group_builder::RoleGroupBuilder, + ValidatedCluster, ValidatedSecurity, build::role_group_builder::RoleGroupBuilder, }, + crd::v1alpha1, framework::{ NameIsValidLabelValue, builder::{ @@ -166,7 +167,7 @@ impl<'a> RoleBuilder<'a> { /// The discovery endpoint is derived from the status of the discovery service Listener. If the /// status is not set yet, the reconciliation process will occur again once the Listener status /// is updated, leading to the eventual creation of the discovery ConfigMap. - pub fn build_discovery_config_map(&self) -> Option { + pub fn build_maybe_discovery_config_map(&self) -> Option { let discovery_endpoint = self.cluster.discovery_endpoint.as_ref()?; let metadata = self.common_metadata(discovery_config_map_name(&self.cluster.name)); @@ -204,6 +205,40 @@ impl<'a> RoleBuilder<'a> { }) } + /// Builds the [`ConfigMap`] containing the security configuration files that were defined by + /// value. + /// + /// Returns `None` if the security plugin is disabled or all configuration files are + /// references. + pub fn build_maybe_security_config_map(&self) -> Option { + let metadata = self.common_metadata(security_config_map_name(&self.cluster.name)); + + let mut data = BTreeMap::new(); + + if let ValidatedSecurity::ManagedByApi { settings, .. } + | ValidatedSecurity::ManagedByOperator { settings, .. } = &self.cluster.security + { + for file_type in settings { + if let v1alpha1::SecuritySettingsFileTypeContent::Value( + v1alpha1::SecuritySettingsFileTypeContentValue { value }, + ) = &file_type.content + { + data.insert(file_type.filename.to_owned(), value.to_string()); + } + } + } + + if data.is_empty() { + None + } else { + Some(ConfigMap { + metadata, + data: Some(data), + ..ConfigMap::default() + }) + } + } + /// Builds a [`PodDisruptionBudget`] used by all role-groups pub fn build_pdb(&self) -> Option { let pdb_config = &self.cluster.role_config.common.pod_disruption_budget; @@ -297,6 +332,20 @@ fn discovery_config_map_name(cluster_name: &ClusterName) -> ConfigMapName { ConfigMapName::from_str(cluster_name.as_ref()).expect("should be a valid ConfigMap name") } +pub fn security_config_map_name(cluster_name: &ClusterName) -> ConfigMapName { + const SUFFIX: &str = "-security-config"; + + // compile-time checks + const _: () = assert!( + ClusterName::MAX_LENGTH + SUFFIX.len() <= ConfigMapName::MAX_LENGTH, + "The string `-security-config` must not exceed the limit of ConfigMap names." + ); + let _ = ClusterName::IS_RFC_1123_SUBDOMAIN_NAME; + + ConfigMapName::from_str(&format!("{}{SUFFIX}", cluster_name.as_ref())) + .expect("should be a valid ConfigMap name") +} + pub fn discovery_service_listener_name(cluster_name: &ClusterName) -> ListenerName { // compile-time checks const _: () = assert!( @@ -640,12 +689,13 @@ mod tests { } #[test] - fn test_build_discovery_config_map() { + fn test_build_maybe_discovery_config_map() { let context_names = context_names(); let role_builder = role_builder(&context_names); - let discovery_config_map = serde_json::to_value(role_builder.build_discovery_config_map()) - .expect("should be serializable"); + let discovery_config_map = + serde_json::to_value(role_builder.build_maybe_discovery_config_map()) + .expect("should be serializable"); assert_eq!( json!({ @@ -683,6 +733,56 @@ mod tests { ); } + #[test] + fn test_build_maybe_security_config_map() { + let context_names = context_names(); + let role_builder = role_builder(&context_names); + + let security_config_map = + serde_json::to_value(role_builder.build_maybe_security_config_map()) + .expect("should be serializable"); + + assert_eq!( + json!({ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": { + "labels": { + "app.kubernetes.io/component": "nodes", + "app.kubernetes.io/instance": "my-opensearch-cluster", + "app.kubernetes.io/managed-by": "opensearch.stackable.tech_opensearchcluster", + "app.kubernetes.io/name": "opensearch", + "app.kubernetes.io/version": "3.4.0", + "stackable.tech/vendor": "Stackable", + }, + "name": "my-opensearch-cluster-security-config", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "opensearch.stackable.tech/v1alpha1", + "controller": true, + "kind": "OpenSearchCluster", + "name": "my-opensearch-cluster", + "uid": "0b1e30e6-326e-4c1a-868d-ad6598b49e8b", + }, + ], + }, + "data": { + "action_groups.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"actiongroups\"}}", + "allowlist.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"allowlist\"},\"config\":{\"enabled\":false}}", + "audit.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"audit\"},\"config\":{\"enabled\":false}}", + "config.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"config\"},\"config\":{\"dynamic\":{\"authc\":{},\"authz\":{},\"http\":{}}}}", + "internal_users.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"internalusers\"}}", + "nodes_dn.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"nodesdn\"}}", + "roles.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"roles\"}}", + "roles_mapping.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"rolesmapping\"}}", + "tenants.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"tenants\"}}", + }, + }), + security_config_map + ); + } + #[test] fn test_build_pdb() { let context_names = context_names(); diff --git a/rust/operator-binary/src/controller/build/role_group_builder.rs b/rust/operator-binary/src/controller/build/role_group_builder.rs index 975efcd..113a4b8 100644 --- a/rust/operator-binary/src/controller/build/role_group_builder.rs +++ b/rust/operator-binary/src/controller/build/role_group_builder.rs @@ -1,6 +1,9 @@ //! Builder for role group resources -use std::{collections::BTreeMap, str::FromStr}; +use std::{ + collections::{BTreeMap, BTreeSet}, + str::FromStr, +}; use stackable_operator::{ builder::{ @@ -47,8 +50,11 @@ use crate::{ controller::{ ContextNames, HTTP_PORT, HTTP_PORT_NAME, OpenSearchRoleGroupConfig, TRANSPORT_PORT, TRANSPORT_PORT_NAME, ValidatedCluster, ValidatedNodeRole, ValidatedSecurity, - build::product_logging::config::{ - MAX_OPENSEARCH_SERVER_LOG_FILES_SIZE, vector_config_file_extra_env_vars, + build::{ + product_logging::config::{ + MAX_OPENSEARCH_SERVER_LOG_FILES_SIZE, vector_config_file_extra_env_vars, + }, + role_builder::security_config_map_name, }, }, crd::{ExtendedSecuritySettingsFileType, v1alpha1}, @@ -67,8 +73,8 @@ use crate::{ role_group_utils::ResourceNames, types::{ kubernetes::{ - ListenerName, PersistentVolumeClaimName, SecretClassName, ServiceAccountName, - ServiceName, VolumeName, + ConfigMapName, ListenerName, PersistentVolumeClaimName, SecretClassName, + SecretName, ServiceAccountName, ServiceName, VolumeName, }, operator::RoleGroupName, }, @@ -294,19 +300,6 @@ impl<'a> RoleGroupBuilder<'a> { data.insert(VECTOR_CONFIG_FILE.to_owned(), vector_config_file_content()); } - if let RoleGroupSecurityMode::Initializing { settings, .. } - | RoleGroupSecurityMode::Managing { settings, .. } = &self.security_mode - { - for file_type in settings { - if let v1alpha1::SecuritySettingsFileTypeContent::Value( - v1alpha1::SecuritySettingsFileTypeContentValue { value }, - ) = &file_type.content - { - data.insert(file_type.filename.to_owned(), value.to_string()); - } - } - } - ConfigMap { metadata, data: Some(data), @@ -319,6 +312,7 @@ impl<'a> RoleGroupBuilder<'a> { let metadata = self .common_metadata(self.resource_names.stateful_set_name()) .with_label(RESTART_CONTROLLER_ENABLED_LABEL.to_owned()) + .with_annotations(self.restarter_ignore_annotations()) .build(); let template = self.build_pod_template(); @@ -383,6 +377,42 @@ impl<'a> RoleGroupBuilder<'a> { } } + fn restarter_ignore_annotations(&self) -> Annotations { + let (security_settings_config_maps, security_settings_secrets) = + self.security_settings_resource_names(); + + let restarter_ignore_config_maps_annotations = security_settings_config_maps + .iter() + .enumerate() + .map(|(i, config_map_name)| { + ( + format!("restarter.stackable.tech/ignore-configmap.{i}"), + config_map_name.to_string(), + ) + }); + let restarter_ignore_secrets_annotations = security_settings_secrets + .iter() + .enumerate() + .map(|(i, secret_name)| { + ( + format!("restarter.stackable.tech/ignore-secret.{i}"), + secret_name.to_string(), + ) + }); + + // The expectation is tested in the unit tests. + Annotations::try_from( + restarter_ignore_config_maps_annotations + .chain(restarter_ignore_secrets_annotations) + .collect::>(), + ) + .expect( + "should contain only valid annotations because the annotation keys are statically \ + defined apart from the index number and the names of ConfigMaps and Secrets are valid \ + annotation values.", + ) + } + /// Builds the [`PodTemplateSpec`] for the [`StatefulSet`] of the role group fn build_pod_template(&self) -> PodTemplateSpec { let mut node_role_labels = Labels::new(); @@ -725,7 +755,10 @@ impl<'a> RoleGroupBuilder<'a> { }; if let RoleGroupSecurityMode::Initializing { settings, .. } = &self.security_mode { - volume_mounts.extend(self.security_config_volume_mounts(settings)); + // Mount the security configuration files using `subPath`, because the configuration + // files are only used for initializing the security index and hot-reloading is not + // required. + volume_mounts.extend(self.security_config_volume_mounts(settings, true)); }; if !self.cluster.keystores.is_empty() { @@ -788,23 +821,45 @@ impl<'a> RoleGroupBuilder<'a> { /// Builds the security settings volume mounts for the [`v1alpha1::Container::OpenSearch`] /// container or the [`v1alpha1::Container::UpdateSecurityConfig`] container + /// + /// If `use_sub_path` is set to `true`, then the configuration files are directly mounted via + /// `subPath` into the opensearch-security configuration directory. If it is set to `false`, + /// then they are mounted into sub directories of the opensearch-security configuration + /// directory without using `subPath`. Files mounted via `subPath` are not updated on changes + /// in the ConfigMap or Secret volume. Therefore, hot-reloading works only without `subPath`, + /// but links from the configuration directory into the sub directories are required. fn security_config_volume_mounts( &self, settings: &v1alpha1::SecuritySettings, + use_sub_path: bool, ) -> Vec { let mut volume_mounts = vec![]; let opensearch_path_conf = self.node_config.opensearch_path_conf(); for file_type in settings { - volume_mounts.push(VolumeMount { - mount_path: format!( + let mount_path; + let sub_path; + + if use_sub_path { + mount_path = format!( "{opensearch_path_conf}/opensearch-security/{filename}", filename = file_type.filename.to_owned() - ), + ); + sub_path = Some(file_type.filename.to_owned()); + } else { + mount_path = format!( + "{opensearch_path_conf}/opensearch-security/{file_type}", + file_type = file_type.id + ); + sub_path = None; + } + + volume_mounts.push(VolumeMount { + mount_path, name: Self::security_settings_file_type_volume_name(&file_type).to_string(), read_only: Some(true), - sub_path: Some(file_type.filename.to_owned()), + sub_path, ..VolumeMount::default() }); } @@ -877,7 +932,10 @@ impl<'a> RoleGroupBuilder<'a> { ..VolumeMount::default() }, ]; - volume_mounts.extend(self.security_config_volume_mounts(settings)); + + // Mount the security configuration files without using `subPath`, so that hot-reloading + // works. + volume_mounts.extend(self.security_config_volume_mounts(settings, false)); let mut env_vars = EnvVarSet::new() .with_value( @@ -1105,6 +1163,39 @@ impl<'a> RoleGroupBuilder<'a> { }] } + fn security_settings_resource_names(&self) -> (BTreeSet, BTreeSet) { + let mut config_map_names = BTreeSet::new(); + let mut secret_names = BTreeSet::new(); + + if let RoleGroupSecurityMode::Initializing { settings, .. } + | RoleGroupSecurityMode::Managing { settings, .. } = &self.security_mode + { + for file_type in settings { + match &file_type.content { + v1alpha1::SecuritySettingsFileTypeContent::Value(_) => { + config_map_names.insert(security_config_map_name(&self.cluster.name)); + } + v1alpha1::SecuritySettingsFileTypeContent::ValueFrom( + v1alpha1::SecuritySettingsFileTypeContentValueFrom::ConfigMapKeyRef( + v1alpha1::ConfigMapKeyRef { name, .. }, + ), + ) => { + config_map_names.insert(name.clone()); + } + v1alpha1::SecuritySettingsFileTypeContent::ValueFrom( + v1alpha1::SecuritySettingsFileTypeContentValueFrom::SecretKeyRef( + v1alpha1::SecretKeyRef { name, .. }, + ), + ) => { + secret_names.insert(name.clone()); + } + }; + } + } + + (config_map_names, secret_names) + } + /// Builds the security settings volumes for the [`PodTemplateSpec`] /// It is not checked if these volumes are required in this role group. fn build_security_settings_volumes( @@ -1125,7 +1216,7 @@ impl<'a> RoleGroupBuilder<'a> { mode: Some(0o660), path: file_type.filename.to_owned(), }]), - name: self.resource_names.role_group_config_map().to_string(), + name: security_config_map_name(&self.cluster.name).to_string(), ..Default::default() }), ..Volume::default() @@ -1628,12 +1719,8 @@ mod tests { } #[rstest] - #[case::security_mode_initializing(TestSecurityMode::Initializing)] - #[case::security_mode_managing(TestSecurityMode::Managing)] - #[case::security_mode_participating(TestSecurityMode::Participating)] - #[case::security_mode_disabled(TestSecurityMode::Disabled)] - fn test_build_config_map(#[case] security_mode: TestSecurityMode) { - let cluster = validated_cluster(security_mode); + fn test_build_config_map() { + let cluster = validated_cluster(TestSecurityMode::Disabled); let context_names = context_names(); let role_group_builder = role_group_builder(&cluster, &context_names); @@ -1649,26 +1736,6 @@ mod tests { // vector.yaml is a static file and does not have to be repeated here. config_map["data"]["vector.yaml"].take(); - let expected_data = match security_mode { - TestSecurityMode::Initializing | TestSecurityMode::Managing => json!({ - "action_groups.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"actiongroups\"}}", - "allowlist.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"allowlist\"},\"config\":{\"enabled\":false}}", - "audit.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"audit\"},\"config\":{\"enabled\":false}}", - "config.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"config\"},\"config\":{\"dynamic\":{\"authc\":{},\"authz\":{},\"http\":{}}}}", - "log4j2.properties": null, - "nodes_dn.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"nodesdn\"}}", - "opensearch.yml": null, - "roles_mapping.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"rolesmapping\"}}", - "tenants.yml": "{\"_meta\":{\"config_version\":2,\"type\":\"tenants\"}}", - "vector.yaml": null - }), - TestSecurityMode::Participating | TestSecurityMode::Disabled => json!({ - "log4j2.properties": null, - "opensearch.yml": null, - "vector.yaml": null - }), - }; - assert_eq!( json!({ "apiVersion": "v1", @@ -1695,7 +1762,11 @@ mod tests { } ] }, - "data": expected_data + "data": { + "log4j2.properties": null, + "opensearch.yml": null, + "vector.yaml": null + } }), config_map ); @@ -1714,6 +1785,15 @@ mod tests { let stateful_set = serde_json::to_value(role_group_builder.build_stateful_set()) .expect("should be serializable"); + let expected_annotations = match security_mode { + TestSecurityMode::Initializing | TestSecurityMode::Managing => json!({ + "restarter.stackable.tech/ignore-configmap.0": "my-opensearch-cluster-security-config", + "restarter.stackable.tech/ignore-configmap.1": "opensearch-security-config", + "restarter.stackable.tech/ignore-secret.0": "opensearch-security-config", + }), + TestSecurityMode::Disabled | TestSecurityMode::Participating => json!({}), + }; + let expected_opensearch_container_volume_mounts = match security_mode { TestSecurityMode::Initializing => json!([ { @@ -2297,58 +2377,49 @@ mod tests { "name": "log", }, { - "mountPath": "/stackable/opensearch/config/opensearch-security/action_groups.yml", + "mountPath": "/stackable/opensearch/config/opensearch-security/actiongroups", "name": "security-config-file-actiongroups", "readOnly": true, - "subPath": "action_groups.yml", }, { - "mountPath": "/stackable/opensearch/config/opensearch-security/allowlist.yml", + "mountPath": "/stackable/opensearch/config/opensearch-security/allowlist", "name": "security-config-file-allowlist", "readOnly": true, - "subPath": "allowlist.yml", }, { - "mountPath": "/stackable/opensearch/config/opensearch-security/audit.yml", + "mountPath": "/stackable/opensearch/config/opensearch-security/audit", "name": "security-config-file-audit", "readOnly": true, - "subPath": "audit.yml", }, { - "mountPath": "/stackable/opensearch/config/opensearch-security/config.yml", + "mountPath": "/stackable/opensearch/config/opensearch-security/config", "name": "security-config-file-config", "readOnly": true, - "subPath": "config.yml", }, { - "mountPath": "/stackable/opensearch/config/opensearch-security/internal_users.yml", + "mountPath": "/stackable/opensearch/config/opensearch-security/internalusers", "name": "security-config-file-internalusers", "readOnly": true, - "subPath": "internal_users.yml", }, { - "mountPath": "/stackable/opensearch/config/opensearch-security/nodes_dn.yml", + "mountPath": "/stackable/opensearch/config/opensearch-security/nodesdn", "name": "security-config-file-nodesdn", "readOnly": true, - "subPath": "nodes_dn.yml", }, { - "mountPath": "/stackable/opensearch/config/opensearch-security/roles.yml", + "mountPath": "/stackable/opensearch/config/opensearch-security/roles", "name": "security-config-file-roles", "readOnly": true, - "subPath": "roles.yml", }, { - "mountPath": "/stackable/opensearch/config/opensearch-security/roles_mapping.yml", + "mountPath": "/stackable/opensearch/config/opensearch-security/rolesmapping", "name": "security-config-file-rolesmapping", "readOnly": true, - "subPath": "roles_mapping.yml", }, { - "mountPath": "/stackable/opensearch/config/opensearch-security/tenants.yml", + "mountPath": "/stackable/opensearch/config/opensearch-security/tenants", "name": "security-config-file-tenants", "readOnly": true, - "subPath": "tenants.yml", }, ], }); @@ -2546,7 +2617,7 @@ mod tests { "path": "action_groups.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-actiongroups" }, @@ -2559,7 +2630,7 @@ mod tests { "path": "allowlist.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-allowlist" }, @@ -2572,7 +2643,7 @@ mod tests { "path": "audit.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-audit" }, @@ -2585,7 +2656,7 @@ mod tests { "path": "config.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-config" }, @@ -2611,7 +2682,7 @@ mod tests { "path": "nodes_dn.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-nodesdn" }, @@ -2637,7 +2708,7 @@ mod tests { "path": "roles_mapping.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-rolesmapping" }, @@ -2650,7 +2721,7 @@ mod tests { "path": "tenants.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-tenants" }, @@ -2756,7 +2827,7 @@ mod tests { "path": "action_groups.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-actiongroups" }, @@ -2769,7 +2840,7 @@ mod tests { "path": "allowlist.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-allowlist" }, @@ -2782,7 +2853,7 @@ mod tests { "path": "audit.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-audit" }, @@ -2795,7 +2866,7 @@ mod tests { "path": "config.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-config" }, @@ -2821,7 +2892,7 @@ mod tests { "path": "nodes_dn.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-nodesdn" }, @@ -2847,7 +2918,7 @@ mod tests { "path": "roles_mapping.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-rolesmapping" }, @@ -2860,7 +2931,7 @@ mod tests { "path": "tenants.yml" } ], - "name": "my-opensearch-cluster-nodes-default" + "name": "my-opensearch-cluster-security-config" }, "name": "security-config-file-tenants" }, @@ -3037,6 +3108,7 @@ mod tests { "apiVersion": "apps/v1", "kind": "StatefulSet", "metadata": { + "annotations": expected_annotations, "labels": { "app.kubernetes.io/component": "nodes", "app.kubernetes.io/instance": "my-opensearch-cluster", diff --git a/rust/operator-binary/src/controller/build/scripts/update-security-config.sh b/rust/operator-binary/src/controller/build/scripts/update-security-config.sh index d84a550..926433f 100644 --- a/rust/operator-binary/src/controller/build/scripts/update-security-config.sh +++ b/rust/operator-binary/src/controller/build/scripts/update-security-config.sh @@ -1,7 +1,51 @@ #!/usr/bin/env bash +# +# Required environment variables: +# - OPENSEARCH_PATH_CONF +# - POD_NAME +# - MANAGE_ACTIONGROUPS +# - MANAGE_ALLOWLIST +# - MANAGE_AUDIT +# - MANAGE_CONFIG +# - MANAGE_INTERNALUSERS +# - MANAGE_NODESDN +# - MANAGE_ROLES +# - MANAGE_ROLESMAPPING +# - MANAGE_TENANTS set -u -o pipefail +VECTOR_CONTROL_DIR=/stackable/log/_vector +SECURITY_CONFIG_DIR="$OPENSEARCH_PATH_CONF/opensearch-security" + +declare -a CONFIG_FILETYPES=( + actiongroups + allowlist + audit + config + internalusers + nodesdn + roles + rolesmapping + tenants +) + +declare -A CONFIG_FILENAME=( + [actiongroups]=action_groups.yml + [allowlist]=allowlist.yml + [audit]=audit.yml + [config]=config.yml + [internalusers]=internal_users.yml + [nodesdn]=nodes_dn.yml + [roles]=roles.yml + [rolesmapping]=roles_mapping.yml + [tenants]=tenants.yml +) + +declare -a managed_filetypes + +last_applied_config_hashes="" + function log () { level="$1" message="$2" @@ -10,6 +54,12 @@ function log () { echo "$timestamp [$level] $message" } +function debug () { + message="$*" + + log DEBUG "$message" +} + function info () { message="$*" @@ -22,33 +72,96 @@ function warn () { log WARN "$message" } -function wait_seconds () { +# Return the configuration file in SECURITY_CONFIG_DIR for the given file type +function config_file () { + filetype="$1" + + echo "$SECURITY_CONFIG_DIR/${CONFIG_FILENAME[$filetype]}" +} + +# Create a link for every configuration file in SECURITY_CONFIG_DIR +function symlink_config_files () { + for filetype in "${CONFIG_FILETYPES[@]}" + do + ln --force --symbolic \ + "$SECURITY_CONFIG_DIR/$filetype/${CONFIG_FILENAME[$filetype]}" \ + "$(config_file "$filetype")" + done +} + +# Initialize the variable managed_filetypes +function initialize_managed_config_filetypes () { + for filetype in "${CONFIG_FILETYPES[@]}" + do + envvar="MANAGE_${filetype^^}" + if test "${!envvar}" = "true" + then + info "Watch managed configuration type \"$filetype\"." + managed_filetypes+=("$filetype") + else + info "Skip unmanaged configuration type \"$filetype\"." + fi + done +} + +# Calculate the hashes of the managed configuration files +function calculate_config_hashes () { + for filetype in "${managed_filetypes[@]}" + do + file=$(config_file "$filetype") + sha256sum "$file" + done +} + +function wait_seconds_or_shutdown () { seconds="$1" - if test "$seconds" = 0 - then - info "Wait until pod is restarted..." - else - info "Wait for $seconds seconds..." - fi + debug "Wait for $seconds seconds..." - if test ! -e /stackable/log/_vector/shutdown + if test ! -e "$VECTOR_CONTROL_DIR/shutdown" then - mkdir --parents /stackable/log/_vector inotifywait \ --quiet --quiet \ --timeout "$seconds" \ --event create \ - /stackable/log/_vector + "$VECTOR_CONTROL_DIR" fi - if test -e /stackable/log/_vector/shutdown + # Only the file named "shutdown" should be created in VECTOR_CONTROL_DIR. If another file is + # created instead, this function will return early; this is acceptable and has no adverse + # effects. + if test -e "$VECTOR_CONTROL_DIR/shutdown" then info "Shut down" exit 0 fi } +function wait_for_configuration_changes_or_shutdown () { + info "Wait for security configuration changes..." + + while test "$(calculate_config_hashes)" = "$last_applied_config_hashes" + do + wait_seconds_or_shutdown 10 + done + + info "Configuration change detected" +} + +function wait_for_shutdown () { + until test ! -e "$VECTOR_CONTROL_DIR/shutdown" + do + inotifywait \ + --quiet --quiet \ + --event create \ + "$VECTOR_CONTROL_DIR" + done + + info "Shut down" + exit 0 +} + +# Return if this pod is responsible for managing the security configuration or wait for shutdown function check_pod () { POD_INDEX="${POD_NAME##*-}" @@ -62,34 +175,36 @@ function check_pod () { "configuration. The security configuration is managed by" \ "the pod \"$MANAGING_POD\"." - wait_seconds 0 + wait_for_shutdown fi } +# Initialize the security index with all (managed and unmanaged) configuration files function initialize_security_index() { info "Initialize the security index." + last_applied_config_hashes=$(calculate_config_hashes) + until plugins/opensearch-security/tools/securityadmin.sh \ - --configdir "$OPENSEARCH_PATH_CONF/opensearch-security" \ + --configdir "$SECURITY_CONFIG_DIR" \ --disable-host-name-verification \ -cacert "$OPENSEARCH_PATH_CONF/tls/ca.crt" \ -cert "$OPENSEARCH_PATH_CONF/tls/tls.crt" \ -key "$OPENSEARCH_PATH_CONF/tls/tls.key" do warn "Initializing the security index failed." - wait_seconds 10 + wait_seconds_or_shutdown 10 done } -function update_config () { - filetype="$1" - filename="$2" +# Update the security index with the managed configuration files +function update_security_index () { + last_applied_config_hashes=$(calculate_config_hashes) - file="$OPENSEARCH_PATH_CONF/opensearch-security/$filename" + for filetype in "${managed_filetypes[@]}" + do + file=$(config_file "$filetype") - envvar="MANAGE_${filetype^^}" - if test "${!envvar}" = "true" - then info "Update managed configuration type \"$filetype\"." until plugins/opensearch-security/tools/securityadmin.sh \ @@ -101,14 +216,13 @@ function update_config () { -key "$OPENSEARCH_PATH_CONF/tls/tls.key" do warn "Updating \"$filetype\" in the security index failed." - wait_seconds 10 + wait_seconds_or_shutdown 10 done - else - info "Skip unmanaged configuration type \"$filetype\"." - fi + done } -function update_security_index() { +# Initialize or update the security index +function apply_configuration_files() { info "Check the status of the security index." STATUS_CODE=$(curl \ @@ -122,30 +236,26 @@ function update_security_index() { if test "$STATUS_CODE" = "200" then info "The security index is already initialized." - - update_config actiongroups action_groups.yml - update_config allowlist allowlist.yml - update_config audit audit.yml - update_config config config.yml - update_config internalusers internal_users.yml - update_config nodesdn nodes_dn.yml - update_config roles roles.yml - update_config rolesmapping roles_mapping.yml - update_config tenants tenants.yml + update_security_index elif test "$STATUS_CODE" = "404" then initialize_security_index else warn "Checking the security index failed." - wait_seconds 10 - check_security_index + wait_seconds_or_shutdown 10 + update_security_index fi } -check_pod +# Ensure that VECTOR_CONTROL_DIR exists, so that calls to inotifywait do not fail +mkdir --parents "$VECTOR_CONTROL_DIR" -update_security_index +check_pod +symlink_config_files +initialize_managed_config_filetypes -info "Wait for security configuration changes..." -# Wait until the pod is restarted due to a change of the Secret. -wait_seconds 0 +while true +do + apply_configuration_files + wait_for_configuration_changes_or_shutdown +done diff --git a/tests/templates/kuttl/security-config/11-assert.yaml b/tests/templates/kuttl/security-config/11-assert.yaml index 11166f9..a012754 100644 --- a/tests/templates/kuttl/security-config/11-assert.yaml +++ b/tests/templates/kuttl/security-config/11-assert.yaml @@ -23,6 +23,20 @@ apiVersion: apps/v1 kind: StatefulSet metadata: name: opensearch-nodes-security-config + annotations: + restarter.stackable.tech/ignore-configmap.0: opensearch-security-config + restarter.stackable.tech/ignore-configmap.1: security-config + restarter.stackable.tech/ignore-secret.0: security-config-file-internal-users + labels: + restarter.stackable.tech/enabled: "true" +spec: + template: + metadata: + annotations: + # configmap.restarter.stackable.tech/opensearch-nodes-security-config: / + configmap.restarter.stackable.tech/opensearch-security-config: changes-ignored + configmap.restarter.stackable.tech/security-config: changes-ignored + secret.restarter.stackable.tech/security-config-file-internal-users: changes-ignored status: readyReplicas: 1 replicas: 1 @@ -30,7 +44,7 @@ status: apiVersion: v1 kind: ConfigMap metadata: - name: opensearch-nodes-security-config + name: opensearch-security-config data: action_groups.yml: '{"_meta":{"config_version":2,"type":"actiongroups"}}' allowlist.yml: '{"_meta":{"config_version":2,"type":"allowlist"},"config":{"enabled":false}}' diff --git a/tests/templates/kuttl/security-config/21-assert.yaml b/tests/templates/kuttl/security-config/21-assert.yaml index bffbbbc..9cab8a4 100644 --- a/tests/templates/kuttl/security-config/21-assert.yaml +++ b/tests/templates/kuttl/security-config/21-assert.yaml @@ -6,7 +6,7 @@ timeout: 120 apiVersion: v1 kind: ConfigMap metadata: - name: opensearch-nodes-security-config + name: opensearch-security-config data: action_groups.yml: '{"_meta":{"config_version":2,"type":"actiongroups"}}' allowlist.yml: '{"_meta":{"config_version":2,"type":"allowlist"},"config":{"enabled":false}}' diff --git a/tests/templates/kuttl/smoke/10-assert.yaml.j2 b/tests/templates/kuttl/smoke/10-assert.yaml.j2 index ec38871..c2cd2a5 100644 --- a/tests/templates/kuttl/smoke/10-assert.yaml.j2 +++ b/tests/templates/kuttl/smoke/10-assert.yaml.j2 @@ -10,6 +10,8 @@ apiVersion: apps/v1 kind: StatefulSet metadata: name: opensearch-nodes-cluster-manager + annotations: + restarter.stackable.tech/ignore-configmap.0: opensearch-security-config labels: app.kubernetes.io/component: nodes app.kubernetes.io/instance: opensearch @@ -17,8 +19,8 @@ metadata: app.kubernetes.io/name: opensearch app.kubernetes.io/role-group: cluster-manager app.kubernetes.io/version: {{ test_scenario['values']['opensearch'].split(',')[0] }} - stackable.tech/vendor: Stackable restarter.stackable.tech/enabled: "true" + stackable.tech/vendor: Stackable generation: 1 # There should be no unneeded Pod restarts ownerReferences: - apiVersion: opensearch.stackable.tech/v1alpha1 @@ -38,6 +40,8 @@ spec: template: metadata: annotations: + # configmap.restarter.stackable.tech/opensearch-nodes-cluster-manager: / + configmap.restarter.stackable.tech/opensearch-security-config: changes-ignored kubectl.kubernetes.io/default-container: opensearch labels: app.kubernetes.io/component: nodes @@ -358,7 +362,7 @@ spec: - key: action_groups.yml mode: 432 path: action_groups.yml - name: opensearch-nodes-cluster-manager + name: opensearch-security-config name: security-config-file-actiongroups - configMap: defaultMode: 420 @@ -366,7 +370,7 @@ spec: - key: allowlist.yml mode: 432 path: allowlist.yml - name: opensearch-nodes-cluster-manager + name: opensearch-security-config name: security-config-file-allowlist - configMap: defaultMode: 420 @@ -374,7 +378,7 @@ spec: - key: audit.yml mode: 432 path: audit.yml - name: opensearch-nodes-cluster-manager + name: opensearch-security-config name: security-config-file-audit - configMap: defaultMode: 420 @@ -382,7 +386,7 @@ spec: - key: config.yml mode: 432 path: config.yml - name: opensearch-nodes-cluster-manager + name: opensearch-security-config name: security-config-file-config - configMap: defaultMode: 420 @@ -390,7 +394,7 @@ spec: - key: internal_users.yml mode: 432 path: internal_users.yml - name: opensearch-nodes-cluster-manager + name: opensearch-security-config name: security-config-file-internalusers - configMap: defaultMode: 420 @@ -398,7 +402,7 @@ spec: - key: nodes_dn.yml mode: 432 path: nodes_dn.yml - name: opensearch-nodes-cluster-manager + name: opensearch-security-config name: security-config-file-nodesdn - configMap: defaultMode: 420 @@ -406,7 +410,7 @@ spec: - key: roles.yml mode: 432 path: roles.yml - name: opensearch-nodes-cluster-manager + name: opensearch-security-config name: security-config-file-roles - configMap: defaultMode: 420 @@ -414,7 +418,7 @@ spec: - key: roles_mapping.yml mode: 432 path: roles_mapping.yml - name: opensearch-nodes-cluster-manager + name: opensearch-security-config name: security-config-file-rolesmapping - configMap: defaultMode: 420 @@ -422,7 +426,7 @@ spec: - key: tenants.yml mode: 432 path: tenants.yml - name: opensearch-nodes-cluster-manager + name: opensearch-security-config name: security-config-file-tenants volumeClaimTemplates: - apiVersion: v1 @@ -488,6 +492,8 @@ apiVersion: apps/v1 kind: StatefulSet metadata: name: opensearch-nodes-data + annotations: + restarter.stackable.tech/ignore-configmap.0: opensearch-security-config labels: app.kubernetes.io/component: nodes app.kubernetes.io/instance: opensearch @@ -495,8 +501,8 @@ metadata: app.kubernetes.io/name: opensearch app.kubernetes.io/role-group: data app.kubernetes.io/version: {{ test_scenario['values']['opensearch'].split(',')[0] }} - stackable.tech/vendor: Stackable restarter.stackable.tech/enabled: "true" + stackable.tech/vendor: Stackable generation: 1 # There should be no unneeded Pod restarts ownerReferences: - apiVersion: opensearch.stackable.tech/v1alpha1 @@ -516,6 +522,8 @@ spec: template: metadata: annotations: + # configmap.restarter.stackable.tech/opensearch-nodes-data: / + configmap.restarter.stackable.tech/opensearch-security-config: changes-ignored kubectl.kubernetes.io/default-container: opensearch labels: app.kubernetes.io/component: nodes @@ -834,7 +842,7 @@ spec: - key: action_groups.yml mode: 432 path: action_groups.yml - name: opensearch-nodes-data + name: opensearch-security-config name: security-config-file-actiongroups - configMap: defaultMode: 420 @@ -842,7 +850,7 @@ spec: - key: allowlist.yml mode: 432 path: allowlist.yml - name: opensearch-nodes-data + name: opensearch-security-config name: security-config-file-allowlist - configMap: defaultMode: 420 @@ -850,7 +858,7 @@ spec: - key: audit.yml mode: 432 path: audit.yml - name: opensearch-nodes-data + name: opensearch-security-config name: security-config-file-audit - configMap: defaultMode: 420 @@ -858,7 +866,7 @@ spec: - key: config.yml mode: 432 path: config.yml - name: opensearch-nodes-data + name: opensearch-security-config name: security-config-file-config - configMap: defaultMode: 420 @@ -866,7 +874,7 @@ spec: - key: internal_users.yml mode: 432 path: internal_users.yml - name: opensearch-nodes-data + name: opensearch-security-config name: security-config-file-internalusers - configMap: defaultMode: 420 @@ -874,7 +882,7 @@ spec: - key: nodes_dn.yml mode: 432 path: nodes_dn.yml - name: opensearch-nodes-data + name: opensearch-security-config name: security-config-file-nodesdn - configMap: defaultMode: 420 @@ -882,7 +890,7 @@ spec: - key: roles.yml mode: 432 path: roles.yml - name: opensearch-nodes-data + name: opensearch-security-config name: security-config-file-roles - configMap: defaultMode: 420 @@ -890,7 +898,7 @@ spec: - key: roles_mapping.yml mode: 432 path: roles_mapping.yml - name: opensearch-nodes-data + name: opensearch-security-config name: security-config-file-rolesmapping - configMap: defaultMode: 420 @@ -898,7 +906,7 @@ spec: - key: tenants.yml mode: 432 path: tenants.yml - name: opensearch-nodes-data + name: opensearch-security-config name: security-config-file-tenants volumeClaimTemplates: - apiVersion: v1 @@ -946,10 +954,9 @@ metadata: app.kubernetes.io/instance: opensearch app.kubernetes.io/managed-by: opensearch.stackable.tech_opensearchcluster app.kubernetes.io/name: opensearch - app.kubernetes.io/role-group: cluster-manager app.kubernetes.io/version: {{ test_scenario['values']['opensearch'].split(',')[0] }} stackable.tech/vendor: Stackable - name: opensearch-nodes-cluster-manager + name: opensearch-security-config ownerReferences: - apiVersion: opensearch.stackable.tech/v1alpha1 controller: true @@ -962,6 +969,28 @@ data: config.yml: '{"_meta":{"config_version":2,"type":"config"},"config":{"dynamic":{"authc":{"basic_internal_auth_domain":{"authentication_backend":{"type":"intern"},"description":"Authenticate via HTTP Basic against internal users database","http_authenticator":{"challenge":true,"type":"basic"},"http_enabled":true,"order":1,"transport_enabled":true}},"authz":{}}}}' internal_users.yml: '{"_meta":{"config_version":2,"type":"internalusers"},"admin":{"backend_roles":["admin"],"description":"OpenSearch admin user","hash":"$2y$10$xRtHZFJ9QhG9GcYhRpAGpufCZYsk//nxsuel5URh0GWEBgmiI4Q/e","reserved":true}}' nodes_dn.yml: '{"_meta":{"config_version":2,"type":"nodesdn"}}' + roles.yml: '{"_meta":{"config_version":2,"type":"roles"}}' + roles_mapping.yml: '{"_meta":{"config_version":2,"type":"rolesmapping"},"all_access":{"backend_roles":["admin"],"reserved":false}}' + tenants.yml: '{"_meta":{"config_version":2,"type":"tenants"}}' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/component: nodes + app.kubernetes.io/instance: opensearch + app.kubernetes.io/managed-by: opensearch.stackable.tech_opensearchcluster + app.kubernetes.io/name: opensearch + app.kubernetes.io/role-group: cluster-manager + app.kubernetes.io/version: {{ test_scenario['values']['opensearch'].split(',')[0] }} + stackable.tech/vendor: Stackable + name: opensearch-nodes-cluster-manager + ownerReferences: + - apiVersion: opensearch.stackable.tech/v1alpha1 + controller: true + kind: OpenSearchCluster + name: opensearch +data: opensearch.yml: |- cluster.name: "opensearch" cluster.routing.allocation.disk.threshold_enabled: "false" @@ -984,9 +1013,6 @@ data: plugins.security.ssl.transport.pemcert_filepath: "{{ test_scenario['values']['opensearch_home'] }}/config/tls/internal/tls.crt" plugins.security.ssl.transport.pemkey_filepath: "{{ test_scenario['values']['opensearch_home'] }}/config/tls/internal/tls.key" plugins.security.ssl.transport.pemtrustedcas_filepath: "{{ test_scenario['values']['opensearch_home'] }}/config/tls/internal/ca.crt" - roles.yml: '{"_meta":{"config_version":2,"type":"roles"}}' - roles_mapping.yml: '{"_meta":{"config_version":2,"type":"rolesmapping"},"all_access":{"backend_roles":["admin"],"reserved":false}}' - tenants.yml: '{"_meta":{"config_version":2,"type":"tenants"}}' --- apiVersion: v1 kind: ConfigMap @@ -1006,12 +1032,6 @@ metadata: kind: OpenSearchCluster name: opensearch data: - action_groups.yml: '{"_meta":{"config_version":2,"type":"actiongroups"}}' - allowlist.yml: '{"_meta":{"config_version":2,"type":"allowlist"},"config":{"enabled":false}}' - audit.yml: '{"_meta":{"config_version":2,"type":"audit"},"config":{"enabled":false}}' - config.yml: '{"_meta":{"config_version":2,"type":"config"},"config":{"dynamic":{"authc":{"basic_internal_auth_domain":{"authentication_backend":{"type":"intern"},"description":"Authenticate via HTTP Basic against internal users database","http_authenticator":{"challenge":true,"type":"basic"},"http_enabled":true,"order":1,"transport_enabled":true}},"authz":{}}}}' - internal_users.yml: '{"_meta":{"config_version":2,"type":"internalusers"},"admin":{"backend_roles":["admin"],"description":"OpenSearch admin user","hash":"$2y$10$xRtHZFJ9QhG9GcYhRpAGpufCZYsk//nxsuel5URh0GWEBgmiI4Q/e","reserved":true}}' - nodes_dn.yml: '{"_meta":{"config_version":2,"type":"nodesdn"}}' opensearch.yml: |- cluster.name: "opensearch" cluster.routing.allocation.disk.threshold_enabled: "false" @@ -1034,9 +1054,6 @@ data: plugins.security.ssl.transport.pemcert_filepath: "{{ test_scenario['values']['opensearch_home'] }}/config/tls/internal/tls.crt" plugins.security.ssl.transport.pemkey_filepath: "{{ test_scenario['values']['opensearch_home'] }}/config/tls/internal/tls.key" plugins.security.ssl.transport.pemtrustedcas_filepath: "{{ test_scenario['values']['opensearch_home'] }}/config/tls/internal/ca.crt" - roles.yml: '{"_meta":{"config_version":2,"type":"roles"}}' - roles_mapping.yml: '{"_meta":{"config_version":2,"type":"rolesmapping"},"all_access":{"backend_roles":["admin"],"reserved":false}}' - tenants.yml: '{"_meta":{"config_version":2,"type":"tenants"}}' --- apiVersion: v1 kind: Service