Skip to content

Commit

Permalink
Filter out ocp certs from the external ones
Browse files Browse the repository at this point in the history
When using RHACM to deploy disconnected IBU seed SNO clusters, the
trusted-ca-bundle, which should only contain external to OCP CA
certificates, can contain also OCP internal CA certificates. E.g.:

- internal-loadbalancer-serving
- service-network-serving-cert
- localhost-serving-cert
- external-loadbalancer-serving

This change filters out all certs found in there with their subject
containing openshift as the organisation unit (i.e. OU=openshift), as
they are not external certs and should not be ignored by recert when
regenerating and re-signing OCP certificates.

Signed-off-by: Michail Resvanis <[email protected]>
  • Loading branch information
mresvanis committed Mar 5, 2025
1 parent 0587575 commit 4807503
Showing 1 changed file with 65 additions and 10 deletions.
75 changes: 65 additions & 10 deletions src/cluster_crypto/scanning/external_certs.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
use super::super::locations::K8sResourceLocation;
use crate::k8s_etcd::get_etcd_json;
use crate::k8s_etcd::InMemoryK8sEtcd;
use anyhow::{bail, Context, Result};
use anyhow::{Context, Result};
use itertools::Itertools;
use std::collections::HashSet;
use std::sync::Arc;
use x509_certificate::X509Certificate;

const OPENSHIFT_CN_PATTERNS: &[&str] = &[
"ou=openshift",
"cn=ingress-operator@",
"cn=openshift-kube-apiserver-operator_localhost-recovery-serving-signer@",
];

fn is_openshift_certificate(subject: &str) -> bool {
let subject_lower = subject.to_lowercase();
OPENSHIFT_CN_PATTERNS.iter().any(|pattern| subject_lower.contains(*pattern))
}

pub(crate) async fn discover_external_certs(in_memory_etcd_client: Arc<InMemoryK8sEtcd>) -> Result<HashSet<String>> {
let proxy_trusted_certs = vec![get_openshift_proxy_trusted_certs(&in_memory_etcd_client)
.await
Expand Down Expand Up @@ -35,16 +46,22 @@ pub(crate) async fn discover_external_certs(in_memory_etcd_client: Arc<InMemoryK
pem::parse_many(all_certs_bundled)
.context("parsing")?
.into_iter()
.map(|pem| match pem.tag() {
"CERTIFICATE" => Ok({
let crt = X509Certificate::from_der(pem.contents()).context("from der")?;
let cn = crt.subject_name().user_friendly_str().unwrap_or("undecodable".to_string());

log::trace!("Found external certificate: {}", cn);
.filter_map(|pem| match pem.tag() {
"CERTIFICATE" => match X509Certificate::from_der(pem.contents()) {
Ok(crt) => {
let cn = crt.subject_name().user_friendly_str().unwrap_or("undecodable".to_string());

cn.to_string()
}),
_ => bail!("unexpected tag"),
if is_openshift_certificate(&cn) {
log::trace!("Ignoring OpenShift certificate found in external certificates: {}", cn);
None
} else {
log::trace!("Found external certificate: {}", cn);
Some(Ok(cn))
}
}
Err(e) => Some(Err(anyhow::Error::new(e).context("from der"))),
},
_ => Some(Err(anyhow::anyhow!("unexpected tag"))),
})
.collect::<Result<HashSet<_>>>()
}
Expand Down Expand Up @@ -134,3 +151,41 @@ pub(crate) async fn get_openshift_user_ca_bundle(in_memory_etcd_client: &Arc<InM
)),
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_is_openshift_certificate() {
// These should match
assert!(is_openshift_certificate("OU=OpenShift,CN=service"));
assert!(is_openshift_certificate("CN=ingress-operator@something,O=cluster"));
assert!(is_openshift_certificate(
"CN=openshift-kube-apiserver-operator_localhost-recovery-serving-signer@example,DC=com"
));
assert!(is_openshift_certificate("DC=com,OU=openshift,CN=service"));

// Case insensitivity tests
assert!(is_openshift_certificate("ou=openshift,CN=service"));
assert!(is_openshift_certificate("CN=INGRESS-OPERATOR@something,O=cluster"));

// Test with more complex DN strings
assert!(is_openshift_certificate("CN=service,OU=OpenShift,O=Example,L=City,ST=State,C=US"));
assert!(is_openshift_certificate(
"C=US,ST=State,L=City,O=Example,OU=Department,CN=ingress-operator@cluster"
));

// These should not match
assert!(!is_openshift_certificate("CN=service,OU=kubernetes"));
assert!(!is_openshift_certificate("CN=operator,O=cluster"));
assert!(!is_openshift_certificate("CN=kube-apiserver,DC=example,DC=com"));
assert!(!is_openshift_certificate("DC=com,OU=other,CN=service"));

// Edge cases
assert!(!is_openshift_certificate(""));
assert!(!is_openshift_certificate("CN=almost-ingress-operator-but-not"));
assert!(!is_openshift_certificate("CN=openshift-kube-apiserver-operator-no-at-sign"));
assert!(!is_openshift_certificate("OUopenshift")); // No equals sign, should not match
}
}

0 comments on commit 4807503

Please sign in to comment.