Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d45f8fb
wip: add run-securityadmin job
labrenbe Aug 14, 2025
c489b44
configure tls on run-securityadmin
labrenbe Aug 15, 2025
ffa0585
add tls secret class to crd
labrenbe Aug 19, 2025
aaa560f
Merge remote-tracking branch 'origin/main' into feat/run-securityadmi…
labrenbe Aug 19, 2025
4d7496c
add tls volume to sts
labrenbe Aug 20, 2025
7f805b8
add tls config to opensearch.yml
labrenbe Aug 21, 2025
c6db525
disable security demo install
labrenbe Aug 22, 2025
1c3e672
Merge remote-tracking branch 'origin/main' into feat/run-securityadmi…
labrenbe Oct 24, 2025
bbbdbb6
wip amend integration tests
labrenbe Oct 27, 2025
1aeb4db
Merge remote-tracking branch 'origin/main' into feat/tls-support
labrenbe Oct 27, 2025
ab42f5a
fix smoke test
labrenbe Oct 28, 2025
97681a3
restore properties file
labrenbe Oct 28, 2025
815d243
mount tls volume in default directory of official image
labrenbe Oct 28, 2025
95986a5
use tls feature in all integration tests
labrenbe Oct 28, 2025
910a58d
use OPENSEARCH_PATH_CONF for tls config
labrenbe Oct 28, 2025
9252b06
Merge remote-tracking branch 'origin/main' into feat/tls-support
labrenbe Oct 28, 2025
beb2aff
fix incorrectly resolved merge conflict
labrenbe Oct 28, 2025
383e358
Merge remote-tracking branch 'origin/main' into feat/tls-support
labrenbe Nov 4, 2025
25745d1
wip: adress feedback on pr
labrenbe Nov 6, 2025
bcb5542
Merge remote-tracking branch 'origin/main' into feat/tls-support
labrenbe Nov 6, 2025
8257b95
address feedback on PR
labrenbe Nov 13, 2025
bd86ebc
Merge remote-tracking branch 'origin/main' into feat/tls-support
labrenbe Nov 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion deploy/helm/opensearch-operator/crds/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,40 @@ spec:
generates in the [operator documentation](https://docs.stackable.tech/home/nightly/opensearch/).
properties:
clusterConfig:
default: {}
default:
tls:
httpSecretClass: tls
transportSecretClass: tls
description: Configuration that applies to all roles and role groups
properties:
tls:
default:
httpSecretClass: tls
transportSecretClass: tls
description: TLS configuration options for the REST API and internal communication (transport).
properties:
httpSecretClass:
default: tls
description: |-
Only affects client connections to the REST API.
This setting controls:
- If TLS encryption is used at all
- Which cert the servers should use to authenticate themselves against the client
maxLength: 253
minLength: 1
nullable: true
type: string
transportSecretClass:
default: tls
description: |-
Only affects internal communication (transport). Used for mutual verification between OpenSearch nodes.
This setting controls:
- Which cert the servers should use to authenticate themselves against other servers
- Which ca.crt to use when validating the other server
maxLength: 253
minLength: 1
type: string
type: object
vectorAggregatorConfigMapName:
description: |-
Name of the Vector aggregator [discovery ConfigMap](https://docs.stackable.tech/home/nightly/concepts/service_discovery).
Expand Down Expand Up @@ -303,6 +334,14 @@ spec:
type: string
nullable: true
type: array
requestedSecretLifetime:
description: |-
Request secret (currently only autoTls certificates) lifetime from the secret operator, e.g. `7d`, or `30d`.
This can be shortened by the `maxCertificateLifetime` setting on the SecretClass issuing the TLS certificate.

Defaults to 1d.
nullable: true
type: string
resources:
default:
cpu:
Expand Down Expand Up @@ -651,6 +690,14 @@ spec:
type: string
nullable: true
type: array
requestedSecretLifetime:
description: |-
Request secret (currently only autoTls certificates) lifetime from the secret operator, e.g. `7d`, or `30d`.
This can be shortened by the `maxCertificateLifetime` setting on the SecretClass issuing the TLS certificate.

Defaults to 1d.
nullable: true
type: string
resources:
default:
cpu:
Expand Down
55 changes: 55 additions & 0 deletions docs/modules/opensearch/pages/usage-guide/security.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
= Security
:description: Configure TLS encryption, authentication, and Open Policy Agent (OPA) authorization for Kafka with the Stackable Operator.

== TLS

The internal and client communication at the REST API can be encrypted with TLS. This requires the xref:secret-operator:index.adoc[Secret Operator] to be running in the Kubernetes cluster providing certificates.
The used certificates can be changed in a cluster-wide config. TLS encryption on the REST API may be disabled, while it is always enabled for the internal communication between nodes using the `transport` port.

[source,yaml]
----
---
apiVersion: opensearch.stackable.tech/v1alpha1
kind: OpenSearchCluster
metadata:
name: opensearch
spec:
image:
productVersion: 3.1.0
clusterConfig:
tls:
httpSecretClass: tls # <1>
transportSecretClass: opensearch-transport-tls # <2>
nodes:
config:
requestedSecretLifetime: 7d # <3>
roleGroups:
default:
replicas: 3
----
<1> The `spec.clusterConfig.tls.httpSecretClass` refers to the client-to-server encryption at the REST API. Defaults to the `tls` SecretClass and can be disabled by setting `httpSecretClass` to `null`.
<2> The `spec.clusterConfig.tls.transportSecretClass` refers to the internal encryption between OpenSearch nodes using mTLS (transport). Defaults to the `tls` SecretClass` and can't be disabled.
<3> The lifetime for autoTls certificates generated by the secret operator.
Only a lifetime up to the `maxCertificateLifetime` setting in the SecretClass is applied.

The `tls` secret is deployed from the xref:secret-operator:index.adoc[Secret Operator] and looks like this:

[source,yaml]
----
---
apiVersion: secrets.stackable.tech/v1alpha1
kind: SecretClass
metadata:
name: tls
spec:
backend:
autoTls:
ca:
secret:
name: secret-provisioner-tls-ca
namespace: default
autoGenerate: true
maxCertificateLifetime: 15d
----

You can create your own secrets and reference them e.g. in the `spec.clusterConfig.tls.httpSecretClass` or `spec.clusterConfig.tls.transportSecretClass` to use different certificates.
16 changes: 14 additions & 2 deletions rust/operator-binary/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use validate::validate;
use crate::{
crd::{
NodeRoles,
v1alpha1::{self},
v1alpha1::{self, OpenSearchTls},
},
framework::{
ClusterName, ControllerName, HasName, HasUid, ListenerClassName, NameIsValidLabelValue,
Expand Down Expand Up @@ -131,6 +131,7 @@ pub struct ValidatedOpenSearchConfig {
pub listener_class: ListenerClassName,
pub logging: ValidatedLogging,
pub node_roles: NodeRoles,
pub requested_secret_lifetime: Duration,
pub resources: OpenSearchNodeResources,
pub termination_grace_period_seconds: i64,
}
Expand Down Expand Up @@ -166,9 +167,11 @@ pub struct ValidatedCluster {
pub uid: Uid,
pub role_config: GenericRoleConfig,
pub role_group_configs: BTreeMap<RoleGroupName, OpenSearchRoleGroupConfig>,
pub tls_config: OpenSearchTls,
}

impl ValidatedCluster {
#[allow(clippy::too_many_arguments)]
pub fn new(
image: ResolvedProductImage,
product_version: ProductVersion,
Expand All @@ -177,6 +180,7 @@ impl ValidatedCluster {
uid: impl Into<Uid>,
role_config: GenericRoleConfig,
role_group_configs: BTreeMap<RoleGroupName, OpenSearchRoleGroupConfig>,
tls_config: OpenSearchTls,
) -> Self {
let uid = uid.into();
ValidatedCluster {
Expand All @@ -193,6 +197,7 @@ impl ValidatedCluster {
uid,
role_config,
role_group_configs,
tls_config,
}
}

Expand Down Expand Up @@ -372,13 +377,17 @@ mod tests {
kvp::LabelValue,
product_logging::spec::AutomaticContainerLogConfig,
role_utils::GenericRoleConfig,
shared::time::Duration,
};
use uuid::uuid;

use super::{Context, OpenSearchRoleGroupConfig, ValidatedCluster, ValidatedLogging};
use crate::{
controller::{OpenSearchNodeResources, ValidatedOpenSearchConfig},
crd::{NodeRoles, v1alpha1},
crd::{
NodeRoles,
v1alpha1::{self, OpenSearchTls},
},
framework::{
ClusterName, ListenerClassName, NamespaceName, OperatorName, ProductVersion,
RoleGroupName, builder::pod::container::EnvVarSet,
Expand Down Expand Up @@ -494,6 +503,7 @@ mod tests {
),
]
.into(),
OpenSearchTls::default(),
)
}

Expand All @@ -513,6 +523,8 @@ mod tests {
vector_container: None,
},
node_roles: NodeRoles(node_roles.to_vec()),
requested_secret_lifetime: Duration::from_str("1d")
.expect("should be a valid duration"),
resources: OpenSearchNodeResources::default(),
termination_grace_period_seconds: 120,
},
Expand Down
9 changes: 8 additions & 1 deletion rust/operator-binary/src/controller/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ mod tests {
kvp::LabelValue,
product_logging::spec::AutomaticContainerLogConfig,
role_utils::GenericRoleConfig,
shared::time::Duration,
};
use uuid::uuid;

Expand All @@ -77,7 +78,10 @@ mod tests {
ContextNames, OpenSearchNodeResources, OpenSearchRoleGroupConfig, ValidatedCluster,
ValidatedContainerLogConfigChoice, ValidatedLogging, ValidatedOpenSearchConfig,
},
crd::{NodeRoles, v1alpha1},
crd::{
NodeRoles,
v1alpha1::{self, OpenSearchTls},
},
framework::{
ClusterName, ControllerName, ListenerClassName, NamespaceName, OperatorName,
ProductName, ProductVersion, RoleGroupName, builder::pod::container::EnvVarSet,
Expand Down Expand Up @@ -191,6 +195,7 @@ mod tests {
),
]
.into(),
OpenSearchTls::default(),
)
}

Expand All @@ -210,6 +215,8 @@ mod tests {
vector_container: None,
},
node_roles: NodeRoles(node_roles.to_vec()),
requested_secret_lifetime: Duration::from_str("1d")
.expect("should be a valid duration"),
resources: OpenSearchNodeResources::default(),
termination_grace_period_seconds: 120,
},
Expand Down
Loading