Skip to content

fix!: Make fields on S3 structs mandatory, add S3 helpers #863

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

Merged
merged 30 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
557845f
refactor!: Add Host type. Fix S3 structs to have mandatory fields
sbernauer Sep 10, 2024
e25c9e0
TLS verification struct now reside top-level in the `commons` module
sbernauer Sep 10, 2024
be75dc2
WIP
sbernauer Sep 10, 2024
68dc317
fix: Use String for Host JsonSchema
sbernauer Sep 11, 2024
4b761eb
changelog
sbernauer Sep 11, 2024
d07bd55
changelog
sbernauer Sep 11, 2024
d97a601
Add unique identifier to avoid clashing volumes and mounts
sbernauer Sep 12, 2024
1f271dd
move identifier to front
sbernauer Sep 12, 2024
decfb05
clippy
sbernauer Sep 12, 2024
20fa37e
Merge branch 'main' into refactor/add-host-struct
sbernauer Sep 12, 2024
5969711
Apply suggestions from code review
sbernauer Sep 12, 2024
687141c
Remove RetrieveS3Bucket error
sbernauer Sep 12, 2024
72417ff
Add some error details
sbernauer Sep 12, 2024
ad89d3f
typo
sbernauer Sep 12, 2024
7dc2394
Add docs for unique_identifier
sbernauer Sep 12, 2024
34d6db8
Apply suggestions from code review
sbernauer Sep 16, 2024
6a27c54
Merge branch 'main' into refactor/add-host-struct
sbernauer Sep 16, 2024
92f09b8
Rename NotAHost -> NotAHost
sbernauer Sep 16, 2024
4fb9d50
Add invalid host to error message
sbernauer Sep 16, 2024
acb84d8
Move to HostParseError
sbernauer Sep 16, 2024
90f9271
Rename Host -> HostName
sbernauer Sep 16, 2024
006e37a
Update crates/stackable-operator/src/commons/networking.rs
sbernauer Sep 18, 2024
5ba4522
Update crates/stackable-operator/CHANGELOG.md
sbernauer Sep 18, 2024
152ee94
Update crates/stackable-operator/CHANGELOG.md
sbernauer Sep 18, 2024
064cc13
Merge branch 'main' into refactor/add-host-struct
sbernauer Sep 19, 2024
9dcd445
changelog
sbernauer Sep 19, 2024
d4e673b
Bump to 0.76.0
sbernauer Sep 19, 2024
16016dc
Merge branch 'main' into refactor/add-host-struct
sbernauer Sep 19, 2024
9e73900
Update crates/stackable-operator/src/commons/networking.rs
sbernauer Sep 19, 2024
87ca305
fix domain names
sbernauer Sep 19, 2024
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
17 changes: 17 additions & 0 deletions crates/stackable-operator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ All notable changes to this project will be documented in this file.

### Added

