Skip to content
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
1,376 changes: 695 additions & 681 deletions Cargo.lock

Large diffs are not rendered by default.

3,282 changes: 1,611 additions & 1,671 deletions Cargo.nix

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ edition = "2021"
repository = "https://github.com/stackabletech/secret-operator"

[workspace.dependencies]
stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.108.0", features = ["time", "crds", "webhook"] }
stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.113.0", features = ["time", "crds", "webhook"] }
krb5 = { git = "https://github.com/stackabletech/krb5-rs.git", tag = "v0.1.0" }

anyhow = "1.0"
Expand All @@ -24,14 +24,13 @@ const_format = "0.2.34"
futures = { version = "0.3", features = ["compat"] }
h2 = "0.4"
hex = "0.4"
indoc = "2.0"
# We can't use the stackable-operator re-export because we need the special "unstable-runtime-stream-control"
# feature. We don't want to enable it in stackable-operator, as we don't want to accidentally use
# unstable features.
# This version needs to match the kube version that is re-exported by stackable-operator, so that
# the feature unification works!
kube-runtime = { git = "https://github.com/kube-rs/kube-rs", rev = "fe69cc486ff8e62a7da61d64ec3ebbd9e64c43b5", default-features = false, features = ["unstable-runtime-stream-control"] }
# Hopefully soon we can switch to
# kube-runtime = { version = "*", default-features = false, features = ["unstable-runtime-stream-control"] }
kube-runtime = { version = "*", default-features = false, features = ["unstable-runtime-stream-control"] }
ldap3 = { version = "0.12", default-features = false, features = ["gssapi", "tls"] }
libc = "0.2"
native-tls = "0.2"
Expand Down
23 changes: 9 additions & 14 deletions crate-hashes.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions extra/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ spec:
name: v1alpha2
schema:
openAPIV3Schema:
description: Auto-generated derived type for SecretClassSpec via `CustomResource`
description: A SecretClass is a cluster-global Kubernetes resource that defines a category of secrets that the Secret Operator knows how to provision.
properties:
spec:
description: |-
Expand Down Expand Up @@ -444,7 +444,7 @@ spec:
name: v1alpha1
schema:
openAPIV3Schema:
description: Auto-generated derived type for SecretClassSpec via `CustomResource`
description: A SecretClass is a cluster-global Kubernetes resource that defines a category of secrets that the Secret Operator knows how to provision.
properties:
spec:
description: |-
Expand Down Expand Up @@ -886,7 +886,7 @@ spec:
name: v1alpha1
schema:
openAPIV3Schema:
description: Auto-generated derived type for TrustStoreSpec via `CustomResource`
description: A TrustStore requests information about how to validate secrets issued by a SecretClass.
properties:
spec:
description: |-
Expand Down
2 changes: 1 addition & 1 deletion rust/cert-tools/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub enum CertInput {
}

