Skip to content

Commit ffa0585

Browse files
committed
add tls secret class to crd
1 parent c489b44 commit ffa0585

8 files changed

Lines changed: 101 additions & 17 deletions

File tree

deploy/helm/opensearch-operator/crds/crds.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ spec:
2525
spec:
2626
description: A OpenSearch cluster stacklet. This resource is managed by the Stackable operator for OpenSearch. Find more information on how to use it and the resources that the operator generates in the [operator documentation](https://docs.stackable.tech/home/nightly/opensearch/).
2727
properties:
28+
clusterConfig:
29+
properties:
30+
tls:
31+
properties:
32+
secretClass:
33+
default: tls
34+
description: 'Only affects client connections. This setting controls: - If TLS encryption is used at all - Which cert the servers should use to authenticate themselves against the client'
35+
type: string
36+
type: object
37+
required:
38+
- tls
39+
type: object
2840
clusterOperation:
2941
default:
3042
reconciliationPaused: false
@@ -461,6 +473,7 @@ spec:
461473
- roleGroups
462474
type: object
463475
required:
476+
- clusterConfig
464477
- image
465478
- nodes
466479
type: object

rust/operator-binary/src/controller.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use validate::validate;
2828
use crate::{
2929
crd::{
3030
NodeRoles,
31-
v1alpha1::{self},
31+
v1alpha1::{self, OpenSearchClusterConfig},
3232
},
3333
framework::{
3434
ClusterName, ControllerName, HasNamespace, HasObjectName, HasUid, IsLabelValue,
@@ -132,6 +132,7 @@ pub struct ValidatedCluster {
132132
pub name: ClusterName,
133133
pub namespace: String,
134134
pub uid: String,
135+
pub cluster_config: OpenSearchClusterConfig,
135136
pub role_config: GenericRoleConfig,
136137
// "validated" means that labels are valid and no ugly rolegroup name broke them
137138
pub role_group_configs: BTreeMap<RoleGroupName, OpenSearchRoleGroupConfig>,

rust/operator-binary/src/controller/build/job_builder.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,33 +66,34 @@ impl<'a> JobBuilder<'a> {
6666

6767
let args = [
6868
"plugins/opensearch-security/tools/securityadmin.sh".to_string(),
69+
"--hostname".to_string(),
70+
self.opensearch_master_fqdn(),
71+
"--configdir".to_string(),
72+
"config/opensearch-security/".to_string(),
6973
"-cacert".to_string(),
7074
"/stackable/tls-client/ca.crt".to_string(),
7175
"-cert".to_string(),
7276
"/stackable/tls-client/tls.crt".to_string(),
7377
"-key".to_string(),
7478
"/stackable/tls-client/tls.key".to_string(),
75-
"--hostname".to_string(),
76-
self.opensearch_master_fqdn(),
77-
"--configdir".to_string(),
78-
"config/opensearch-security/".to_string(),
7979
];
80+
8081
let mut cb = ContainerBuilder::new(RUN_SECURITYADMIN_CONTAINER_NAME)
8182
.expect("should be a valid container name");
8283
let container = cb
8384
.image_from_product_image(&product_image)
8485
.command(vec!["sh".to_string(), "-c".to_string()])
8586
.args(vec![args.join(" ")])
8687
// The VolumeMount for the secret operator key store certificates
87-
.add_volume_mounts([
88+
.add_volume_mounts(vec![
8889
VolumeMount {
89-
mount_path: RUN_SECURITYADMIN_CERT_VOLUME_MOUNT.to_owned(),
90-
name: RUN_SECURITYADMIN_CERT_VOLUME_NAME.to_owned(),
90+
mount_path: SECURITY_CONFIG_VOLUME_MOUNT.to_owned(),
91+
name: SECURITY_CONFIG_VOLUME_NAME.to_owned(),
9192
..VolumeMount::default()
9293
},
9394
VolumeMount {
94-
mount_path: SECURITY_CONFIG_VOLUME_MOUNT.to_owned(),
95-
name: SECURITY_CONFIG_VOLUME_NAME.to_owned(),
95+
mount_path: RUN_SECURITYADMIN_CERT_VOLUME_MOUNT.to_owned(),
96+
name: RUN_SECURITYADMIN_CERT_VOLUME_NAME.to_owned(),
9697
..VolumeMount::default()
9798
},
9899
])
@@ -106,7 +107,6 @@ impl<'a> JobBuilder<'a> {
106107
.build(),
107108
)
108109
.build();
109-
110110
let pod_template = PodTemplateSpec {
111111
metadata: Some(metadata.clone()),
112112
spec: Some(PodSpec {
@@ -128,6 +128,7 @@ impl<'a> JobBuilder<'a> {
128128
},
129129
build_tls_volume(
130130
RUN_SECURITYADMIN_CERT_VOLUME_NAME,
131+
&self.cluster.cluster_config.tls.secret_class,
131132
Vec::<String>::new(),
132133
SecretFormat::TlsPem,
133134
&Duration::from_days_unchecked(15),

rust/operator-binary/src/controller/build/node_config.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,10 @@ mod tests {
258258
use super::*;
259259
use crate::{
260260
controller::ValidatedOpenSearchConfig,
261-
crd::NodeRoles,
261+
crd::{
262+
NodeRoles,
263+
v1alpha1::{OpenSearchClusterConfig, OpenSearchTls},
264+
},
262265
framework::{ClusterName, ProductVersion, role_utils::GenericProductSpecificCommonConfig},
263266
};
264267

@@ -275,6 +278,11 @@ mod tests {
275278
.expect("should be a valid ClusterName"),
276279
namespace: "default".to_owned(),
277280
uid: "0b1e30e6-326e-4c1a-868d-ad6598b49e8b".to_owned(),
281+
cluster_config: OpenSearchClusterConfig {
282+
tls: OpenSearchTls {
283+
secret_class: "my-tls-secret-class".to_owned(),
284+
},
285+
},
278286
role_config: GenericRoleConfig::default(),
279287
role_group_configs: BTreeMap::new(),
280288
};

rust/operator-binary/src/controller/validate.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ use super::{
1313
ValidatedOpenSearchConfig,
1414
};
1515
use crate::{
16-
crd::v1alpha1::{self, OpenSearchConfig, OpenSearchConfigFragment},
16+
crd::v1alpha1::{
17+
self, OpenSearchClusterConfig, OpenSearchConfig, OpenSearchConfigFragment, OpenSearchTls,
18+
},
1719
framework::{
18-
ClusterName,
20+
ClusterName, TlsSecretClassName,
1921
role_utils::{GenericProductSpecificCommonConfig, RoleGroupConfig, with_validated_config},
2022
},
2123
};
@@ -41,6 +43,9 @@ pub enum Error {
4143
#[snafu(display("failed to set role-group name"))]
4244
ParseRoleGroupName { source: crate::framework::Error },
4345

46+
#[snafu(display("failed to set tls secret class"))]
47+
ParseTlsSecretClassName { source: crate::framework::Error },
48+
4449
#[snafu(display("fragment validation failure"))]
4550
ValidateOpenSearchConfig {
4651
source: stackable_operator::config::fragment::ValidationError,
@@ -70,6 +75,8 @@ pub fn validate(
7075
let product_version = ProductVersion::from_str(cluster.spec.image.product_version())
7176
.context(ParseProductVersionSnafu)?;
7277

78+
let validated_cluster_config = validate_cluster_config(cluster.spec.cluster_config.clone())?;
79+
7380
let mut role_group_configs = BTreeMap::new();
7481
for (raw_role_group_name, role_group_config) in &cluster.spec.nodes.role_groups {
7582
let role_group_name =
@@ -88,11 +95,24 @@ pub fn validate(
8895
name: cluster_name,
8996
namespace,
9097
uid,
98+
cluster_config: validated_cluster_config,
9199
role_config: cluster.spec.nodes.role_config.clone(),
92100
role_group_configs,
93101
})
94102
}
95103

104+
fn validate_cluster_config(
105+
cluster_config: OpenSearchClusterConfig,
106+
) -> Result<OpenSearchClusterConfig> {
107+
validate_tls_config(&cluster_config.tls)?;
108+
Ok(cluster_config)
109+
}
110+
111+
fn validate_tls_config(tls_config: &OpenSearchTls) -> Result<()> {
112+
TlsSecretClassName::from_str(&tls_config.secret_class).context(ParseTlsSecretClassNameSnafu)?;
113+
Ok(())
114+
}
115+
96116
fn validate_role_group_config(
97117
context_names: &ContextNames,
98118
cluster_name: &ClusterName,

rust/operator-binary/src/crd/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use crate::framework::{
3131
};
3232

3333
const DEFAULT_LISTENER_CLASS: &str = "cluster-internal";
34+
const TLS_DEFAULT_SECRET_CLASS: &str = "tls";
3435

3536
#[versioned(version(name = "v1alpha1"))]
3637
pub mod versioned {
@@ -57,6 +58,9 @@ pub mod versioned {
5758
// no doc string - see ProductImage struct
5859
pub image: ProductImage,
5960

61+
// no doc string - see ProductImage struct
62+
pub cluster_config: OpenSearchClusterConfig,
63+
6064
// no doc string - see ClusterOperation struct
6165
#[serde(default)]
6266
pub cluster_operation: ClusterOperation,
@@ -66,6 +70,23 @@ pub mod versioned {
6670
Role<OpenSearchConfigFragment, GenericRoleConfig, GenericProductSpecificCommonConfig>,
6771
}
6872

73+
#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
74+
#[serde(rename_all = "camelCase")]
75+
pub struct OpenSearchClusterConfig {
76+
pub tls: OpenSearchTls,
77+
}
78+
79+
#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
80+
#[serde(rename_all = "camelCase")]
81+
pub struct OpenSearchTls {
82+
/// Only affects client connections.
83+
/// This setting controls:
84+
/// - If TLS encryption is used at all
85+
/// - Which cert the servers should use to authenticate themselves against the client
86+
#[serde(default = "tls_secret_class_default")]
87+
pub secret_class: String,
88+
}
89+
6990
// The possible node roles are by default the built-in roles and the search role, see
7091
// https://github.com/opensearch-project/OpenSearch/blob/3.0.0/server/src/main/java/org/opensearch/cluster/node/DiscoveryNode.java#L609-L614.
7192
//
@@ -243,6 +264,18 @@ impl v1alpha1::OpenSearchConfig {
243264
}
244265
}
245266

267+
impl Default for v1alpha1::OpenSearchTls {
268+
fn default() -> Self {
269+
v1alpha1::OpenSearchTls {
270+
secret_class: tls_secret_class_default(),
271+
}
272+
}
273+
}
274+
275+
fn tls_secret_class_default() -> String {
276+
TLS_DEFAULT_SECRET_CLASS.to_string()
277+
}
278+
246279
#[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Serialize)]
247280
pub struct NodeRoles(Vec<v1alpha1::NodeRole>);
248281

rust/operator-binary/src/framework.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ pub enum Error {
3838
#[allow(dead_code)]
3939
pub const MAX_OBJECT_NAME_LENGTH: usize = 253;
4040

41+
#[allow(dead_code)]
42+
pub const MAX_ANNOTATION_LENGTH: usize = 253;
43+
4144
/// Has a name that can be used as a DNS subdomain name as defined in RFC 1123.
4245
/// Most resource types, e.g. a Pod, require such a compliant name.
4346
pub trait HasObjectName {
@@ -172,7 +175,11 @@ attributed_string_type! {
172175
is_object_name,
173176
is_valid_label_value
174177
}
175-
178+
attributed_string_type! {
179+
TlsSecretClassName,
180+
"The TLS SecretClass name",
181+
(max_length = MAX_ANNOTATION_LENGTH - 30)
182+
}
176183
#[cfg(test)]
177184
mod tests {
178185
use std::str::FromStr;

rust/operator-binary/src/framework/builder/volume.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ use stackable_operator::{
66

77
pub fn build_tls_volume(
88
volume_name: &str,
9+
tls_secret_class_name: &str,
910
service_scopes: impl IntoIterator<Item = impl AsRef<str>>,
1011
secret_format: SecretFormat,
1112
requested_secret_lifetime: &Duration,
1213
listener_scope: Option<&str>,
1314
) -> Volume {
1415
let mut secret_volume_source_builder =
15-
SecretOperatorVolumeSourceBuilder::new("tls".to_string());
16+
SecretOperatorVolumeSourceBuilder::new(tls_secret_class_name);
1617

1718
for scope in service_scopes {
1819
secret_volume_source_builder.with_service_scope(scope.as_ref());
@@ -28,7 +29,7 @@ pub fn build_tls_volume(
2829
.with_format(secret_format)
2930
.with_auto_tls_cert_lifetime(*requested_secret_lifetime)
3031
.build()
31-
.expect("volume should be built"),
32+
.expect("volume should be built without parse errors"),
3233
)
3334
.build()
3435
}

0 commit comments

Comments
 (0)