- BREAKING: Add `HostName` type and use it within LDAP and OIDC AuthenticationClass as well as S3Connection ([#863]).

### Changed

- BREAKING: TLS verification struct now reside in the `commons::tls_verification` module, instead of being placed below `commons::authentication::tls` ([#863]).
- BREAKING: Rename the `Hostname` type to `DomainName` to be consistent with RFC 1123 ([#863]).

### Fixed

- BREAKING: The fields `bucketName`, `connection` and `host` on `S3BucketSpec`, `InlinedS3BucketSpec` and `S3ConnectionSpec` are now mandatory. Previously operators probably errored out in case they where missing, so this should not affect users, but make the errors much clearer ([#863]).

[#863]: https://github.com/stackabletech/operator-rs/pull/863

## TODO: Create a release before #863, as it's majorly breaking

### Added

- Add `Hostname` and `KerberosRealmName` types extracted from secret-operator ([#851]).
- Add support for listener volume scopes to `SecretOperatorVolumeSourceBuilder` ([#858]).

Expand Down
11 changes: 5 additions & 6 deletions crates/stackable-operator/src/commons/authentication/ldap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ use url::{ParseError, Url};
use crate::{
builder::pod::{container::ContainerBuilder, volume::VolumeMountBuilder, PodBuilder},
commons::{
authentication::{
tls::{TlsClientDetails, TlsClientDetailsError},
SECRET_BASE_PATH,
},
authentication::SECRET_BASE_PATH,
networking::HostName,
secret_class::{SecretClassVolume, SecretClassVolumeError},
tls_verification::{TlsClientDetails, TlsClientDetailsError},
},
};

Expand All @@ -36,8 +35,8 @@ pub enum Error {
)]
#[serde(rename_all = "camelCase")]
pub struct AuthenticationProvider {
/// Hostname of the LDAP server, for example: `my.ldap.server`.
pub hostname: String,
/// Host of the LDAP server, for example: `my.ldap.server` or `127.0.0.1`.
pub hostname: HostName,

/// Port of the LDAP server. If TLS is used defaults to 636 otherwise to 389.
port: Option<u16>,
Expand Down
20 changes: 13 additions & 7 deletions crates/stackable-operator/src/commons/authentication/oidc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use url::{ParseError, Url};

#[cfg(doc)]
use crate::commons::authentication::AuthenticationClass;
use crate::commons::authentication::{tls::TlsClientDetails, SECRET_BASE_PATH};
use crate::commons::{
authentication::SECRET_BASE_PATH, networking::HostName, tls_verification::TlsClientDetails,
};

pub type Result<T, E = Error> = std::result::Result<T, E>;

Expand Down Expand Up @@ -40,8 +42,8 @@ pub enum Error {
)]
#[serde(rename_all = "camelCase")]
pub struct AuthenticationProvider {
/// Hostname of the identity provider, e.g. `my.keycloak.corp`.
hostname: String,
/// Host of the identity provider, e.g. `my.keycloak.corp` or `127.0.0.1`.
hostname: HostName,

/// Port of the identity provider. If TLS is used defaults to 443,
/// otherwise to 80.
Expand Down Expand Up @@ -90,7 +92,7 @@ fn default_root_path() -> String {

impl AuthenticationProvider {
pub fn new(
hostname: String,
hostname: HostName,
port: Option<u16>,
root_path: String,
tls: TlsClientDetails,
Expand All @@ -113,8 +115,12 @@ impl AuthenticationProvider {
/// configuration path, use `url.join()`. This module provides the default
/// path at [`DEFAULT_OIDC_WELLKNOWN_PATH`].
pub fn endpoint_url(&self) -> Result<Url> {
let mut url = Url::parse(&format!("http://{}:{}", self.hostname, self.port()))
.context(ParseOidcEndpointUrlSnafu)?;
let mut url = Url::parse(&format!(
"http://{host}:{port}",
host = self.hostname.as_url_host(),
port = self.port()
))
.context(ParseOidcEndpointUrlSnafu)?;

if self.tls.uses_tls() {
url.set_scheme("https").map_err(|_| {
Expand Down Expand Up @@ -317,7 +323,7 @@ mod test {
fn test_oidc_ipv6_endpoint_url() {
let oidc = serde_yaml::from_str::<AuthenticationProvider>(
"
hostname: '[2606:2800:220:1:248:1893:25c8:1946]'
hostname: 2606:2800:220:1:248:1893:25c8:1946
rootPath: my-root-path
port: 12345
scopes: [openid]
Expand Down
155 changes: 0 additions & 155 deletions crates/stackable-operator/src/commons/authentication/tls.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
use k8s_openapi::api::core::v1::{Volume, VolumeMount};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use snafu::{ResultExt, Snafu};

use crate::{
builder::pod::{container::ContainerBuilder, volume::VolumeMountBuilder, PodBuilder},
commons::{
authentication::SECRET_BASE_PATH,
secret_class::{SecretClassVolume, SecretClassVolumeError},
},
};

#[derive(
Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize,
Expand All @@ -22,148 +12,3 @@ pub struct AuthenticationProvider {
/// will be used to provision client certificates.
pub client_cert_secret_class: Option<String>,
}

#[derive(Debug, PartialEq, Snafu)]
pub enum TlsClientDetailsError {
#[snafu(display("failed to convert secret class volume into named Kubernetes volume"))]
SecretClassVolume { source: SecretClassVolumeError },
}

#[derive(
Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "camelCase")]
pub struct TlsClientDetails {
/// Use a TLS connection. If not specified no TLS will be used.
pub tls: Option<Tls>,
}

impl TlsClientDetails {
/// This functions adds
///
/// * The needed volumes to the PodBuilder
/// * The needed volume_mounts to all the ContainerBuilder in the list (e.g. init + main container)
///
/// This function will handle
///
/// * Tls secret class used to verify the cert of the LDAP server
pub fn add_volumes_and_mounts(
&self,
pod_builder: &mut PodBuilder,
container_builders: Vec<&mut ContainerBuilder>,
) -> Result<(), TlsClientDetailsError> {
let (volumes, mounts) = self.volumes_and_mounts()?;
pod_builder.add_volumes(volumes);

for cb in container_builders {
cb.add_volume_mounts(mounts.clone());
}

Ok(())
}

/// It is recommended to use [`Self::add_volumes_and_mounts`], this function returns you the
/// volumes and mounts in case you need to add them by yourself.
pub fn volumes_and_mounts(
&self,
) -> Result<(Vec<Volume>, Vec<VolumeMount>), TlsClientDetailsError> {
let mut volumes = Vec::new();
let mut mounts = Vec::new();

if let Some(secret_class) = self.tls_ca_cert_secret_class() {
let volume_name = format!("{secret_class}-ca-cert");
let secret_class_volume = SecretClassVolume::new(secret_class.clone(), None);
let volume = secret_class_volume
.to_volume(&volume_name)
.context(SecretClassVolumeSnafu)?;

volumes.push(volume);
mounts.push(
VolumeMountBuilder::new(volume_name, format!("{SECRET_BASE_PATH}/{secret_class}"))
.build(),
);
}

Ok((volumes, mounts))
}

/// Whether TLS is configured
pub const fn uses_tls(&self) -> bool {
self.tls.is_some()
}

/// Whether TLS verification is configured. Returns `false` if TLS itself isn't configured
pub fn uses_tls_verification(&self) -> bool {
self.tls
.as_ref()
.map(|tls| tls.verification != TlsVerification::None {})
.unwrap_or_default()
}

/// Returns the path of the ca.crt that should be used to verify the LDAP server certificate
/// if TLS verification with a CA cert from a SecretClass is configured.
pub fn tls_ca_cert_mount_path(&self) -> Option<String> {
self.tls_ca_cert_secret_class()
.map(|secret_class| format!("{SECRET_BASE_PATH}/{secret_class}/ca.crt"))
}

/// Extracts the SecretClass that provides the CA cert used to verify the server certificate.
pub(crate) fn tls_ca_cert_secret_class(&self) -> Option<String> {
if let Some(Tls {
verification:
TlsVerification::Server(TlsServerVerification {
ca_cert: CaCert::SecretClass(secret_class),
}),
}) = &self.tls
{
Some(secret_class.to_owned())
} else {
None
}
}
}

#[derive(
Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "camelCase")]
pub struct Tls {
/// The verification method used to verify the certificates of the server and/or the client.
pub verification: TlsVerification,
}

#[derive(
Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "camelCase")]
pub enum TlsVerification {
/// Use TLS but don't verify certificates.
None {},

/// Use TLS and a CA certificate to verify the server.
Server(TlsServerVerification),
}

#[derive(
Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "camelCase")]
pub struct TlsServerVerification {
/// CA cert to verify the server.
pub ca_cert: CaCert,
}

#[derive(
Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "camelCase")]
pub enum CaCert {
/// Use TLS and the CA certificates trusted by the common web browsers to verify the server.
/// This can be useful when you e.g. use public AWS S3 or other public available services.
WebPki {},

/// Name of the [SecretClass](DOCS_BASE_URL_PLACEHOLDER/secret-operator/secretclass) which will provide the CA certificate.
/// Note that a SecretClass does not need to have a key but can also work with just a CA certificate,
/// so if you got provided with a CA cert but don't have access to the key you can still use this method.
SecretClass(String),
}
1 change: 1 addition & 0 deletions crates/stackable-operator/src/commons/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ pub mod resources;
pub mod s3;
pub mod secret;
pub mod secret_class;
pub mod tls_verification;
Loading