Skip to content
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

Let secret-operator handle PKCS#12 conversion #695

Merged
merged 8 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ All notable changes to this project will be documented in this file.

- `vector` `0.26.0` -> `0.31.0` ([#709]).
- `operator-rs` `0.44.0` -> `0.45.1` ([#711]).
- Let secret-operator handle certificate conversion ([#695]).

[#695]: https://github.com/stackabletech/zookeeper-operator/pull/695
[#709]: https://github.com/stackabletech/zookeeper-operator/pull/709
[#711]: https://github.com/stackabletech/zookeeper-operator/pull/711

Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[workspace]
members = ["rust/crd", "rust/operator-binary"]

#[patch."https://github.com/stackabletech/operator-rs.git"]
#stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "main" }
[patch."https://github.com/stackabletech/operator-rs.git"]
# stackable-operator = { path = "../operator-rs" }
# stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "main" }

#[patch.crates-io]
# tokio-zookeeper = { git = "https://github.com/stackabletech/tokio-zookeeper.git", branch = "feature/tokio-modernize" }
130 changes: 9 additions & 121 deletions rust/crd/src/security.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
//!
//! This is required due to overlaps between TLS encryption and e.g. mTLS authentication or Kerberos

use crate::{
authentication, authentication::ResolvedAuthenticationClasses, tls, ZookeeperCluster,
STACKABLE_RW_CONFIG_DIR, ZOOKEEPER_PROPERTIES_FILE,
};
use crate::{authentication, authentication::ResolvedAuthenticationClasses, tls, ZookeeperCluster};

use snafu::{ResultExt, Snafu};
use stackable_operator::{
builder::{ContainerBuilder, PodBuilder, SecretOperatorVolumeSourceBuilder, VolumeBuilder},
builder::{
ContainerBuilder, PodBuilder, SecretFormat, SecretOperatorVolumeSourceBuilder,
VolumeBuilder,
},
client::Client,
commons::authentication::AuthenticationClassProvider,
k8s_openapi::api::core::v1::Volume,
Expand Down Expand Up @@ -117,100 +117,26 @@ impl ZookeeperSecurity {
}
}

/// Returns required (init) container commands to generate keystores and truststores
/// depending on the tls and authentication settings.
pub fn commands(&self) -> Vec<String> {
let mut args = vec![];
// Quorum
args.push(Self::generate_password(Self::STORE_PASSWORD_ENV));
args.extend(Self::create_key_and_trust_store_cmd(
Self::QUORUM_TLS_MOUNT_DIR,
Self::QUORUM_TLS_DIR,
"quorum-tls",
Self::STORE_PASSWORD_ENV,
));
args.extend(vec![
Self::write_store_password_to_config(
Self::SSL_QUORUM_KEY_STORE_PASSWORD,
STACKABLE_RW_CONFIG_DIR,
Self::STORE_PASSWORD_ENV,
),
Self::write_store_password_to_config(
Self::SSL_QUORUM_TRUST_STORE_PASSWORD,
STACKABLE_RW_CONFIG_DIR,
Self::STORE_PASSWORD_ENV,
),
]);

// server-tls or client-auth-tls (only the certificates specified are accepted)
if self.tls_enabled() {
args.push(Self::generate_password(Self::STORE_PASSWORD_ENV));

args.extend(Self::create_key_and_trust_store_cmd(
Self::SERVER_TLS_MOUNT_DIR,
Self::SERVER_TLS_DIR,
"server-tls",
Self::STORE_PASSWORD_ENV,
));

args.extend(vec![
Self::write_store_password_to_config(
Self::SSL_KEY_STORE_PASSWORD,
STACKABLE_RW_CONFIG_DIR,
Self::STORE_PASSWORD_ENV,
),
Self::write_store_password_to_config(
Self::SSL_TRUST_STORE_PASSWORD,
STACKABLE_RW_CONFIG_DIR,
Self::STORE_PASSWORD_ENV,
),
]);
}

args
}

/// Adds required volumes and volume mounts to the pod and container builders
/// depending on the tls and authentication settings.
pub fn add_volume_mounts(
&self,
pod_builder: &mut PodBuilder,
cb_prepare: &mut ContainerBuilder,
cb_zookeeper: &mut ContainerBuilder,
) {
let tls_secret_class = self.get_tls_secret_class();

if let Some(secret_class) = tls_secret_class {
// mounts for secret volume
cb_prepare.add_volume_mount("server-tls-mount", Self::SERVER_TLS_MOUNT_DIR);
cb_zookeeper.add_volume_mount("server-tls-mount", Self::SERVER_TLS_MOUNT_DIR);
pod_builder.add_volume(Self::create_tls_volume("server-tls-mount", secret_class));
// empty mount for trust and keystore
cb_prepare.add_volume_mount("server-tls", Self::SERVER_TLS_DIR);
cb_zookeeper.add_volume_mount("server-tls", Self::SERVER_TLS_DIR);
pod_builder.add_volume(
VolumeBuilder::new("server-tls")
.with_empty_dir(Some(""), None)
.build(),
);
pod_builder.add_volume(Self::create_tls_volume("server-tls", secret_class));
}

// quorum
// mounts for secret volume
cb_prepare.add_volume_mount("quorum-tls-mount", Self::QUORUM_TLS_MOUNT_DIR);
cb_zookeeper.add_volume_mount("quorum-tls-mount", Self::QUORUM_TLS_MOUNT_DIR);
cb_zookeeper.add_volume_mount("quorum-tls", Self::QUORUM_TLS_DIR);
pod_builder.add_volume(Self::create_tls_volume(
"quorum-tls-mount",
"quorum-tls",
&self.quorum_secret_class,
));
// empty mount for trust and keystore
cb_prepare.add_volume_mount("quorum-tls", Self::QUORUM_TLS_DIR);
cb_zookeeper.add_volume_mount("quorum-tls", Self::QUORUM_TLS_DIR);
pod_builder.add_volume(
VolumeBuilder::new("quorum-tls")
.with_empty_dir(Some(""), None)
.build(),
);
}

/// Returns required ZooKeeper configuration settings for the `zoo.cfg` properties file
Expand Down Expand Up @@ -331,47 +257,9 @@ impl ZookeeperSecurity {
SecretOperatorVolumeSourceBuilder::new(secret_class_name)
.with_pod_scope()
.with_node_scope()
.with_format(SecretFormat::TlsPkcs12)
.build(),
)
.build()
}

/// Generates the shell script to retrieve a random 20 character password
fn generate_password(store_password_env_var: &str) -> String {
format!(
"export {store_password_env_var}=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 20 ; echo '')",
)
}

/// Generates the shell script to append the generated password from `generate_password()`
/// to the zoo.cfg to set key and truststore passwords.
fn write_store_password_to_config(
property: &str,
rw_conf_dir: &str,
store_password_env_var: &str,
) -> String {
format!(
"echo {property}=${store_password_env_var} >> {rw_conf_dir}/{ZOOKEEPER_PROPERTIES_FILE}",
)
}

/// Generates the shell script to create key and trust stores from the certificates provided
/// by the secret operator
fn create_key_and_trust_store_cmd(
mount_directory: &str,
stackable_directory: &str,
alias_name: &str,
store_password_env_var: &str,
) -> Vec<String> {
vec![
format!("echo [{stackable_directory}] Cleaning up truststore - just in case"),
format!("rm -f {stackable_directory}/truststore.p12"),
format!("echo [{stackable_directory}] Creating truststore"),
format!("keytool -importcert -file {mount_directory}/ca.crt -keystore {stackable_directory}/truststore.p12 -storetype pkcs12 -noprompt -alias {alias_name} -storepass ${store_password_env_var}"),
format!("echo [{stackable_directory}] Creating certificate chain"),
format!("cat {mount_directory}/ca.crt {mount_directory}/tls.crt > {stackable_directory}/chain.crt"),
format!("echo [{stackable_directory}] Creating keystore"),
format!("openssl pkcs12 -export -in {stackable_directory}/chain.crt -inkey {mount_directory}/tls.key -out {stackable_directory}/keystore.p12 --passout pass:${store_password_env_var}"),
]
}
}
3 changes: 1 addition & 2 deletions rust/operator-binary/src/zk_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ fn build_server_rolegroup_statefulset(
let mut pod_builder = PodBuilder::new();

// add volumes and mounts depending on tls / auth settings
zookeeper_security.add_volume_mounts(&mut pod_builder, &mut cb_prepare, &mut cb_zookeeper);
zookeeper_security.add_volume_mounts(&mut pod_builder, &mut cb_zookeeper);

let mut args = Vec::new();

Expand All @@ -655,7 +655,6 @@ fn build_server_rolegroup_statefulset(
));
}
args.extend(create_init_container_command_args());
args.extend(zookeeper_security.commands());

let container_prepare = cb_prepare
.image_from_product_image(resolved_product_image)
Expand Down