diff --git a/CHANGELOG.md b/CHANGELOG.md index eaaf688caf..1039c8cccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Support for ZooKeeper-based Apache Kafka clusters and for KRaft migration has been removed * Support for MirrorMaker 1 has been removed * Added support to configure `dnsPolicy` and `dnsConfig` using the `template` sections. +* Store Kafka node certificates in separate Secrets, one Secret per pod. ### Major changes, deprecations and removals diff --git a/api/src/main/java/io/strimzi/api/kafka/model/kafka/KafkaResources.java b/api/src/main/java/io/strimzi/api/kafka/model/kafka/KafkaResources.java index ceb5575ccc..ad64a5eaa5 100644 --- a/api/src/main/java/io/strimzi/api/kafka/model/kafka/KafkaResources.java +++ b/api/src/main/java/io/strimzi/api/kafka/model/kafka/KafkaResources.java @@ -154,6 +154,7 @@ public static String initContainerClusterRoleBindingName(String cluster, String * * @return The name of the corresponding Kafka Secret. */ + @Deprecated // Kafka server certificates are now kept in per-node Secrets public static String kafkaSecretName(String clusterName) { return clusterName + "-kafka-brokers"; } diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CertUtils.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CertUtils.java index 4676acd64f..10176dca1f 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CertUtils.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CertUtils.java @@ -132,6 +132,21 @@ public static Map buildSecretData(Map certif return data; } + /** + * Constructs a Map containing the provided certificates to be stored in a Kubernetes Secret. + * + * @param certificateName Name to use to create identifier for storing the data in the Secret. + * @param certAndKey Private key and public cert pair to store in the Secret. + * + * @return Map of certificate identifier to base64 encoded certificate or key + */ + public static Map buildSecretData(String certificateName, CertAndKey certAndKey) { + return Map.of( + Ca.SecretEntry.KEY.asKey(certificateName), certAndKey.keyAsBase64String(), + Ca.SecretEntry.CRT.asKey(certificateName), certAndKey.certAsBase64String() + ); + } + private static byte[] decodeFromSecret(Secret secret, String key) { if (secret.getData().get(key) != null && !secret.getData().get(key).isEmpty()) { return Util.decodeBytesFromBase64(secret.getData().get(key)); diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/ClusterCa.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/ClusterCa.java index d6de9bf037..53d99319cf 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/ClusterCa.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/ClusterCa.java @@ -107,7 +107,6 @@ protected String caName() { * @param existingCertificates Existing certificates (or null if they do not exist yet) * @param nodes Nodes that are part of the Cruise Control cluster * @param isMaintenanceTimeWindowsSatisfied Flag indicating whether we can do maintenance tasks or not - * @param caCertGenerationChanged Flag indicating whether the CA cert generation has changed since the existing certificates were issued * * @return Map with CertAndKey object containing the public and private key * @@ -118,8 +117,7 @@ protected Map generateCcCerts( String clusterName, Map existingCertificates, Set nodes, - boolean isMaintenanceTimeWindowsSatisfied, - boolean caCertGenerationChanged + boolean isMaintenanceTimeWindowsSatisfied ) throws IOException { DnsNameGenerator ccDnsGenerator = DnsNameGenerator.of(namespace, CruiseControlResources.serviceName(clusterName)); @@ -143,8 +141,8 @@ protected Map generateCcCerts( nodes, subjectFn, existingCertificates, - isMaintenanceTimeWindowsSatisfied, - caCertGenerationChanged); + isMaintenanceTimeWindowsSatisfied + ); } /** @@ -158,7 +156,6 @@ protected Map generateCcCerts( * @param externalBootstrapAddresses List of external bootstrap addresses (used for certificate SANs) * @param externalAddresses Map with external listener addresses for the different nodes (used for certificate SANs) * @param isMaintenanceTimeWindowsSatisfied Flag indicating whether we can do maintenance tasks or not - * @param caCertGenerationChanged Flag indicating whether the CA cert generation has changed since the existing certificates were issued * * @return Map with CertAndKey objects containing the public and private keys for the different brokers * @@ -171,8 +168,7 @@ protected Map generateBrokerCerts( Set nodes, Set externalBootstrapAddresses, Map> externalAddresses, - boolean isMaintenanceTimeWindowsSatisfied, - boolean caCertGenerationChanged + boolean isMaintenanceTimeWindowsSatisfied ) throws IOException { Function subjectFn = node -> { Subject.Builder subject = new Subject.Builder() @@ -219,8 +215,8 @@ protected Map generateBrokerCerts( nodes, subjectFn, existingCertificates, - isMaintenanceTimeWindowsSatisfied, - caCertGenerationChanged); + isMaintenanceTimeWindowsSatisfied + ); } @Override @@ -237,7 +233,6 @@ protected String caCertGenerationAnnotation() { * @param subjectFn Function to generate certificate subject for given node / pod * @param existingCertificates Existing certificates (or null if they do not exist yet) * @param isMaintenanceTimeWindowsSatisfied Flag indicating if we are inside a maintenance window or not - * @param caCertGenerationChanged Flag indicating whether the CA cert generation has changed since the existing certificates were issued * * @return Returns map with node certificates which can be used to create or update the stored certificates * @@ -248,8 +243,7 @@ protected String caCertGenerationAnnotation() { Set nodes, Function subjectFn, Map existingCertificates, - boolean isMaintenanceTimeWindowsSatisfied, - boolean caCertGenerationChanged + boolean isMaintenanceTimeWindowsSatisfied ) throws IOException { // Maps for storing the certificates => will be used in the new or updated certificate store. This map is filled in this method and returned at the end. Map certs = new HashMap<>(); @@ -269,7 +263,6 @@ protected String caCertGenerationAnnotation() { if (!this.certRenewed() // No CA renewal is happening && certAndKey != null // There is a public cert and private key for this pod - && !caCertGenerationChanged // The CA cert generation has not changed since the existing certificates were issued ) { // A certificate for this node already exists, so we will try to reuse it LOGGER.debugCr(reconciliation, "Certificate for node {} already exists", node); diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CruiseControl.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CruiseControl.java index d7b06d5e41..f81ca15993 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CruiseControl.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CruiseControl.java @@ -434,8 +434,10 @@ public Secret generateCertificatesSecret(String namespace, String clusterName, C LOGGER.debugCr(reconciliation, "Generating certificates"); try { Set nodes = Set.of(new NodeRef(CruiseControl.COMPONENT_TYPE, 0, null, false, false)); - ccCerts = clusterCa.generateCcCerts(namespace, clusterName, CertUtils.extractCertsAndKeysFromSecret(existingSecret, nodes), - nodes, isMaintenanceTimeWindowsSatisfied, clusterCa.hasCaCertGenerationChanged(existingSecret)); + ccCerts = clusterCa.generateCcCerts(namespace, clusterName, + // Only pass existing certificates if the CA cert generation hasn't changed since they were generated + clusterCa.hasCaCertGenerationChanged(existingSecret) ? Map.of() : CertUtils.extractCertsAndKeysFromSecret(existingSecret, nodes), + nodes, isMaintenanceTimeWindowsSatisfied); } catch (IOException e) { LOGGER.warnCr(reconciliation, "Error while generating certificates", e); } diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaCluster.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaCluster.java index 7860002e46..e8cb5fd19e 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaCluster.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaCluster.java @@ -108,7 +108,10 @@ */ @SuppressWarnings({"checkstyle:ClassDataAbstractionCoupling", "checkstyle:ClassFanOutComplexity"}) public class KafkaCluster extends AbstractModel implements SupportsMetrics, SupportsLogging, SupportsJmx { - protected static final String COMPONENT_TYPE = "kafka"; + /** + * Component type used by Kubernetes labels + */ + public static final String COMPONENT_TYPE = "kafka"; protected static final String ENV_VAR_KAFKA_INIT_EXTERNAL_ADDRESS = "EXTERNAL_ADDRESS"; private static final String ENV_VAR_KAFKA_METRICS_ENABLED = "KAFKA_METRICS_ENABLED"; @@ -1230,37 +1233,55 @@ public List generatePodSets(boolean isOpenShift, } /** - * Generates the private keys for the Kafka brokers (if needed) and the secret with them which contains both the + * Generates the private keys for the Kafka nodes (if needed) and the Secrets with them which contain both the * public and private keys. * * @param clusterCa The CA for cluster certificates * @param clientsCa The CA for clients certificates - * @param existingSecret The existing secret with Kafka certificates + * @param existingSecrets The existing secrets containing Kafka certificates * @param externalBootstrapDnsName Map with bootstrap DNS names which should be added to the certificate * @param externalDnsNames Map with broker DNS names which should be added to the certificate * @param isMaintenanceTimeWindowsSatisfied Indicates whether we are in a maintenance window or not * - * @return The generated Secret with broker certificates + * @return The generated Secrets containing Kafka node certificates */ - public Secret generateCertificatesSecret(ClusterCa clusterCa, ClientsCa clientsCa, Secret existingSecret, Set externalBootstrapDnsName, Map> externalDnsNames, boolean isMaintenanceTimeWindowsSatisfied) { + public List generateCertificatesSecrets(ClusterCa clusterCa, ClientsCa clientsCa, List existingSecrets, Set externalBootstrapDnsName, Map> externalDnsNames, boolean isMaintenanceTimeWindowsSatisfied) { + Map existingSecretWithName = existingSecrets.stream().collect(Collectors.toMap(secret -> secret.getMetadata().getName(), secret -> secret)); Set nodes = nodes(); - Map brokerCerts; + Map existingCerts = new HashMap<>(); + for (NodeRef node : nodes) { + String podName = node.podName(); + // Reuse existing certificate if it exists and the CA cert generation hasn't changed since they were generated + if (existingSecretWithName.get(podName) != null) { + if (clusterCa.hasCaCertGenerationChanged(existingSecretWithName.get(podName))) { + LOGGER.debugCr(reconciliation, "Certificate for pod {}/{} has old cert generation", namespace, podName); + } else { + existingCerts.put(podName, CertUtils.keyStoreCertAndKey(existingSecretWithName.get(podName), podName)); + } + } else { + LOGGER.debugCr(reconciliation, "No existing certificate found for pod {}/{}", namespace, podName); + } + } + Map updatedCerts; try { - brokerCerts = clusterCa.generateBrokerCerts(namespace, cluster, CertUtils.extractCertsAndKeysFromSecret(existingSecret, nodes), - nodes, externalBootstrapDnsName, externalDnsNames, isMaintenanceTimeWindowsSatisfied, clusterCa.hasCaCertGenerationChanged(existingSecret)); + updatedCerts = clusterCa.generateBrokerCerts(namespace, cluster, existingCerts, + nodes, externalBootstrapDnsName, externalDnsNames, isMaintenanceTimeWindowsSatisfied); } catch (IOException e) { LOGGER.warnCr(reconciliation, "Error while generating certificates", e); throw new RuntimeException("Failed to prepare Kafka certificates", e); } - return ModelUtils.createSecret(KafkaResources.kafkaSecretName(cluster), namespace, labels, ownerReference, - CertUtils.buildSecretData(brokerCerts), - Map.ofEntries( - clusterCa.caCertGenerationFullAnnotation(), - clientsCa.caCertGenerationFullAnnotation() - ), - emptyMap()); + return updatedCerts.entrySet() + .stream() + .map(entry -> ModelUtils.createSecret(entry.getKey(), namespace, labels, ownerReference, + CertUtils.buildSecretData(entry.getKey(), entry.getValue()), + Map.ofEntries( + clusterCa.caCertGenerationFullAnnotation(), + clientsCa.caCertGenerationFullAnnotation() + ), + emptyMap())) + .toList(); } /** @@ -1354,7 +1375,7 @@ private List getNonDataVolumes(boolean isOpenShift, NodeRef node, PodTem volumeList.add(VolumeUtils.createTempDirVolume(templatePod)); volumeList.add(VolumeUtils.createSecretVolume(CLUSTER_CA_CERTS_VOLUME, AbstractModel.clusterCaCertSecretName(cluster), isOpenShift)); - volumeList.add(VolumeUtils.createSecretVolume(BROKER_CERTS_VOLUME, KafkaResources.kafkaSecretName(cluster), isOpenShift)); + volumeList.add(VolumeUtils.createSecretVolume(BROKER_CERTS_VOLUME, node.podName(), isOpenShift)); volumeList.add(VolumeUtils.createSecretVolume(CLIENT_CA_CERTS_VOLUME, KafkaResources.clientsCaCertificateSecretName(cluster), isOpenShift)); volumeList.add(VolumeUtils.createConfigMapVolume(LOG_AND_METRICS_CONFIG_VOLUME_NAME, node.podName())); volumeList.add(VolumeUtils.createEmptyDirVolume("ready-files", "1Ki", "Memory")); diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/operator/assembly/KafkaReconciler.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/operator/assembly/KafkaReconciler.java index 820cc4372c..b7f2f71aa7 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/operator/assembly/KafkaReconciler.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/operator/assembly/KafkaReconciler.java @@ -9,6 +9,7 @@ import io.fabric8.kubernetes.api.model.Node; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding; import io.fabric8.kubernetes.client.KubernetesClient; import io.strimzi.api.kafka.model.common.Condition; @@ -161,6 +162,7 @@ public class KafkaReconciler { private final Map brokerLoggingHash = new HashMap<>(); private final Map brokerConfigurationHash = new HashMap<>(); private final Map kafkaServerCertificateHash = new HashMap<>(); + private final List secretsToDelete = new ArrayList<>(); /* test */ TlsPemIdentity coTlsPemIdentity; /* test */ KafkaListenersReconciler.ReconciliationResult listenerReconciliationResults; // Result of the listener reconciliation with the listener details @@ -257,7 +259,7 @@ public Future reconcile(KafkaStatus kafkaStatus, Clock clock) { .compose(i -> scaleDown()) .compose(i -> updateNodePoolStatuses(kafkaStatus)) .compose(i -> listeners()) - .compose(i -> certificateSecret(clock)) + .compose(i -> certificateSecrets(clock)) .compose(i -> brokerConfigurationConfigMaps()) .compose(i -> jmxSecret()) .compose(i -> podDisruptionBudget()) @@ -272,6 +274,7 @@ public Future reconcile(KafkaStatus kafkaStatus, Clock clock) { .compose(i -> metadataVersion(kafkaStatus)) .compose(i -> deletePersistentClaims()) .compose(i -> sharedKafkaConfigurationCleanup()) + .compose(i -> deleteOldCertificateSecrets()) // This has to run after all possible rolling updates which might move the pods to different nodes .compose(i -> nodePortExternalListenerStatus()) .compose(i -> updateKafkaStatus(kafkaStatus)); @@ -731,33 +734,83 @@ protected Future brokerConfigurationConfigMaps() { } /** - * Manages the Secret with the node certificates used by the Kafka brokers. + * Manages the Secrets with the node certificates used by the Kafka nodes. * * @param clock The clock for supplying the reconciler with the time instant of each reconciliation cycle. * That time is used for checking maintenance windows * - * @return Completes when the Secret was successfully created or updated + * @return Completes when the Secrets were successfully created, deleted or updated */ - protected Future certificateSecret(Clock clock) { - return secretOperator.getAsync(reconciliation.namespace(), KafkaResources.kafkaSecretName(reconciliation.name())) + protected Future certificateSecrets(Clock clock) { + return secretOperator.listAsync(reconciliation.namespace(), kafka.getSelectorLabels().withStrimziComponentType(KafkaCluster.COMPONENT_TYPE)) + .compose(existingSecrets -> { + List desiredCertSecrets = kafka.generateCertificatesSecrets(clusterCa, clientsCa, existingSecrets, + listenerReconciliationResults.bootstrapDnsNames, listenerReconciliationResults.brokerDnsNames, + Util.isMaintenanceTimeWindowsSatisfied(reconciliation, maintenanceWindows, clock.instant())); + + List desiredCertSecretNames = desiredCertSecrets.stream().map(secret -> secret.getMetadata().getName()).toList(); + existingSecrets.forEach(secret -> { + String secretName = secret.getMetadata().getName(); + // Don't delete desired secrets or jmx secrets + if (!desiredCertSecretNames.contains(secretName) && !KafkaResources.kafkaJmxSecretName(reconciliation.name()).equals(secretName)) { + secretsToDelete.add(secretName); + } + }); + return updateCertificateSecrets(desiredCertSecrets); + }).mapEmpty(); + } + + /** + * Delete old certificate Secrets that are no longer needed. + * + * @return Future that completes when the Secrets have been deleted. + */ + protected Future deleteOldCertificateSecrets() { + List> deleteFutures = secretsToDelete.stream() + .map(secretName -> { + LOGGER.debugCr(reconciliation, "Deleting old Secret {}/{} that is no longer used.", reconciliation.namespace(), secretName); + return secretOperator.deleteAsync(reconciliation, reconciliation.namespace(), secretName, false); + }).toList(); + + // Remove old Secret containing all certs if it exists + @SuppressWarnings("deprecation") + String oldSecretName = KafkaResources.kafkaSecretName(reconciliation.name()); + return secretOperator.getAsync(reconciliation.namespace(), oldSecretName) .compose(oldSecret -> { - return secretOperator - .reconcile(reconciliation, reconciliation.namespace(), KafkaResources.kafkaSecretName(reconciliation.name()), - kafka.generateCertificatesSecret(clusterCa, clientsCa, oldSecret, listenerReconciliationResults.bootstrapDnsNames, listenerReconciliationResults.brokerDnsNames, Util.isMaintenanceTimeWindowsSatisfied(reconciliation, maintenanceWindows, clock.instant()))) + if (oldSecret != null) { + LOGGER.debugCr(reconciliation, "Deleting legacy Secret {}/{} that is replaced by pod specific Secret.", reconciliation.namespace(), oldSecretName); + deleteFutures.add(secretOperator.deleteAsync(reconciliation, reconciliation.namespace(), oldSecretName, false)); + } + + return Future.join(deleteFutures).mapEmpty(); + }); + } + + /** + * Updates the Secrets with the node certificates used by the Kafka nodes. + * + * @param secrets Secrets to update + * + * @return Future that completes when the Secrets were successfully created or updated + */ + protected Future updateCertificateSecrets(List secrets) { + List> reconcileFutures = secrets + .stream() + .map(secret -> { + String secretName = secret.getMetadata().getName(); + return secretOperator.reconcile(reconciliation, reconciliation.namespace(), secretName, secret) .compose(patchResult -> { if (patchResult != null) { - for (NodeRef node : kafka.nodes()) { - kafkaServerCertificateHash.put( - node.nodeId(), - CertUtils.getCertificateThumbprint(patchResult.resource(), - Ca.SecretEntry.CRT.asKey(node.podName()) - )); - } + kafkaServerCertificateHash.put( + ReconcilerUtils.getPodIndexFromPodName(secretName), + CertUtils.getCertificateThumbprint(patchResult.resource(), + Ca.SecretEntry.CRT.asKey(secretName) + )); } - return Future.succeededFuture(); }); - }); + }).toList(); + return Future.join(reconcileFutures).mapEmpty(); } /** diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/ClusterCaRenewalTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/ClusterCaRenewalTest.java index 1a2b5425b6..f33e2ec754 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/ClusterCaRenewalTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/ClusterCaRenewalTest.java @@ -52,8 +52,8 @@ public void renewalOfCertificatesWithNullCertificates() throws IOException { NODES, SUBJECT_FN, null, - isMaintenanceTimeWindowsSatisfied, - false); + isMaintenanceTimeWindowsSatisfied + ); assertThat(new String(newCerts.get("pod0").cert()), is("new-cert0")); assertThat(new String(newCerts.get("pod0").key()), is("new-key0")); @@ -88,43 +88,8 @@ public void renewalOfCertificatesWithCaRenewal() throws IOException { NODES, SUBJECT_FN, initialCerts, - isMaintenanceTimeWindowsSatisfied, - false); - - assertThat(new String(newCerts.get("pod0").cert()), is("new-cert0")); - assertThat(new String(newCerts.get("pod0").key()), is("new-key0")); - assertThat(new String(newCerts.get("pod0").keyStore()), is("new-keystore0")); - assertThat(newCerts.get("pod0").storePassword(), is("new-password0")); - - assertThat(new String(newCerts.get("pod1").cert()), is("new-cert1")); - assertThat(new String(newCerts.get("pod1").key()), is("new-key1")); - assertThat(new String(newCerts.get("pod1").keyStore()), is("new-keystore1")); - assertThat(newCerts.get("pod1").storePassword(), is("new-password1")); - - assertThat(new String(newCerts.get("pod2").cert()), is("new-cert2")); - assertThat(new String(newCerts.get("pod2").key()), is("new-key2")); - assertThat(new String(newCerts.get("pod2").keyStore()), is("new-keystore2")); - assertThat(newCerts.get("pod2").storePassword(), is("new-password2")); - } - - @ParallelTest - public void renewalOfCertificatesWithForcedCaRenewal() throws IOException { - MockedClusterCa mockedCa = new MockedClusterCa(Reconciliation.DUMMY_RECONCILIATION, null, null, null, null, null, 2, 1, true, null); - - Map initialCerts = new HashMap<>(); - initialCerts.put("pod0", new CertAndKey("old-key".getBytes(), "old-cert".getBytes())); - initialCerts.put("pod1", new CertAndKey("old-key".getBytes(), "old-cert".getBytes())); - initialCerts.put("pod2", new CertAndKey("old-key".getBytes(), "old-cert".getBytes())); - - boolean isMaintenanceTimeWindowsSatisfied = true; - - Map newCerts = mockedCa.maybeCopyOrGenerateCerts( - Reconciliation.DUMMY_RECONCILIATION, - NODES, - SUBJECT_FN, - initialCerts, - isMaintenanceTimeWindowsSatisfied, - true); + isMaintenanceTimeWindowsSatisfied + ); assertThat(new String(newCerts.get("pod0").cert()), is("new-cert0")); assertThat(new String(newCerts.get("pod0").key()), is("new-key0")); @@ -159,8 +124,8 @@ public void renewalOfCertificatesDelayedRenewalInWindow() throws IOException { NODES, SUBJECT_FN, initialCerts, - isMaintenanceTimeWindowsSatisfied, - false); + isMaintenanceTimeWindowsSatisfied + ); assertThat(new String(newCerts.get("pod0").cert()), is("new-cert0")); assertThat(new String(newCerts.get("pod0").key()), is("new-key0")); @@ -195,8 +160,8 @@ public void renewalOfCertificatesDelayedRenewalOutsideWindow() throws IOExceptio NODES, SUBJECT_FN, initialCerts, - isMaintenanceTimeWindowsSatisfied, - false); + isMaintenanceTimeWindowsSatisfied + ); assertThat(new String(newCerts.get("pod0").cert()), is("old-cert")); assertThat(new String(newCerts.get("pod0").key()), is("old-key")); @@ -224,8 +189,8 @@ public void renewalOfCertificatesWithNewNodesOutsideWindow() throws IOException NODES, SUBJECT_FN, initialCerts, - isMaintenanceTimeWindowsSatisfied, - false); + isMaintenanceTimeWindowsSatisfied + ); assertThat(new String(newCerts.get("pod0").cert()), is("old-cert")); assertThat(new String(newCerts.get("pod0").key()), is("old-key")); @@ -251,8 +216,8 @@ public void noRenewal() throws IOException { NODES, SUBJECT_FN, initialCerts, - true, - false); + true + ); assertThat(new String(newCerts.get("pod0").cert()), is("old-cert")); assertThat(new String(newCerts.get("pod0").key()), is("old-key")); @@ -276,8 +241,8 @@ public void noRenewalWithScaleUp() throws IOException { NODES, SUBJECT_FN, initialCerts, - true, - false); + true + ); assertThat(new String(newCerts.get("pod0").cert()), is("old-cert")); assertThat(new String(newCerts.get("pod0").key()), is("old-key")); @@ -302,8 +267,8 @@ public void noRenewalWithScaleUpInTheMiddle() throws IOException { NODES, SUBJECT_FN, initialCerts, - true, - false); + true + ); assertThat(new String(newCerts.get("pod0").cert()), is("old-cert")); assertThat(new String(newCerts.get("pod0").key()), is("old-key")); @@ -329,8 +294,8 @@ public void noRenewalScaleDown() throws IOException { Set.of(new NodeRef("pod1", 1, null, false, true)), SUBJECT_FN, initialCerts, - true, - false); + true + ); assertThat(newCerts.get("pod0"), is(nullValue())); @@ -357,8 +322,8 @@ public void changedSubject() throws IOException { NODES, node -> new Subject.Builder().withCommonName(node.podName()).build(), initialCerts, - isMaintenanceTimeWindowsSatisfied, - false); + isMaintenanceTimeWindowsSatisfied + ); assertThat(new String(newCerts.get("pod0").cert()), is("new-cert0")); assertThat(new String(newCerts.get("pod0").key()), is("new-key0")); diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaClusterTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaClusterTest.java index f398011466..adde95c0e1 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaClusterTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaClusterTest.java @@ -256,13 +256,13 @@ private void checkHeadlessService(Service headless) { assertThat(headless.getMetadata().getLabels().containsKey(Labels.STRIMZI_DISCOVERY_LABEL), is(false)); } - private Secret generateBrokerSecret(Set externalBootstrapAddress, Map> externalAddresses) { + private List generateBrokerSecrets(Set externalBootstrapAddress, Map> externalAddresses) { ClusterCa clusterCa = new ClusterCa(Reconciliation.DUMMY_RECONCILIATION, new OpenSslCertManager(), new PasswordGenerator(10, "a", "a"), CLUSTER, null, null); clusterCa.createRenewOrReplace(NAMESPACE, Map.of(), Map.of(), Map.of(), null, true); ClientsCa clientsCa = new ClientsCa(Reconciliation.DUMMY_RECONCILIATION, new OpenSslCertManager(), new PasswordGenerator(10, "a", "a"), null, null, null, null, 365, 30, true, CertificateExpirationPolicy.RENEW_CERTIFICATE); clientsCa.createRenewOrReplace(NAMESPACE, Map.of(), Map.of(), Map.of(), null, true); - return KC.generateCertificatesSecret(clusterCa, clientsCa, null, externalBootstrapAddress, externalAddresses, true); + return KC.generateCertificatesSecrets(clusterCa, clientsCa, List.of(), externalBootstrapAddress, externalAddresses, true); } ////////// @@ -1177,8 +1177,14 @@ public void testPerBrokerConfigMaps() { @ParallelTest public void testGenerateBrokerSecret() throws CertificateParsingException { - Secret secret = generateBrokerSecret(null, Map.of()); - assertThat(secret.getData().keySet(), is(Set.of( + List secrets = generateBrokerSecrets(null, Map.of()); + Set secretDataKeys = new HashSet<>(); + Map secretMap = new HashMap<>(); + secrets.forEach(secret -> { + secretDataKeys.addAll(secret.getData().keySet()); + secretMap.put(secret.getMetadata().getName(), secret); + }); + assertThat(secretDataKeys, is(Set.of( "foo-controllers-0.crt", "foo-controllers-0.key", "foo-controllers-1.crt", "foo-controllers-1.key", "foo-controllers-2.crt", "foo-controllers-2.key", @@ -1188,7 +1194,7 @@ public void testGenerateBrokerSecret() throws CertificateParsingException { "foo-brokers-6.crt", "foo-brokers-6.key", "foo-brokers-7.crt", "foo-brokers-7.key"))); - X509Certificate cert = Ca.cert(secret, "foo-controllers-0.crt"); + X509Certificate cert = Ca.cert(secretMap.get("foo-controllers-0"), "foo-controllers-0.crt"); assertThat(cert.getSubjectX500Principal().getName(), is("CN=foo-kafka,O=io.strimzi")); assertThat(cert.getSubjectAlternativeNames().size(), is(10)); assertThat(new HashSet(cert.getSubjectAlternativeNames()), is(Set.of( @@ -1203,7 +1209,7 @@ public void testGenerateBrokerSecret() throws CertificateParsingException { List.of(2, "foo-kafka-brokers.test.svc"), List.of(2, "foo-kafka-brokers.test.svc.cluster.local")))); - cert = Ca.cert(secret, "foo-mixed-3.crt"); + cert = Ca.cert(secretMap.get("foo-mixed-3"), "foo-mixed-3.crt"); assertThat(cert.getSubjectX500Principal().getName(), is("CN=foo-kafka,O=io.strimzi")); assertThat(cert.getSubjectAlternativeNames().size(), is(10)); assertThat(new HashSet(cert.getSubjectAlternativeNames()), is(Set.of( @@ -1218,7 +1224,7 @@ public void testGenerateBrokerSecret() throws CertificateParsingException { List.of(2, "foo-kafka-brokers.test.svc"), List.of(2, "foo-kafka-brokers.test.svc.cluster.local")))); - cert = Ca.cert(secret, "foo-brokers-6.crt"); + cert = Ca.cert(secretMap.get("foo-brokers-6"), "foo-brokers-6.crt"); assertThat(cert.getSubjectX500Principal().getName(), is("CN=foo-kafka,O=io.strimzi")); assertThat(cert.getSubjectAlternativeNames().size(), is(10)); assertThat(new HashSet(cert.getSubjectAlternativeNames()), is(Set.of( @@ -1241,8 +1247,14 @@ public void testGenerateBrokerSecretExternal() throws CertificateParsingExceptio 3, Set.of("123.10.125.133"), 6, Set.of("123.10.125.136")); - Secret secret = generateBrokerSecret(Set.of("123.10.125.140"), externalAddresses); - assertThat(secret.getData().keySet(), is(Set.of( + List secrets = generateBrokerSecrets(Set.of("123.10.125.140"), externalAddresses); + Set secretDataKeys = new HashSet<>(); + Map secretMap = new HashMap<>(); + secrets.forEach(secret -> { + secretDataKeys.addAll(secret.getData().keySet()); + secretMap.put(secret.getMetadata().getName(), secret); + }); + assertThat(secretDataKeys, is(Set.of( "foo-controllers-0.crt", "foo-controllers-0.key", "foo-controllers-1.crt", "foo-controllers-1.key", "foo-controllers-2.crt", "foo-controllers-2.key", @@ -1252,7 +1264,7 @@ public void testGenerateBrokerSecretExternal() throws CertificateParsingExceptio "foo-brokers-6.crt", "foo-brokers-6.key", "foo-brokers-7.crt", "foo-brokers-7.key"))); - X509Certificate cert = Ca.cert(secret, "foo-controllers-0.crt"); + X509Certificate cert = Ca.cert(secretMap.get("foo-controllers-0"), "foo-controllers-0.crt"); assertThat(cert.getSubjectX500Principal().getName(), is("CN=foo-kafka,O=io.strimzi")); assertThat(cert.getSubjectAlternativeNames().size(), is(10)); assertThat(new HashSet(cert.getSubjectAlternativeNames()), is(Set.of( @@ -1267,7 +1279,7 @@ public void testGenerateBrokerSecretExternal() throws CertificateParsingExceptio List.of(2, "foo-kafka-brokers.test.svc"), List.of(2, "foo-kafka-brokers.test.svc.cluster.local")))); - cert = Ca.cert(secret, "foo-mixed-3.crt"); + cert = Ca.cert(secretMap.get("foo-mixed-3"), "foo-mixed-3.crt"); assertThat(cert.getSubjectX500Principal().getName(), is("CN=foo-kafka,O=io.strimzi")); assertThat(cert.getSubjectAlternativeNames().size(), is(12)); assertThat(new HashSet(cert.getSubjectAlternativeNames()), is(Set.of( @@ -1284,7 +1296,7 @@ public void testGenerateBrokerSecretExternal() throws CertificateParsingExceptio List.of(7, "123.10.125.140"), List.of(7, "123.10.125.133")))); - cert = Ca.cert(secret, "foo-brokers-6.crt"); + cert = Ca.cert(secretMap.get("foo-brokers-6"), "foo-brokers-6.crt"); assertThat(cert.getSubjectX500Principal().getName(), is("CN=foo-kafka,O=io.strimzi")); assertThat(cert.getSubjectAlternativeNames().size(), is(12)); assertThat(new HashSet(cert.getSubjectAlternativeNames()), is(Set.of( @@ -1309,8 +1321,15 @@ public void testGenerateBrokerSecretExternalWithManyDNS() throws CertificatePars 3, Set.of("123.10.125.133", "my-broker-3"), 6, Set.of("123.10.125.136", "my-broker-6")); - Secret secret = generateBrokerSecret(Set.of("123.10.125.140", "my-bootstrap"), externalAddresses); - assertThat(secret.getData().keySet(), is(Set.of( + List secrets = generateBrokerSecrets(Set.of("123.10.125.140", "my-bootstrap"), externalAddresses); + Set secretDataKeys = new HashSet<>(); + Map secretMap = new HashMap<>(); + secrets.forEach(secret -> { + secretDataKeys.addAll(secret.getData().keySet()); + secretMap.put(secret.getMetadata().getName(), secret); + }); + + assertThat(secretDataKeys, is(Set.of( "foo-controllers-0.crt", "foo-controllers-0.key", "foo-controllers-1.crt", "foo-controllers-1.key", "foo-controllers-2.crt", "foo-controllers-2.key", @@ -1320,7 +1339,7 @@ public void testGenerateBrokerSecretExternalWithManyDNS() throws CertificatePars "foo-brokers-6.crt", "foo-brokers-6.key", "foo-brokers-7.crt", "foo-brokers-7.key"))); - X509Certificate cert = Ca.cert(secret, "foo-controllers-0.crt"); + X509Certificate cert = Ca.cert(secretMap.get("foo-controllers-0"), "foo-controllers-0.crt"); assertThat(cert.getSubjectX500Principal().getName(), is("CN=foo-kafka,O=io.strimzi")); assertThat(cert.getSubjectAlternativeNames().size(), is(10)); assertThat(new HashSet(cert.getSubjectAlternativeNames()), is(Set.of( @@ -1335,7 +1354,7 @@ public void testGenerateBrokerSecretExternalWithManyDNS() throws CertificatePars List.of(2, "foo-kafka-brokers.test.svc"), List.of(2, "foo-kafka-brokers.test.svc.cluster.local")))); - cert = Ca.cert(secret, "foo-mixed-3.crt"); + cert = Ca.cert(secretMap.get("foo-mixed-3"), "foo-mixed-3.crt"); assertThat(cert.getSubjectX500Principal().getName(), is("CN=foo-kafka,O=io.strimzi")); assertThat(cert.getSubjectAlternativeNames().size(), is(14)); assertThat(new HashSet(cert.getSubjectAlternativeNames()), is(Set.of( @@ -1354,7 +1373,7 @@ public void testGenerateBrokerSecretExternalWithManyDNS() throws CertificatePars List.of(7, "123.10.125.140"), List.of(7, "123.10.125.133")))); - cert = Ca.cert(secret, "foo-brokers-6.crt"); + cert = Ca.cert(secretMap.get("foo-brokers-6"), "foo-brokers-6.crt"); assertThat(cert.getSubjectX500Principal().getName(), is("CN=foo-kafka,O=io.strimzi")); assertThat(cert.getSubjectAlternativeNames().size(), is(14)); assertThat(new HashSet(cert.getSubjectAlternativeNames()), is(Set.of( @@ -3355,7 +3374,7 @@ public void testPodSet() { assertThat(pod.getSpec().getVolumes().get(2).getName(), is(KafkaCluster.CLUSTER_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(2).getSecret().getSecretName(), is("foo-cluster-ca-cert")); assertThat(pod.getSpec().getVolumes().get(3).getName(), is(KafkaCluster.BROKER_CERTS_VOLUME)); - assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is("foo-kafka-brokers")); + assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is(pod.getMetadata().getName())); assertThat(pod.getSpec().getVolumes().get(4).getName(), is(KafkaCluster.CLIENT_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(4).getSecret().getSecretName(), is("foo-clients-ca-cert")); assertThat(pod.getSpec().getVolumes().get(5).getName(), is("kafka-metrics-and-logging")); @@ -3421,7 +3440,7 @@ public void testPodSet() { assertThat(pod.getSpec().getVolumes().get(2).getName(), is(KafkaCluster.CLUSTER_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(2).getSecret().getSecretName(), is("foo-cluster-ca-cert")); assertThat(pod.getSpec().getVolumes().get(3).getName(), is(KafkaCluster.BROKER_CERTS_VOLUME)); - assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is("foo-kafka-brokers")); + assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is(pod.getMetadata().getName())); assertThat(pod.getSpec().getVolumes().get(4).getName(), is(KafkaCluster.CLIENT_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(4).getSecret().getSecretName(), is("foo-clients-ca-cert")); assertThat(pod.getSpec().getVolumes().get(5).getName(), is("kafka-metrics-and-logging")); @@ -3487,7 +3506,7 @@ public void testPodSet() { assertThat(pod.getSpec().getVolumes().get(2).getName(), is(KafkaCluster.CLUSTER_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(2).getSecret().getSecretName(), is("foo-cluster-ca-cert")); assertThat(pod.getSpec().getVolumes().get(3).getName(), is(KafkaCluster.BROKER_CERTS_VOLUME)); - assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is("foo-kafka-brokers")); + assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is(pod.getMetadata().getName())); assertThat(pod.getSpec().getVolumes().get(4).getName(), is(KafkaCluster.CLIENT_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(4).getSecret().getSecretName(), is("foo-clients-ca-cert")); assertThat(pod.getSpec().getVolumes().get(5).getName(), is("kafka-metrics-and-logging")); @@ -3711,7 +3730,7 @@ public void testCustomizedPodSet() { assertThat(pod.getSpec().getVolumes().get(2).getName(), is(KafkaCluster.CLUSTER_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(2).getSecret().getSecretName(), is("foo-cluster-ca-cert")); assertThat(pod.getSpec().getVolumes().get(3).getName(), is(KafkaCluster.BROKER_CERTS_VOLUME)); - assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is("foo-kafka-brokers")); + assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is(pod.getMetadata().getName())); assertThat(pod.getSpec().getVolumes().get(4).getName(), is(KafkaCluster.CLIENT_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(4).getSecret().getSecretName(), is("foo-clients-ca-cert")); assertThat(pod.getSpec().getVolumes().get(5).getName(), is("kafka-metrics-and-logging")); @@ -4054,7 +4073,7 @@ public void testCustomizedPodSetInKafkaAndNodePool() { assertThat(pod.getSpec().getVolumes().get(2).getName(), is(KafkaCluster.CLUSTER_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(2).getSecret().getSecretName(), is("foo-cluster-ca-cert")); assertThat(pod.getSpec().getVolumes().get(3).getName(), is(KafkaCluster.BROKER_CERTS_VOLUME)); - assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is("foo-kafka-brokers")); + assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is(pod.getMetadata().getName())); assertThat(pod.getSpec().getVolumes().get(4).getName(), is(KafkaCluster.CLIENT_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(4).getSecret().getSecretName(), is("foo-clients-ca-cert")); assertThat(pod.getSpec().getVolumes().get(5).getName(), is("kafka-metrics-and-logging")); @@ -4116,7 +4135,7 @@ public void testCustomizedPodSetInKafkaAndNodePool() { assertThat(pod.getSpec().getVolumes().get(2).getName(), is(KafkaCluster.CLUSTER_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(2).getSecret().getSecretName(), is("foo-cluster-ca-cert")); assertThat(pod.getSpec().getVolumes().get(3).getName(), is(KafkaCluster.BROKER_CERTS_VOLUME)); - assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is("foo-kafka-brokers")); + assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is(pod.getMetadata().getName())); assertThat(pod.getSpec().getVolumes().get(4).getName(), is(KafkaCluster.CLIENT_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(4).getSecret().getSecretName(), is("foo-clients-ca-cert")); assertThat(pod.getSpec().getVolumes().get(5).getName(), is("kafka-metrics-and-logging")); @@ -4356,7 +4375,7 @@ public void testCustomizedPodSetInNodePool() { assertThat(pod.getSpec().getVolumes().get(2).getName(), is(KafkaCluster.CLUSTER_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(2).getSecret().getSecretName(), is("foo-cluster-ca-cert")); assertThat(pod.getSpec().getVolumes().get(3).getName(), is(KafkaCluster.BROKER_CERTS_VOLUME)); - assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is("foo-kafka-brokers")); + assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is(pod.getMetadata().getName())); assertThat(pod.getSpec().getVolumes().get(4).getName(), is(KafkaCluster.CLIENT_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(4).getSecret().getSecretName(), is("foo-clients-ca-cert")); assertThat(pod.getSpec().getVolumes().get(5).getName(), is("kafka-metrics-and-logging")); @@ -4420,7 +4439,7 @@ public void testCustomizedPodSetInNodePool() { assertThat(pod.getSpec().getVolumes().get(2).getName(), is(KafkaCluster.CLUSTER_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(2).getSecret().getSecretName(), is("foo-cluster-ca-cert")); assertThat(pod.getSpec().getVolumes().get(3).getName(), is(KafkaCluster.BROKER_CERTS_VOLUME)); - assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is("foo-kafka-brokers")); + assertThat(pod.getSpec().getVolumes().get(3).getSecret().getSecretName(), is(pod.getMetadata().getName())); assertThat(pod.getSpec().getVolumes().get(4).getName(), is(KafkaCluster.CLIENT_CA_CERTS_VOLUME)); assertThat(pod.getSpec().getVolumes().get(4).getSecret().getSecretName(), is("foo-clients-ca-cert")); assertThat(pod.getSpec().getVolumes().get(5).getName(), is("kafka-metrics-and-logging")); diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/CaReconcilerTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/CaReconcilerTest.java index a1f9ae4534..aefef1433b 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/CaReconcilerTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/CaReconcilerTest.java @@ -7,7 +7,6 @@ import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodBuilder; import io.fabric8.kubernetes.api.model.Secret; -import io.fabric8.kubernetes.api.model.SecretBuilder; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.strimzi.api.ResourceAnnotations; @@ -1664,11 +1663,6 @@ public void testUserManagedClusterCaKeyReplaced(Vertx vertx, VertxTestContext co List clientsCaSecrets = initialClientsCaSecrets(certificateAuthority); - // Kafka brokers Secret with old annotation - Secret kafkaBrokersSecret = kafkaBrokersSecretWithAnnotations(Map.of( - Ca.ANNO_STRIMZI_IO_CLUSTER_CA_CERT_GENERATION, "0", - Ca.ANNO_STRIMZI_IO_CLIENTS_CA_CERT_GENERATION, "0")); - Map generationAnnotations = Map.of(Ca.ANNO_STRIMZI_IO_CLUSTER_CA_CERT_GENERATION, "0", Ca.ANNO_STRIMZI_IO_CLUSTER_CA_KEY_GENERATION, "0", @@ -1686,8 +1680,7 @@ public void testUserManagedClusterCaKeyReplaced(Vertx vertx, VertxTestContext co initTrustRolloutTestMocks(supplier, List.of(clusterCaKeySecret, clusterCaCertSecret, - clientsCaSecrets.get(0), clientsCaSecrets.get(1), - kafkaBrokersSecret), + clientsCaSecrets.get(0), clientsCaSecrets.get(1)), controllerPods, brokerPods); @@ -1754,11 +1747,6 @@ public void testUserManagedClusterCaCertRenewed(Vertx vertx, VertxTestContext co List clientsCaSecrets = initialClientsCaSecrets(certificateAuthority); - // Kafka brokers Secret with old annotation - Secret kafkaBrokersSecret = kafkaBrokersSecretWithAnnotations(Map.of( - Ca.ANNO_STRIMZI_IO_CLUSTER_CA_CERT_GENERATION, "0", - Ca.ANNO_STRIMZI_IO_CLIENTS_CA_CERT_GENERATION, "0")); - Map generationAnnotations = Map.of(Ca.ANNO_STRIMZI_IO_CLUSTER_CA_CERT_GENERATION, "0", Ca.ANNO_STRIMZI_IO_CLUSTER_CA_KEY_GENERATION, "0", @@ -1776,8 +1764,7 @@ public void testUserManagedClusterCaCertRenewed(Vertx vertx, VertxTestContext co initTrustRolloutTestMocks(supplier, List.of(clusterCaSecrets.get(0), clusterCaCertSecret, - clientsCaSecrets.get(0), clientsCaSecrets.get(1), - kafkaBrokersSecret), + clientsCaSecrets.get(0), clientsCaSecrets.get(1)), controllerPods, brokerPods); @@ -1985,11 +1972,6 @@ public void testUserManagedClientsCaKeyReplaced(Vertx vertx, VertxTestContext co .endMetadata() .build(); - // Kafka brokers Secret with old annotation - Secret kafkaBrokersSecret = kafkaBrokersSecretWithAnnotations(Map.of( - Ca.ANNO_STRIMZI_IO_CLUSTER_CA_CERT_GENERATION, "0", - Ca.ANNO_STRIMZI_IO_CLIENTS_CA_CERT_GENERATION, "0")); - Map generationAnnotations = Map.of(Ca.ANNO_STRIMZI_IO_CLUSTER_CA_CERT_GENERATION, "0", Ca.ANNO_STRIMZI_IO_CLUSTER_CA_KEY_GENERATION, "0", @@ -2007,8 +1989,7 @@ public void testUserManagedClientsCaKeyReplaced(Vertx vertx, VertxTestContext co initTrustRolloutTestMocks(supplier, List.of(clusterCaSecrets.get(0), clusterCaSecrets.get(1), - clientsCaKeySecret, clientsCaCertSecret, - kafkaBrokersSecret), + clientsCaKeySecret, clientsCaCertSecret), controllerPods, brokerPods); @@ -2051,11 +2032,6 @@ public void testUserManagedClientsCaCertRenewed(Vertx vertx, VertxTestContext co .endMetadata() .build(); - // Kafka brokers Secret with old annotation - Secret kafkaBrokersSecret = kafkaBrokersSecretWithAnnotations(Map.of( - Ca.ANNO_STRIMZI_IO_CLUSTER_CA_CERT_GENERATION, "0", - Ca.ANNO_STRIMZI_IO_CLIENTS_CA_CERT_GENERATION, "0")); - Map generationAnnotations = Map.of(Ca.ANNO_STRIMZI_IO_CLUSTER_CA_CERT_GENERATION, "0", Ca.ANNO_STRIMZI_IO_CLUSTER_CA_KEY_GENERATION, "0", @@ -2073,8 +2049,7 @@ public void testUserManagedClientsCaCertRenewed(Vertx vertx, VertxTestContext co initTrustRolloutTestMocks(supplier, List.of(clusterCaSecrets.get(0), clusterCaSecrets.get(1), - clientsCaSecrets.get(0), clientsCaCertSecret, - kafkaBrokersSecret), + clientsCaSecrets.get(0), clientsCaCertSecret), controllerPods, brokerPods); @@ -2196,15 +2171,6 @@ private static Deployment deploymentWithName(String name) { .build(); } - private static Secret kafkaBrokersSecretWithAnnotations(Map annotations) { - return new SecretBuilder() - .withNewMetadata() - .withName(KafkaResources.kafkaSecretName(NAME)) - .withAnnotations(annotations) - .endMetadata() - .build(); - } - private static CertificateAuthority getCertificateAuthority() { return new CertificateAuthorityBuilder() .withValidityDays(100) diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaAssemblyOperatorKRaftMockTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaAssemblyOperatorKRaftMockTest.java index 7f78b6ce10..db5b396747 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaAssemblyOperatorKRaftMockTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaAssemblyOperatorKRaftMockTest.java @@ -228,9 +228,9 @@ private void basicCheck() { assertThat(actualPod.getMetadata().getAnnotations(), hasEntry(Ca.ANNO_STRIMZI_IO_CLIENTS_CA_CERT_GENERATION, "0")); assertThat(actualPod.getMetadata().getAnnotations(), hasEntry(Ca.ANNO_STRIMZI_IO_CLUSTER_CA_CERT_GENERATION, "0")); - Secret brokersSecret = client.secrets().inNamespace(namespace).withName(KafkaResources.kafkaSecretName(CLUSTER_NAME)).get(); - assertThat(desiredPod.getMetadata().getAnnotations(), hasEntry(Annotations.ANNO_STRIMZI_SERVER_CERT_HASH, CertUtils.getCertificateThumbprint(brokersSecret, Ca.SecretEntry.CRT.asKey(desiredPod.getMetadata().getName())))); - assertThat(actualPod.getMetadata().getAnnotations(), hasEntry(Annotations.ANNO_STRIMZI_SERVER_CERT_HASH, CertUtils.getCertificateThumbprint(brokersSecret, Ca.SecretEntry.CRT.asKey(desiredPod.getMetadata().getName())))); + Secret certSecret = client.secrets().inNamespace(namespace).withName(desiredPod.getMetadata().getName()).get(); + assertThat(desiredPod.getMetadata().getAnnotations(), hasEntry(Annotations.ANNO_STRIMZI_SERVER_CERT_HASH, CertUtils.getCertificateThumbprint(certSecret, Ca.SecretEntry.CRT.asKey(desiredPod.getMetadata().getName())))); + assertThat(actualPod.getMetadata().getAnnotations(), hasEntry(Annotations.ANNO_STRIMZI_SERVER_CERT_HASH, CertUtils.getCertificateThumbprint(certSecret, Ca.SecretEntry.CRT.asKey(desiredPod.getMetadata().getName())))); assertThat(client.configMaps().inNamespace(namespace).withName(desiredPod.getMetadata().getName()).get(), is(notNullValue())); }); @@ -246,9 +246,9 @@ private void basicCheck() { assertThat(actualPod.getMetadata().getAnnotations(), hasEntry(Ca.ANNO_STRIMZI_IO_CLIENTS_CA_CERT_GENERATION, "0")); assertThat(actualPod.getMetadata().getAnnotations(), hasEntry(Ca.ANNO_STRIMZI_IO_CLUSTER_CA_CERT_GENERATION, "0")); - Secret brokersSecret = client.secrets().inNamespace(namespace).withName(KafkaResources.kafkaSecretName(CLUSTER_NAME)).get(); - assertThat(desiredPod.getMetadata().getAnnotations(), hasEntry(Annotations.ANNO_STRIMZI_SERVER_CERT_HASH, CertUtils.getCertificateThumbprint(brokersSecret, Ca.SecretEntry.CRT.asKey(desiredPod.getMetadata().getName())))); - assertThat(actualPod.getMetadata().getAnnotations(), hasEntry(Annotations.ANNO_STRIMZI_SERVER_CERT_HASH, CertUtils.getCertificateThumbprint(brokersSecret, Ca.SecretEntry.CRT.asKey(desiredPod.getMetadata().getName())))); + Secret certSecret = client.secrets().inNamespace(namespace).withName(desiredPod.getMetadata().getName()).get(); + assertThat(desiredPod.getMetadata().getAnnotations(), hasEntry(Annotations.ANNO_STRIMZI_SERVER_CERT_HASH, CertUtils.getCertificateThumbprint(certSecret, Ca.SecretEntry.CRT.asKey(desiredPod.getMetadata().getName())))); + assertThat(actualPod.getMetadata().getAnnotations(), hasEntry(Annotations.ANNO_STRIMZI_SERVER_CERT_HASH, CertUtils.getCertificateThumbprint(certSecret, Ca.SecretEntry.CRT.asKey(desiredPod.getMetadata().getName())))); assertThat(client.configMaps().inNamespace(namespace).withName(desiredPod.getMetadata().getName()).get(), is(notNullValue())); }); @@ -301,7 +301,12 @@ public void testReconcileReplacesAllDeletedSecrets(VertxTestContext context) { List secrets = List.of(KafkaResources.clientsCaKeySecretName(CLUSTER_NAME), KafkaResources.clientsCaCertificateSecretName(CLUSTER_NAME), KafkaResources.clusterCaCertificateSecretName(CLUSTER_NAME), - KafkaResources.kafkaSecretName(CLUSTER_NAME), + CLUSTER_NAME + "-controllers-0", + CLUSTER_NAME + "-controllers-1", + CLUSTER_NAME + "-controllers-2", + CLUSTER_NAME + "-brokers-10", + CLUSTER_NAME + "-brokers-11", + CLUSTER_NAME + "-brokers-12", KafkaResources.clusterOperatorCertsSecretName(CLUSTER_NAME)); Checkpoint async = context.checkpoint(); @@ -533,7 +538,9 @@ public void testReconcileKafkaScaleUpAndDown(VertxTestContext context) { operator.reconcile(new Reconciliation("initial-trigger", Kafka.RESOURCE_KIND, namespace, CLUSTER_NAME)) .onComplete(context.succeeding(v -> context.verify(() -> { - assertThat(client.secrets().inNamespace(namespace).withName(KafkaResources.kafkaSecretName(CLUSTER_NAME)).get().getData().size(), is(12)); + assertThat(client.secrets().inNamespace(namespace).withLabels(Labels.fromMap(kafkaLabels).withStrimziComponentType("kafka").toMap()).list().getItems().size(), is(6)); + assertThat(client.secrets().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-13").get(), is(nullValue())); + assertThat(client.secrets().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-14").get(), is(nullValue())); assertThat(client.pods().inNamespace(namespace).withLabels(kafkaLabels).list().getItems().size(), is(6)); assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-13").get(), is(nullValue())); assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-14").get(), is(nullValue())); @@ -547,7 +554,9 @@ public void testReconcileKafkaScaleUpAndDown(VertxTestContext context) { }))) .compose(v -> operator.reconcile(new Reconciliation("test-trigger", Kafka.RESOURCE_KIND, namespace, CLUSTER_NAME))) .onComplete(context.succeeding(v -> context.verify(() -> { - assertThat(client.secrets().inNamespace(namespace).withName(KafkaResources.kafkaSecretName(CLUSTER_NAME)).get().getData().size(), is(16)); + assertThat(client.secrets().inNamespace(namespace).withLabels(Labels.fromMap(kafkaLabels).withStrimziComponentType("kafka").toMap()).list().getItems().size(), is(8)); + assertThat(client.secrets().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-13").get(), is(notNullValue())); + assertThat(client.secrets().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-14").get(), is(notNullValue())); assertThat(client.pods().inNamespace(namespace).withLabels(kafkaLabels).list().getItems().size(), is(8)); assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-13").get(), is(notNullValue())); assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-14").get(), is(notNullValue())); @@ -578,7 +587,9 @@ public void testReconcileKafkaScaleUpAndDown(VertxTestContext context) { }))) .compose(v -> operator.reconcile(new Reconciliation("test-trigger2", Kafka.RESOURCE_KIND, namespace, CLUSTER_NAME))) .onComplete(context.succeeding(v -> context.verify(() -> { - assertThat(client.secrets().inNamespace(namespace).withName(KafkaResources.kafkaSecretName(CLUSTER_NAME)).get().getData().size(), is(12)); + assertThat(client.secrets().inNamespace(namespace).withLabels(Labels.fromMap(kafkaLabels).withStrimziComponentType("kafka").toMap()).list().getItems().size(), is(6)); + assertThat(client.secrets().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-13").get(), is(nullValue())); + assertThat(client.secrets().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-14").get(), is(nullValue())); assertThat(client.pods().inNamespace(namespace).withLabels(kafkaLabels).list().getItems().size(), is(6)); assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-13").get(), is(nullValue())); assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-brokers-14").get(), is(nullValue())); @@ -620,8 +631,14 @@ public void testReconcileAddAndRemovePool(VertxTestContext context) { operator.reconcile(new Reconciliation("initial-trigger", Kafka.RESOURCE_KIND, namespace, CLUSTER_NAME)) .onComplete(context.succeeding(v -> context.verify(() -> { - assertThat(client.secrets().inNamespace(namespace).withName(KafkaResources.kafkaSecretName(CLUSTER_NAME)).get().getData().size(), is(12)); - assertThat(client.pods().inNamespace(namespace).withLabels(kafkaLabels).list().getItems().size(), is(6)); + assertThat(client.secrets().inNamespace(namespace).withLabels(Labels.fromMap(kafkaLabels).withStrimziComponentType("kafka").toMap()).list().getItems().size(), is(6)); + List initialPods = client.pods().inNamespace(namespace).withLabels(kafkaLabels).list().getItems(); + assertThat(initialPods.size(), is(6)); + for (Pod pod : initialPods) { + Secret certSecret = client.secrets().inNamespace(namespace).withName(pod.getMetadata().getName()).get(); + assertThat(certSecret, is(notNullValue())); + assertThat(certSecret.getData().keySet(), hasItems(pod.getMetadata().getName() + ".crt", pod.getMetadata().getName() + ".key")); + } KafkaNodePool newPool = new KafkaNodePoolBuilder() .withNewMetadata() @@ -645,11 +662,19 @@ public void testReconcileAddAndRemovePool(VertxTestContext context) { .compose(v -> operator.reconcile(new Reconciliation("test-trigger", Kafka.RESOURCE_KIND, namespace, CLUSTER_NAME))) .onComplete(context.succeeding(v -> context.verify(() -> { // Assert that the new pool is added - assertThat(client.secrets().inNamespace(namespace).withName(KafkaResources.kafkaSecretName(CLUSTER_NAME)).get().getData().size(), is(18)); + assertThat(client.secrets().inNamespace(namespace).withLabels(Labels.fromMap(kafkaLabels).withStrimziComponentType("kafka").toMap()).list().getItems().size(), is(9)); assertThat(client.pods().inNamespace(namespace).withLabels(kafkaLabels).list().getItems().size(), is(9)); - assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-new-pool-13").get(), is(notNullValue())); - assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-new-pool-14").get(), is(notNullValue())); - assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-new-pool-15").get(), is(notNullValue())); + List expectedNewResources = List.of( + CLUSTER_NAME + "-new-pool-13", + CLUSTER_NAME + "-new-pool-14", + CLUSTER_NAME + "-new-pool-15" + ); + for (String resourceName : expectedNewResources) { + assertThat(client.pods().inNamespace(namespace).withName(resourceName).get(), is(notNullValue())); + Secret certSecret = client.secrets().inNamespace(namespace).withName(resourceName).get(); + assertThat(certSecret, is(notNullValue())); + assertThat(certSecret.getData().keySet(), hasItems(resourceName + ".crt", resourceName + ".key")); + } Kafka kafka = Crds.kafkaOperation(client).inNamespace(namespace).withName(CLUSTER_NAME).get(); assertThat(kafka.getStatus().getKafkaNodePools().size(), is(3)); @@ -681,11 +706,17 @@ public void testReconcileAddAndRemovePool(VertxTestContext context) { .compose(v -> operator.reconcile(new Reconciliation("test-trigger2", Kafka.RESOURCE_KIND, namespace, CLUSTER_NAME))) .onComplete(context.succeeding(v -> context.verify(() -> { // Assert that the new pool is deleted - assertThat(client.secrets().inNamespace(namespace).withName(KafkaResources.kafkaSecretName(CLUSTER_NAME)).get().getData().size(), is(12)); + assertThat(client.secrets().inNamespace(namespace).withLabels(Labels.fromMap(kafkaLabels).withStrimziComponentType("kafka").toMap()).list().getItems().size(), is(6)); assertThat(client.pods().inNamespace(namespace).withLabels(kafkaLabels).list().getItems().size(), is(6)); - assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-new-pool-13").get(), is(nullValue())); - assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-new-pool-14").get(), is(nullValue())); - assertThat(client.pods().inNamespace(namespace).withName(CLUSTER_NAME + "-new-pool-15").get(), is(nullValue())); + List expectedDeletedResources = List.of( + CLUSTER_NAME + "-new-pool-13", + CLUSTER_NAME + "-new-pool-14", + CLUSTER_NAME + "-new-pool-15" + ); + for (String resourceName : expectedDeletedResources) { + assertThat(client.pods().inNamespace(namespace).withName(resourceName).get(), is(nullValue())); + assertThat(client.secrets().inNamespace(namespace).withName(resourceName).get(), is(nullValue())); + } Kafka kafka = Crds.kafkaOperation(client).inNamespace(namespace).withName(CLUSTER_NAME).get(); assertThat(kafka.getStatus().getKafkaNodePools().size(), is(2)); diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaAssemblyOperatorTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaAssemblyOperatorTest.java index 0098d8b68c..3c6124b828 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaAssemblyOperatorTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaAssemblyOperatorTest.java @@ -527,9 +527,11 @@ private void createCluster(VertxTestContext context, Kafka kafka, List expectedSecrets.add(node.podName())); + if (metrics) { expectedSecrets.add(KafkaExporterResources.secretName(CLUSTER_NAME)); } diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/PartialRollingUpdateMockTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/PartialRollingUpdateMockTest.java index 45f51ffd88..70d9d5c9e9 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/PartialRollingUpdateMockTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/PartialRollingUpdateMockTest.java @@ -56,6 +56,7 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -258,13 +259,15 @@ public void testReconcileOfPartiallyRolledKafkaClusterForServerCertificates(Vert Checkpoint async = context.checkpoint(); // Check the initial state first - Secret brokersSecret = client.secrets().inNamespace(namespace).withName(KafkaResources.kafkaSecretName(CLUSTER_NAME)).get(); + Map certSecrets = client.secrets().inNamespace(namespace).withLabels(Map.of(Labels.STRIMZI_NAME_LABEL, KafkaResources.kafkaComponentName(CLUSTER_NAME))).list().getItems() + .stream().collect(Collectors.toMap(secret -> secret.getMetadata().getName(), secret -> secret)); + context.verify(() -> assertThat(certSecrets.size(), is(6))); List initialPods = client.pods().inNamespace(namespace).withLabels(Map.of(Labels.STRIMZI_NAME_LABEL, KafkaResources.kafkaComponentName(CLUSTER_NAME))).list().getItems(); context.verify(() -> assertThat(initialPods.size(), is(6))); for (Pod pod : initialPods) { String podCertHash = pod.getMetadata().getAnnotations().get(Annotations.ANNO_STRIMZI_SERVER_CERT_HASH); - String expectedCertHash = CertUtils.getCertificateThumbprint(brokersSecret, Ca.SecretEntry.CRT.asKey(pod.getMetadata().getName())); + String expectedCertHash = CertUtils.getCertificateThumbprint(certSecrets.get(pod.getMetadata().getName()), Ca.SecretEntry.CRT.asKey(pod.getMetadata().getName())); context.verify(() -> assertThat(podCertHash, is(expectedCertHash))); } @@ -280,7 +283,7 @@ public void testReconcileOfPartiallyRolledKafkaClusterForServerCertificates(Vert for (Pod pod : initialPods) { String podCertHash = pod.getMetadata().getAnnotations().get(Annotations.ANNO_STRIMZI_SERVER_CERT_HASH); - String expectedCertHash = CertUtils.getCertificateThumbprint(brokersSecret, Ca.SecretEntry.CRT.asKey(pod.getMetadata().getName())); + String expectedCertHash = CertUtils.getCertificateThumbprint(certSecrets.get(pod.getMetadata().getName()), Ca.SecretEntry.CRT.asKey(pod.getMetadata().getName())); assertThat(podCertHash, is(expectedCertHash)); } diff --git a/documentation/modules/configuring/ref-list-of-kafka-cluster-resources.adoc b/documentation/modules/configuring/ref-list-of-kafka-cluster-resources.adoc index 0f944d35ca..c9953f4440 100644 --- a/documentation/modules/configuring/ref-list-of-kafka-cluster-resources.adoc +++ b/documentation/modules/configuring/ref-list-of-kafka-cluster-resources.adoc @@ -39,7 +39,7 @@ The following resources are created by the Cluster Operator in the Kubernetes cl `-kafka--bootstrap`:: Bootstrap route for clients connecting from outside the Kubernetes cluster. This resource is created only when an external listener is enabled and set to type `route`. The new route name will be used for all other external listeners. `-kafka--`:: Route for traffic from outside the Kubernetes cluster to individual pods. This resource is created only when an external listener is enabled and set to type `route`. The new route name will be used for all other external listeners. `-kafka-config`:: ConfigMap containing the Kafka ancillary configuration, which is mounted as a volume by the broker pods when the `UseStrimziPodSets` feature gate is disabled. -`-kafka-brokers`:: Secret with Kafka broker keys. +`--_`:: Secret with Kafka node public and private keys. `-network-policy-kafka`:: Network policy managing access to the Kafka services. `strimzi-_namespace-name_--kafka-init`:: Cluster role binding used by the Kafka brokers. `-jmx`:: Secret with JMX username and password used to secure the Kafka broker port. This resource is created only when JMX is enabled in Kafka. diff --git a/documentation/modules/security/ref-certificates-and-secrets.adoc b/documentation/modules/security/ref-certificates-and-secrets.adoc index 1f3c3bded3..db155cd069 100644 --- a/documentation/modules/security/ref-certificates-and-secrets.adoc +++ b/documentation/modules/security/ref-certificates-and-secrets.adoc @@ -97,8 +97,8 @@ Contains the public key of the clients CA. Kafka brokers use the public key to v Secrets for communication between Strimzi components contain a private key and a public key certificate signed by the cluster CA. -`__-kafka-brokers`:: -Contains the private and public keys for Kafka brokers. +`__-__-__`:: +Contains the private and public keys for a Kafka node. Each pod has its own secret. `__-cluster-operator-certs`:: Contains the private and public keys for encrypting communication between the Cluster Operator and Kafka. `__-entity-topic-operator-certs`:: Contains the private and public keys for encrypting communication between the Topic Operator and Kafka. @@ -149,24 +149,18 @@ m¦ca.crt |=== -.Fields in the `__-kafka-brokers` secret +.Fields in the `__-__-__` secret [cols="40,60",options="header",stripes="none",separator=¦] |=== ¦Field ¦Description -m¦__-kafka-__.p12 -¦PKCS #12 store for storing certificates and keys. - -m¦__-kafka-__.password -¦Password for protecting the PKCS #12 store. - -m¦__-kafka-__.crt -¦Certificate for a Kafka broker pod __. Signed by a current or former cluster CA private key in `__-cluster-ca`. +m¦__-kafka-__.crt +¦Certificate for a Kafka pod __. Signed by a current or former cluster CA private key in `__-cluster-ca`. -m¦__-kafka-__.key -¦Private key for a Kafka broker pod `__`. +m¦__-kafka-__.key +¦Private key for a Kafka pod `__`. |=== diff --git a/systemtest/src/test/java/io/strimzi/systemtest/kafka/KafkaST.java b/systemtest/src/test/java/io/strimzi/systemtest/kafka/KafkaST.java index b28d23df01..5912e25cbb 100644 --- a/systemtest/src/test/java/io/strimzi/systemtest/kafka/KafkaST.java +++ b/systemtest/src/test/java/io/strimzi/systemtest/kafka/KafkaST.java @@ -489,9 +489,9 @@ void testRegenerateCertExternalAddressChange() { ); resourceManager.createResourceWithWait(KafkaTemplates.kafkaPersistent(testStorage.getNamespaceName(), testStorage.getClusterName(), 3, 1).build()); - final String brokerSecret = testStorage.getClusterName() + "-kafka-brokers"; - - Secret secretsWithoutExt = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), brokerSecret); + Map secretsWithoutExt = kubeClient(testStorage.getNamespaceName()).listSecrets() + .stream() + .collect(Collectors.toMap(secret -> secret.getMetadata().getName(), secret -> secret)); LOGGER.info("Editing Kafka with external listener"); KafkaResource.replaceKafkaResourceInSpecificNamespace(testStorage.getNamespaceName(), testStorage.getClusterName(), kafka -> { @@ -517,13 +517,12 @@ void testRegenerateCertExternalAddressChange() { RollingUpdateUtils.waitTillComponentHasRolled(testStorage.getNamespaceName(), testStorage.getBrokerSelector(), 3, PodUtils.podSnapshot(testStorage.getNamespaceName(), testStorage.getBrokerSelector())); - Secret secretsWithExt = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), brokerSecret); - LOGGER.info("Checking Secrets"); kubeClient(testStorage.getNamespaceName()).listPodsByPrefixInName(testStorage.getNamespaceName(), StrimziPodSetResource.getBrokerComponentName(testStorage.getClusterName())).forEach(kafkaPod -> { String kafkaPodName = kafkaPod.getMetadata().getName(); - assertThat(secretsWithExt.getData().get(kafkaPodName + ".crt"), is(not(secretsWithoutExt.getData().get(kafkaPodName + ".crt")))); - assertThat(secretsWithExt.getData().get(kafkaPodName + ".key"), is(not(secretsWithoutExt.getData().get(kafkaPodName + ".key")))); + Secret secretWithExt = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), kafkaPodName); + assertThat(secretWithExt.getData().get(kafkaPodName + ".crt"), is(not(secretsWithoutExt.get(kafkaPodName).getData().get(kafkaPodName + ".crt")))); + assertThat(secretWithExt.getData().get(kafkaPodName + ".key"), is(not(secretsWithoutExt.get(kafkaPodName).getData().get(kafkaPodName + ".key")))); }); } diff --git a/systemtest/src/test/java/io/strimzi/systemtest/kafka/listeners/ListenersST.java b/systemtest/src/test/java/io/strimzi/systemtest/kafka/listeners/ListenersST.java index cd6d0c623e..688842565a 100644 --- a/systemtest/src/test/java/io/strimzi/systemtest/kafka/listeners/ListenersST.java +++ b/systemtest/src/test/java/io/strimzi/systemtest/kafka/listeners/ListenersST.java @@ -2762,12 +2762,12 @@ void testAdvertisedHostNamesAppearsInBrokerCerts() throws CertificateException { .endSpec() .build()); - Map secretData = kubeClient().getSecret(testStorage.getNamespaceName(), KafkaResources.brokersServiceName(testStorage.getClusterName())).getData(); List brokerPods = kubeClient().listPodNamesInSpecificNamespace(testStorage.getNamespaceName(), Labels.STRIMZI_KIND_LABEL, Kafka.RESOURCE_KIND) .stream().filter(podName -> podName.contains("kafka")).collect(Collectors.toList()); int index = 0; for (String kafkaBroker : brokerPods) { + Map secretData = kubeClient().getSecret(testStorage.getNamespaceName(), kafkaBroker).getData(); String cert = secretData.get(kafkaBroker + ".crt"); LOGGER.info("Encoding {}.crt", kafkaBroker); diff --git a/systemtest/src/test/java/io/strimzi/systemtest/rollingupdate/AlternativeReconcileTriggersST.java b/systemtest/src/test/java/io/strimzi/systemtest/rollingupdate/AlternativeReconcileTriggersST.java index 01d7c40f81..32ea04a4e0 100644 --- a/systemtest/src/test/java/io/strimzi/systemtest/rollingupdate/AlternativeReconcileTriggersST.java +++ b/systemtest/src/test/java/io/strimzi/systemtest/rollingupdate/AlternativeReconcileTriggersST.java @@ -10,7 +10,6 @@ import io.strimzi.api.kafka.model.kafka.JbodStorage; import io.strimzi.api.kafka.model.kafka.JbodStorageBuilder; import io.strimzi.api.kafka.model.kafka.KRaftMetadataStorage; -import io.strimzi.api.kafka.model.kafka.KafkaResources; import io.strimzi.api.kafka.model.kafka.PersistentClaimStorage; import io.strimzi.api.kafka.model.kafka.PersistentClaimStorageBuilder; import io.strimzi.api.kafka.model.kafka.listener.GenericKafkaListenerBuilder; @@ -223,18 +222,16 @@ void testTriggerRollingUpdateAfterOverrideBootstrap() throws CertificateExceptio RollingUpdateUtils.waitTillComponentHasRolled(testStorage.getNamespaceName(), testStorage.getBrokerSelector(), 3, brokerPods); KafkaUtils.waitForKafkaReady(testStorage.getNamespaceName(), testStorage.getClusterName()); - Map secretData = kubeClient().getSecret(testStorage.getNamespaceName(), KafkaResources.brokersServiceName(testStorage.getClusterName())).getData(); + for (String podName : brokerPods.keySet()) { + Map secretData = kubeClient().getSecret(testStorage.getNamespaceName(), podName).getData(); + String certKey = podName + ".crt"; + LOGGER.info("Encoding {} cert", certKey); + ByteArrayInputStream publicCert = new ByteArrayInputStream(Util.decodeBytesFromBase64(secretData.get(certKey).getBytes())); + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + Certificate certificate = certificateFactory.generateCertificate(publicCert); - for (Map.Entry item : secretData.entrySet()) { - if (item.getKey().endsWith(".crt") && !item.getKey().contains(testStorage.getControllerComponentName())) { - LOGGER.info("Encoding {} cert", item.getKey()); - ByteArrayInputStream publicCert = new ByteArrayInputStream(Util.decodeBytesFromBase64(item.getValue().getBytes())); - CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); - Certificate certificate = certificateFactory.generateCertificate(publicCert); - - LOGGER.info("Verifying that new DNS is in certificate subject alternative names"); - assertThat(certificate.toString(), containsString(bootstrapDns)); - } + LOGGER.info("Verifying that new DNS is in certificate subject alternative names"); + assertThat(certificate.toString(), containsString(bootstrapDns)); } } diff --git a/systemtest/src/test/java/io/strimzi/systemtest/security/SecurityST.java b/systemtest/src/test/java/io/strimzi/systemtest/security/SecurityST.java index 506a5feb4a..d573674c5d 100644 --- a/systemtest/src/test/java/io/strimzi/systemtest/security/SecurityST.java +++ b/systemtest/src/test/java/io/strimzi/systemtest/security/SecurityST.java @@ -1280,7 +1280,7 @@ void testClusterCACertRenew() { Date initialCertEndTime = cacert.getNotAfter(); // Check Broker kafka certificate dates - Secret brokerCertCreationSecret = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), testStorage.getClusterName() + "-kafka-brokers"); + Secret brokerCertCreationSecret = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), brokerPodName); X509Certificate kafkaBrokerCert = SecretUtils.getCertificateFromSecret(brokerCertCreationSecret, brokerPodName + ".crt"); Date initialKafkaBrokerCertStartTime = kafkaBrokerCert.getNotBefore(); @@ -1308,7 +1308,7 @@ void testClusterCACertRenew() { Date changedCertEndTime = cacert.getNotAfter(); // Check renewed Broker kafka certificate dates - brokerCertCreationSecret = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), testStorage.getClusterName() + "-kafka-brokers"); + brokerCertCreationSecret = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), brokerPodName); kafkaBrokerCert = SecretUtils.getCertificateFromSecret(brokerCertCreationSecret, brokerPodName + ".crt"); Date changedKafkaBrokerCertStartTime = kafkaBrokerCert.getNotBefore(); Date changedKafkaBrokerCertEndTime = kafkaBrokerCert.getNotAfter(); diff --git a/systemtest/src/test/java/io/strimzi/systemtest/security/custom/CustomCaST.java b/systemtest/src/test/java/io/strimzi/systemtest/security/custom/CustomCaST.java index 915af375d1..f37f93d922 100644 --- a/systemtest/src/test/java/io/strimzi/systemtest/security/custom/CustomCaST.java +++ b/systemtest/src/test/java/io/strimzi/systemtest/security/custom/CustomCaST.java @@ -250,7 +250,7 @@ void testCustomClusterCaAndClientsCaCertificates() { LOGGER.info("Check Kafka(s) certificates"); String brokerPodName = kubeClient().listPods(testStorage.getNamespaceName(), testStorage.getBrokerSelector()).get(0).getMetadata().getName(); final X509Certificate kafkaCert = SecretUtils.getCertificateFromSecret(kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), - testStorage.getClusterName() + "-kafka-brokers"), brokerPodName + ".crt"); + brokerPodName), brokerPodName + ".crt"); assertThat("KafkaCert does not have expected test Issuer: " + kafkaCert.getIssuerDN(), SystemTestCertManager.containsAllDN(kafkaCert.getIssuerX500Principal().getName(), clusterCa.getSubjectDn())); @@ -304,7 +304,7 @@ void testReplaceCustomClusterCACertificateValidityToInvokeRenewalProcess() { // Check Broker kafka certificate dates String brokerPodName = kubeClient().listPods(testStorage.getNamespaceName(), testStorage.getBrokerSelector()).get(0).getMetadata().getName(); - Secret brokerCertCreationSecret = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), testStorage.getClusterName() + "-kafka-brokers"); + Secret brokerCertCreationSecret = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), brokerPodName); X509Certificate kafkaBrokerCert = SecretUtils.getCertificateFromSecret(brokerCertCreationSecret, brokerPodName + ".crt"); final Date initialKafkaBrokerCertStartTime = kafkaBrokerCert.getNotBefore(); final Date initialKafkaBrokerCertEndTime = kafkaBrokerCert.getNotAfter(); @@ -343,7 +343,7 @@ void testReplaceCustomClusterCACertificateValidityToInvokeRenewalProcess() { final Date changedCertEndTime = cacert.getNotAfter(); // Check renewed Broker kafka certificate dates - brokerCertCreationSecret = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), testStorage.getClusterName() + "-kafka-brokers"); + brokerCertCreationSecret = kubeClient(testStorage.getNamespaceName()).getSecret(testStorage.getNamespaceName(), brokerPodName); kafkaBrokerCert = SecretUtils.getCertificateFromSecret(brokerCertCreationSecret, brokerPodName + ".crt"); final Date changedKafkaBrokerCertStartTime = kafkaBrokerCert.getNotBefore(); final Date changedKafkaBrokerCertEndTime = kafkaBrokerCert.getNotAfter();