impl CertInput {
pub fn from_file(&self) -> Result<Vec<X509>, CertInputError> {
pub fn read_certificates(&self) -> Result<Vec<X509>, CertInputError> {
let read_file_fn = |path| fs::read(path).context(ReadFileSnafu { path });

match self {
Expand Down
2 changes: 1 addition & 1 deletion rust/cert-tools/src/cmds/pkcs12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub fn generate_truststore(args: GeneratePkcs12TruststoreArguments) -> Result<()
let certificate_sources = certificate_sources
.iter()
.map(|source| {
let certificates_list = source.from_file().context(ReadCertificateSnafu {
let certificates_list = source.read_certificates().context(ReadCertificateSnafu {
path: source.path(),
})?;

Expand Down
2 changes: 1 addition & 1 deletion rust/cert-tools/src/parsers/pkcs12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub fn parse_file_workaround(
password: &str,
) -> Result<Vec<X509>, WorkaroundError> {
let mut child = Command::new("openssl")
.args(&[
.args([
"pkcs12",
"-nokeys",
"-password",
Expand Down
11 changes: 8 additions & 3 deletions rust/krb5-provision-keytab/src/active_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use crate::credential_cache::{self, CredentialCache};
pub enum Error {
#[snafu(display("failed to retrieve LDAP TLS CA {ca_ref}"))]
GetLdapTlsCa {
source: kube::Error,
#[snafu(source(from(kube::Error, Box::new)))]
source: Box<kube::Error>,
ca_ref: ObjectRef<Secret>,
},

Expand All @@ -33,7 +34,10 @@ pub enum Error {
ParseLdapTlsCa { source: native_tls::Error },

#[snafu(display("password cache error"))]
PasswordCache { source: credential_cache::Error },
PasswordCache {
#[snafu(source(from(credential_cache::Error, Box::new)))]
source: Box<credential_cache::Error>,
},

#[snafu(display("failed to configure LDAP TLS"))]
ConfigureLdapTls { source: native_tls::Error },
Expand All @@ -58,7 +62,8 @@ pub enum Error {
link = "https://docs.stackable.tech/home/nightly/secret-operator/troubleshooting.html#active-directory-ldap-user-conflict"
))]
CreateLdapUserConflict {
source: ldap3::LdapError,
#[snafu(source(from(ldap3::LdapError, Box::new)))]
source: Box<ldap3::LdapError>,
password_cache_ref: ObjectRef<Secret>,
},

Expand Down
6 changes: 3 additions & 3 deletions rust/krb5-provision-keytab/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ enum Error {

enum AdminConnection<'a> {
Mit(mit::MitAdmin<'a>),
ActiveDirectory(active_directory::AdAdmin<'a>),
ActiveDirectory(Box<active_directory::AdAdmin<'a>>),
}

async fn run() -> Result<Response, Error> {
Expand All @@ -95,7 +95,7 @@ async fn run() -> Result<Response, Error> {
user_distinguished_name,
schema_distinguished_name,
generate_sam_account_name,
} => AdminConnection::ActiveDirectory(
} => AdminConnection::ActiveDirectory(Box::new(
active_directory::AdAdmin::connect(
&ldap_server,
&krb,
Expand All @@ -107,7 +107,7 @@ async fn run() -> Result<Response, Error> {
)
.await
.context(ActiveDirectoryInitSnafu)?,
),
)),
};
let mut kt = Keytab::resolve(
&krb,
Expand Down
4 changes: 1 addition & 3 deletions rust/olm-deployer/src/data.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use stackable_operator::kube::{ResourceExt, api::DynamicObject};

pub fn containers<'a>(
target: &'a mut DynamicObject,
) -> anyhow::Result<&'a mut Vec<serde_json::Value>> {
pub fn containers(target: &mut DynamicObject) -> anyhow::Result<&mut Vec<serde_json::Value>> {
let tname = target.name_any();
let path = "template/spec/containers".split("/");
match get_or_create(target.data.pointer_mut("/spec").unwrap(), path)? {
Expand Down
3 changes: 1 addition & 2 deletions rust/olm-deployer/src/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ fn deployer_env_var(deployment: &Deployment) -> Option<&Vec<EnvVar>> {
.map(|ts| ts.containers.iter())
.into_iter()
.flatten()
.filter(|c| c.name == "secret-operator-deployer")
.last()
.rfind(|c| c.name == "secret-operator-deployer")
.and_then(|c| c.env.as_ref())
}

Expand Down
3 changes: 1 addition & 2 deletions rust/olm-deployer/src/resources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ fn deployment_resources(deployment: &Deployment) -> Option<&ResourceRequirements
.map(|ts| ts.containers.iter())
.into_iter()
.flatten()
.filter(|c| c.name == "secret-operator-deployer")
.last()
.rfind(|c| c.name == "secret-operator-deployer")
.and_then(|c| c.resources.as_ref())
}

Expand Down
1 change: 1 addition & 0 deletions rust/operator-binary/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ rand.workspace = true
const_format.workspace = true

[dev-dependencies]
indoc.workspace = true
serde_yaml.workspace = true

[build-dependencies]
Expand Down
5 changes: 4 additions & 1 deletion rust/operator-binary/src/backend/auto_tls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ pub enum Error {
GenerateKey { source: openssl::error::ErrorStack },

#[snafu(display("failed to load CA"))]
LoadCa { source: ca::Error },
LoadCa {
#[snafu(source(from(ca::Error, Box::new)))]
source: Box<ca::Error>,
},

#[snafu(display("failed to pick a CA"))]
PickCa { source: ca::GetCaError },
Expand Down
122 changes: 117 additions & 5 deletions rust/operator-binary/src/crd/secret_class/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ mod v1alpha2_impl;
pub mod versioned {
/// A [SecretClass](DOCS_BASE_URL_PLACEHOLDER/secret-operator/secretclass) is a cluster-global Kubernetes resource
/// that defines a category of secrets that the Secret Operator knows how to provision.
#[versioned(crd(group = "secrets.stackable.tech"))]
#[versioned(crd(
group = "secrets.stackable.tech",
doc = "A SecretClass is a cluster-global Kubernetes resource that defines a category of secrets that the Secret Operator knows how to provision."
))]
#[derive(CustomResource, Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct SecretClassSpec {
Expand Down Expand Up @@ -335,20 +338,129 @@ pub mod versioned {

#[cfg(test)]
mod test {
use stackable_operator::shared::time::Duration;
use stackable_operator::{shared::time::Duration, versioned::test_utils::RoundtripTestData};
use stackable_secret_operator_utils::crd::{ConfigMapReference, SecretReference};

use crate::{
backend::auto_tls::{
DEFAULT_CA_CERT_LIFETIME, DEFAULT_CA_CERT_RETIREMENT_DURATION,
DEFAULT_MAX_CERT_LIFETIME,
},
crd::v1alpha2::{
AdditionalTrustRoot, AutoTlsBackend, AutoTlsCa, CertificateKeyGeneration, SecretClass,
SecretClassBackend, SecretClassSpec,
crd::{
secret_class::v1alpha1,
v1alpha2::{
self, AdditionalTrustRoot, AutoTlsBackend, AutoTlsCa, CertificateKeyGeneration,
SecretClass, SecretClassBackend, SecretClassSpec,
},
},
};

/// The test data for [`v1alpha1`] and [`v1alpha2`] is identical except for the names of the
/// `certManager` backend variant and the `generateSamAccountName` field, both of which were
/// renamed in v1alpha2. The differing names are templated in via `{{cert_manager_backend}}`
/// and `{{generate_sam_account_name}}` so that the YAML can be shared between both versions.
fn secret_class_roundtrip_test_data(
Comment thread
sbernauer marked this conversation as resolved.
cert_manager_backend: &str,
generate_sam_account_name: &str,
) -> String {
indoc::indoc! {"
- backend:
autoTls:
ca:
secret:
name: secret-provisioner-tls-ca
namespace: default
autoGenerate: true
caCertificateLifetime: 100d
caCertificateRetirementDuration: 1d
keyGeneration:
rsa:
length: 3072
additionalTrustRoots:
- configMap:
name: tls-root-ca-config-map
namespace: default
- secret:
name: tls-root-ca-secret
namespace: default
maxCertificateLifetime: 31d
- backend:
k8sSearch:
searchNamespace:
name: default
trustStoreConfigMapName: my-trust-store
- backend:
k8sSearch:
searchNamespace:
pod: {}
- backend:
{{cert_manager_backend}}:
issuer:
kind: ClusterIssuer
name: secret-operator-issuer
defaultCertificateLifetime: 2d
keyGeneration:
rsa:
length: 4096
- backend:
kerberosKeytab:
realmName: CLUSTER.LOCAL
kdc: krb5-kdc.default.svc.cluster.local
admin:
mit:
kadminServer: krb5-kdc.default.svc.cluster.local
adminKeytabSecret:
name: secret-operator-keytab
namespace: default
adminPrincipal: stackable-secret-operator
- backend:
kerberosKeytab:
realmName: SBLE.TEST
kdc: sble-adds.sble.test
admin:
activeDirectory:
ldapServer: sble-adds.sble.test
ldapTlsCaSecret:
name: secret-operator-ad-ca
namespace: default
passwordCacheSecret:
name: secret-operator-ad-passwords
namespace: default
userDistinguishedName: CN=Stackable,CN=Users,DC=sble,DC=test
schemaDistinguishedName: CN=Schema,CN=Configuration,DC=sble,DC=test
{{generate_sam_account_name}}:
prefix: sble-
totalLength: 15
adminKeytabSecret:
name: secret-operator-keytab
namespace: default
adminPrincipal: stackable-secret-operator
"}
.replace("{{cert_manager_backend}}", cert_manager_backend)
.replace("{{generate_sam_account_name}}", generate_sam_account_name)
}

impl RoundtripTestData for v1alpha1::SecretClassSpec {
fn roundtrip_test_data() -> Vec<Self> {
stackable_operator::utils::yaml_from_str_singleton_map(
&secret_class_roundtrip_test_data(
"experimentalCertManager",
"experimentalGenerateSamAccountName",
),
)
.expect("Failed to parse v1alpha1 SecretClassSpec YAML")
}
}

impl RoundtripTestData for v1alpha2::SecretClassSpec {
fn roundtrip_test_data() -> Vec<Self> {
stackable_operator::utils::yaml_from_str_singleton_map(
&secret_class_roundtrip_test_data("certManager", "generateSamAccountName"),
)
.expect("Failed to parse v1alpha2 SecretClassSpec YAML")
}
}

#[test]
fn test_deserialization() {
let input: &str = r#"
Expand Down
Loading
Loading