-
-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Support hot-reloading for security configuration files #130
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
base: main
Are you sure you want to change the base?
Changes from all commits
28b1f27
e5d2574
75d3683
12f20b1
86eb855
e7fa7be
c730d83
8000c6d
a7dfe3c
bcd1480
0c51fd2
dd4c2f2
b03ba92
9d4680b
334d42f
3eef786
9ca72d2
9d130e7
d3698d4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 { | ||
|
Comment on lines
-212
to
+216
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Enable security to trigger the creation of the security ConfigMap. |
||
| 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"), | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<ConfigMap> { | ||
| pub fn build_maybe_discovery_config_map(&self) -> Option<ConfigMap> { | ||
| 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<ConfigMap> { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The security settings which are defined by value, are now written to a dedicated (role-wide) ConfigMap instead of the role group ConfigMaps. This security ConfigMap is then excluded from the restart controller. |
||
| 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<PodDisruptionBudget> { | ||
| 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 `<cluster_name>-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(); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The operator creates now a ConfigMap named
<cluster-name>-security-config, see the upgrade guide. Therefore, another name is used here.