Skip to content

Commit c77ac69

Browse files
committed
feat: Allow adding entries to the OpenSearch keystore
1 parent efb3509 commit c77ac69

File tree

13 files changed

+385
-75
lines changed

13 files changed

+385
-75
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ All notable changes to this project will be documented in this file.
77
### Added
88

99
- Add the role group as a node attribute ([#63]).
10+
- Allow adding entries to the OpenSearch keystore ([#76]).
1011

1112
[#63]: https://github.com/stackabletech/opensearch-operator/pull/63
13+
[#76]: https://github.com/stackabletech/opensearch-operator/pull/76
1214

1315
## [25.11.0] - 2025-11-07
1416

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,40 @@ spec:
2929
generates in the [operator documentation](https://docs.stackable.tech/home/nightly/opensearch/).
3030
properties:
3131
clusterConfig:
32-
default: {}
32+
default:
33+
keystore: []
3334
description: Configuration that applies to all roles and role groups
3435
properties:
36+
keystore:
37+
default: []
38+
description: Entries to add to the OpenSearch keystore.
39+
items:
40+
properties:
41+
key:
42+
description: Key in the OpenSearch keystore
43+
type: string
44+
secretKeyRef:
45+
description: Reference to the Secret containing the value which will be stored in the OpenSearch keystore
46+
properties:
47+
key:
48+
description: Key in the Secret that contains the value
49+
maxLength: 253
50+
minLength: 1
51+
type: string
52+
name:
53+
description: Name of the Secret
54+
maxLength: 253
55+
minLength: 1
56+
type: string
57+
required:
58+
- key
59+
- name
60+
type: object
61+
required:
62+
- key
63+
- secretKeyRef
64+
type: object
65+
type: array
3566
vectorAggregatorConfigMapName:
3667
description: |-
3768
Name of the Vector aggregator [discovery ConfigMap](https://docs.stackable.tech/home/nightly/concepts/service_discovery).
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
= Add entries to the OpenSearch Keystore
2+
:description: Add entries to the OpenSearch Keystore
3+
4+
The OpenSearch keystore provides secure storage for sensitive configuration settings such as credentials and API keys.
5+
You can populate the keystore by referencing Secrets from in your OpenSearch configuration.
6+
7+
[source,yaml]
8+
----
9+
---
10+
apiVersion: opensearch.stackable.tech/v1alpha1
11+
kind: OpenSearchCluster
12+
metadata:
13+
name: opensearch
14+
spec:
15+
clusterConfig:
16+
keystore:
17+
- key: s3.client.default.access_key # <1>
18+
secretKeyRef:
19+
name: s3-credentials # <2>
20+
key: accessKey # <3>
21+
- key: s3.client.default.secret_key
22+
secretKeyRef:
23+
name: s3-credentials
24+
key: secretKey
25+
nodes:
26+
roleGroups:
27+
default:
28+
replicas: 1
29+
---
30+
apiVersion: v1
31+
kind: Secret
32+
metadata:
33+
name: s3-credentials
34+
stringData:
35+
accessKey: my-access-key
36+
secretKey: my-secret-key
37+
----
38+
<1> The key in the OpenSearch keystore which corresponds to a setting in OpenSearch (e.g. `s3.client.default.access_key`).
39+
<2> The name of the Secret containing the value
40+
<3> The key within that Secret

docs/modules/opensearch/partials/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
** xref:opensearch:usage-guide/logging.adoc[]
1111
** xref:opensearch:usage-guide/opensearch-dashboards.adoc[]
1212
** xref:opensearch:usage-guide/scaling.adoc[]
13+
** xref:opensearch:usage-guide/keystore.adoc[]
1314
** xref:opensearch:usage-guide/operations/index.adoc[]
1415
*** xref:opensearch:usage-guide/operations/cluster-operations.adoc[]
1516
*** xref:opensearch:usage-guide/operations/pod-placement.adoc[]

rust/operator-binary/src/controller.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use validate::validate;
3030
use crate::{
3131
crd::{
3232
NodeRoles,
33-
v1alpha1::{self},
33+
v1alpha1::{self, OpenSearchKeystore},
3434
},
3535
framework::{
3636
ClusterName, ControllerName, HasName, HasUid, ListenerClassName, NameIsValidLabelValue,
@@ -166,9 +166,11 @@ pub struct ValidatedCluster {
166166
pub uid: Uid,
167167
pub role_config: GenericRoleConfig,
168168
pub role_group_configs: BTreeMap<RoleGroupName, OpenSearchRoleGroupConfig>,
169+
pub keystores: Vec<OpenSearchKeystore>,
169170
}
170171

171172
impl ValidatedCluster {
173+
#[allow(clippy::too_many_arguments)]
172174
pub fn new(
173175
image: ResolvedProductImage,
174176
product_version: ProductVersion,
@@ -177,6 +179,7 @@ impl ValidatedCluster {
177179
uid: impl Into<Uid>,
178180
role_config: GenericRoleConfig,
179181
role_group_configs: BTreeMap<RoleGroupName, OpenSearchRoleGroupConfig>,
182+
keystores: Vec<OpenSearchKeystore>,
180183
) -> Self {
181184
let uid = uid.into();
182185
ValidatedCluster {
@@ -193,6 +196,7 @@ impl ValidatedCluster {
193196
uid,
194197
role_config,
195198
role_group_configs,
199+
keystores,
196200
}
197201
}
198202

@@ -378,10 +382,13 @@ mod tests {
378382
use super::{Context, OpenSearchRoleGroupConfig, ValidatedCluster, ValidatedLogging};
379383
use crate::{
380384
controller::{OpenSearchNodeResources, ValidatedOpenSearchConfig},
381-
crd::{NodeRoles, v1alpha1},
385+
crd::{
386+
NodeRoles,
387+
v1alpha1::{self, OpenSearchKeystore, SecretKeyRef},
388+
},
382389
framework::{
383390
ClusterName, ListenerClassName, NamespaceName, OperatorName, ProductVersion,
384-
RoleGroupName, builder::pod::container::EnvVarSet,
391+
RoleGroupName, SecretKey, SecretName, builder::pod::container::EnvVarSet,
385392
product_logging::framework::ValidatedContainerLogConfigChoice,
386393
role_utils::GenericProductSpecificCommonConfig,
387394
},
@@ -494,6 +501,13 @@ mod tests {
494501
),
495502
]
496503
.into(),
504+
vec![OpenSearchKeystore {
505+
key: "Keystore1".to_string(),
506+
secret_key_ref: SecretKeyRef {
507+
name: SecretName::from_str_unsafe("my-keystore-secret"),
508+
key: SecretKey::from_str_unsafe("my-keystore-file"),
509+
},
510+
}],
497511
)
498512
}
499513

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,14 @@ mod tests {
7777
ContextNames, OpenSearchNodeResources, OpenSearchRoleGroupConfig, ValidatedCluster,
7878
ValidatedContainerLogConfigChoice, ValidatedLogging, ValidatedOpenSearchConfig,
7979
},
80-
crd::{NodeRoles, v1alpha1},
80+
crd::{
81+
NodeRoles,
82+
v1alpha1::{self, OpenSearchKeystore, SecretKeyRef},
83+
},
8184
framework::{
8285
ClusterName, ControllerName, ListenerClassName, NamespaceName, OperatorName,
83-
ProductName, ProductVersion, RoleGroupName, builder::pod::container::EnvVarSet,
84-
role_utils::GenericProductSpecificCommonConfig,
86+
ProductName, ProductVersion, RoleGroupName, SecretKey, SecretName,
87+
builder::pod::container::EnvVarSet, role_utils::GenericProductSpecificCommonConfig,
8588
},
8689
};
8790

@@ -191,6 +194,13 @@ mod tests {
191194
),
192195
]
193196
.into(),
197+
vec![OpenSearchKeystore {
198+
key: "Keystore1".to_string(),
199+
secret_key_ref: SecretKeyRef {
200+
name: SecretName::from_str_unsafe("my-keystore-secret"),
201+
key: SecretKey::from_str_unsafe("my-keystore-file"),
202+
},
203+
}],
194204
)
195205
}
196206

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ pub const CONFIG_OPTION_PLUGINS_SECURITY_NODES_DN: &str = "plugins.security.node
6262
pub const CONFIG_OPTION_PLUGINS_SECURITY_SSL_HTTP_ENABLED: &str =
6363
"plugins.security.ssl.http.enabled";
6464

65+
const DEFAULT_OPENSEARCH_HOME: &str = "/stackable/opensearch";
66+
6567
/// Configuration of an OpenSearch node based on the cluster and role-group configuration
6668
pub struct NodeConfig {
6769
cluster: ValidatedCluster,
@@ -272,6 +274,23 @@ impl NodeConfig {
272274
String::new()
273275
}
274276
}
277+
278+
/// Return content of the `OPENSEARCH_HOME` environment variable from envOverrides or default to `DEFAULT_OPENSEARCH_HOME`
279+
pub fn opensearch_home(&self) -> String {
280+
self.environment_variables()
281+
.get(&EnvVarName::from_str_unsafe("OPENSEARCH_HOME"))
282+
.and_then(|env_var| env_var.value.clone())
283+
.unwrap_or(DEFAULT_OPENSEARCH_HOME.to_owned())
284+
}
285+
286+
/// Return content of the `OPENSEARCH_PATH_CONF` environment variable from envOverrides or default to `OPENSEARCH_HOME/config`
287+
pub fn opensearch_path_conf(&self) -> String {
288+
let opensearch_home = self.opensearch_home();
289+
self.environment_variables()
290+
.get(&EnvVarName::from_str_unsafe("OPENSEARCH_PATH_CONF"))
291+
.and_then(|env_var| env_var.value.clone())
292+
.unwrap_or(format!("{opensearch_home}/config"))
293+
}
275294
}
276295

277296
#[cfg(test)]
@@ -383,6 +402,7 @@ mod tests {
383402
role_group_config.clone(),
384403
)]
385404
.into(),
405+
vec![],
386406
);
387407

388408
NodeConfig::new(

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ mod tests {
305305
role_group_config.clone(),
306306
)]
307307
.into(),
308+
vec![],
308309
);
309310

310311
RoleBuilder::new(cluster, context_names)

0 commit comments

Comments
 (0)