use of io.fabric8.kubernetes.api.model.rbac.Subject in project strimzi-kafka-operator by strimzi.
the class SecurityST method testCustomClusterCAClientsCA.
@ParallelNamespaceTest
void testCustomClusterCAClientsCA(ExtensionContext extensionContext) {
final String namespaceName = StUtils.getNamespaceBasedOnRbac(namespace, extensionContext);
final String clusterName = mapWithClusterNames.get(extensionContext.getDisplayName());
final String topicName = mapWithTestTopics.get(extensionContext.getDisplayName());
final String userName = mapWithTestUsers.get(extensionContext.getDisplayName());
generateAndDeployCustomStrimziCA(namespaceName, clusterName);
checkCustomCAsCorrectness(namespaceName, clusterName);
LOGGER.info(" Deploy kafka with new certs/secrets.");
resourceManager.createResource(extensionContext, KafkaTemplates.kafkaEphemeral(clusterName, 3, 3).editSpec().withNewClusterCa().withGenerateCertificateAuthority(false).endClusterCa().withNewClientsCa().withGenerateCertificateAuthority(false).endClientsCa().editKafka().withListeners(new GenericKafkaListenerBuilder().withType(KafkaListenerType.INTERNAL).withName(Constants.PLAIN_LISTENER_DEFAULT_NAME).withPort(9092).withTls(false).build(), new GenericKafkaListenerBuilder().withType(KafkaListenerType.INTERNAL).withName(Constants.TLS_LISTENER_DEFAULT_NAME).withPort(9093).withTls(true).withNewKafkaListenerAuthenticationTlsAuth().endKafkaListenerAuthenticationTlsAuth().build()).endKafka().endSpec().build());
LOGGER.info("Check Kafka(s) and Zookeeper(s) certificates.");
X509Certificate kafkaCert = SecretUtils.getCertificateFromSecret(kubeClient(namespaceName).getSecret(namespaceName, clusterName + "-kafka-brokers"), clusterName + "-kafka-0.crt");
assertThat("KafkaCert does not have expected test Issuer: " + kafkaCert.getIssuerDN(), SystemTestCertManager.containsAllDN(kafkaCert.getIssuerX500Principal().getName(), STRIMZI_TEST_CLUSTER_CA));
X509Certificate zookeeperCert = SecretUtils.getCertificateFromSecret(kubeClient(namespaceName).getSecret(namespaceName, clusterName + "-zookeeper-nodes"), clusterName + "-zookeeper-0.crt");
assertThat("ZookeeperCert does not have expected test Subject: " + zookeeperCert.getIssuerDN(), SystemTestCertManager.containsAllDN(zookeeperCert.getIssuerX500Principal().getName(), STRIMZI_TEST_CLUSTER_CA));
resourceManager.createResource(extensionContext, KafkaTopicTemplates.topic(clusterName, topicName).build());
LOGGER.info("Check KafkaUser certificate.");
KafkaUser user = KafkaUserTemplates.tlsUser(clusterName, userName).build();
resourceManager.createResource(extensionContext, user);
X509Certificate userCert = SecretUtils.getCertificateFromSecret(kubeClient(namespaceName).getSecret(namespaceName, userName), "user.crt");
assertThat("Generated ClientsCA does not have expected test Subject: " + userCert.getIssuerDN(), SystemTestCertManager.containsAllDN(userCert.getIssuerX500Principal().getName(), STRIMZI_TEST_CLIENTS_CA));
LOGGER.info("Send and receive messages over TLS.");
resourceManager.createResource(extensionContext, KafkaClientsTemplates.kafkaClients(true, clusterName + "-" + Constants.KAFKA_CLIENTS, user).build());
final String kafkaClientsPodName = kubeClient(namespaceName).listPodsByPrefixInName(namespaceName, clusterName + "-" + Constants.KAFKA_CLIENTS).get(0).getMetadata().getName();
InternalKafkaClient internalKafkaClient = new InternalKafkaClient.Builder().withUsingPodName(kafkaClientsPodName).withTopicName(topicName).withNamespaceName(namespaceName).withClusterName(clusterName).withKafkaUsername(userName).withMessageCount(MESSAGE_COUNT).withListenerName(Constants.TLS_LISTENER_DEFAULT_NAME).build();
LOGGER.info("Check for certificates used within kafka pod internal clients (producer/consumer)");
List<VolumeMount> volumeMounts = kubeClient(namespaceName).listPodsByPrefixInName(namespaceName, clusterName + "-" + Constants.KAFKA_CLIENTS).get(0).getSpec().getContainers().get(0).getVolumeMounts();
for (VolumeMount vm : volumeMounts) {
if (vm.getMountPath().contains("user-secret-" + internalKafkaClient.getKafkaUsername())) {
assertThat("UserCert Issuer DN in clients pod is incorrect!", checkMountVolumeSecret(namespaceName, kafkaClientsPodName, vm, "issuer", STRIMZI_INTERMEDIATE_CA));
assertThat("UserCert Subject DN in clients pod is incorrect!", checkMountVolumeSecret(namespaceName, kafkaClientsPodName, vm, "subject", STRIMZI_TEST_CLIENTS_CA));
} else if (vm.getMountPath().contains("cluster-ca-" + internalKafkaClient.getKafkaUsername())) {
assertThat("ClusterCA Issuer DN in clients pod is incorrect!", checkMountVolumeSecret(namespaceName, kafkaClientsPodName, vm, "issuer", STRIMZI_INTERMEDIATE_CA));
assertThat("ClusterCA Subject DN in clients pod is incorrect!", checkMountVolumeSecret(namespaceName, kafkaClientsPodName, vm, "subject", STRIMZI_TEST_CLUSTER_CA));
}
}
LOGGER.info("Checking produced and consumed messages via TLS to pod:{}", kafkaClientsPodName);
internalKafkaClient.checkProducedAndConsumedMessages(internalKafkaClient.sendMessagesTls(), internalKafkaClient.receiveMessagesTls());
}
use of io.fabric8.kubernetes.api.model.rbac.Subject in project strimzi-kafka-operator by strimzi.
the class CaRenewalTest method renewalOfStatefulSetCertificatesWithCaRenewal.
@ParallelTest
public void renewalOfStatefulSetCertificatesWithCaRenewal() throws IOException {
MockedCa mockedCa = new MockedCa(Reconciliation.DUMMY_RECONCILIATION, null, null, null, null, null, null, null, 2, 1, true, null);
mockedCa.setCertRenewed(true);
Secret initialSecret = new SecretBuilder().withNewMetadata().withName("test-secret").endMetadata().addToData("pod0.crt", Base64.getEncoder().encodeToString("old-cert".getBytes())).addToData("pod0.key", Base64.getEncoder().encodeToString("old-key".getBytes())).addToData("pod0.p12", Base64.getEncoder().encodeToString("old-keystore".getBytes())).addToData("pod0.password", Base64.getEncoder().encodeToString("old-password".getBytes())).addToData("pod1.crt", Base64.getEncoder().encodeToString("old-cert".getBytes())).addToData("pod1.key", Base64.getEncoder().encodeToString("old-key".getBytes())).addToData("pod1.p12", Base64.getEncoder().encodeToString("old-keystore".getBytes())).addToData("pod1.password", Base64.getEncoder().encodeToString("old-password".getBytes())).addToData("pod2.crt", Base64.getEncoder().encodeToString("old-cert".getBytes())).addToData("pod2.key", Base64.getEncoder().encodeToString("old-key".getBytes())).addToData("pod2.p12", Base64.getEncoder().encodeToString("old-keystore".getBytes())).addToData("pod2.password", Base64.getEncoder().encodeToString("old-password".getBytes())).build();
int replicas = 3;
Function<Integer, Subject> subjectFn = i -> new Subject.Builder().build();
Function<Integer, String> podNameFn = i -> "pod" + i;
boolean isMaintenanceTimeWindowsSatisfied = true;
Map<String, CertAndKey> newCerts = mockedCa.maybeCopyOrGenerateCerts(Reconciliation.DUMMY_RECONCILIATION, replicas, subjectFn, initialSecret, podNameFn, isMaintenanceTimeWindowsSatisfied);
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"));
}
use of io.fabric8.kubernetes.api.model.rbac.Subject in project strimzi by strimzi.
the class CaRenewalTest method renewalOfStatefulSetCertificatesWithCaRenewal.
@ParallelTest
public void renewalOfStatefulSetCertificatesWithCaRenewal() throws IOException {
MockedCa mockedCa = new MockedCa(Reconciliation.DUMMY_RECONCILIATION, null, null, null, null, null, null, null, 2, 1, true, null);
mockedCa.setCertRenewed(true);
Secret initialSecret = new SecretBuilder().withNewMetadata().withName("test-secret").endMetadata().addToData("pod0.crt", Base64.getEncoder().encodeToString("old-cert".getBytes())).addToData("pod0.key", Base64.getEncoder().encodeToString("old-key".getBytes())).addToData("pod0.p12", Base64.getEncoder().encodeToString("old-keystore".getBytes())).addToData("pod0.password", Base64.getEncoder().encodeToString("old-password".getBytes())).addToData("pod1.crt", Base64.getEncoder().encodeToString("old-cert".getBytes())).addToData("pod1.key", Base64.getEncoder().encodeToString("old-key".getBytes())).addToData("pod1.p12", Base64.getEncoder().encodeToString("old-keystore".getBytes())).addToData("pod1.password", Base64.getEncoder().encodeToString("old-password".getBytes())).addToData("pod2.crt", Base64.getEncoder().encodeToString("old-cert".getBytes())).addToData("pod2.key", Base64.getEncoder().encodeToString("old-key".getBytes())).addToData("pod2.p12", Base64.getEncoder().encodeToString("old-keystore".getBytes())).addToData("pod2.password", Base64.getEncoder().encodeToString("old-password".getBytes())).build();
int replicas = 3;
Function<Integer, Subject> subjectFn = i -> new Subject.Builder().build();
Function<Integer, String> podNameFn = i -> "pod" + i;
boolean isMaintenanceTimeWindowsSatisfied = true;
Map<String, CertAndKey> newCerts = mockedCa.maybeCopyOrGenerateCerts(Reconciliation.DUMMY_RECONCILIATION, replicas, subjectFn, initialSecret, podNameFn, isMaintenanceTimeWindowsSatisfied);
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"));
}
use of io.fabric8.kubernetes.api.model.rbac.Subject in project strimzi by strimzi.
the class CaRenewalTest method renewalOfStatefulSetCertificatesDelayedRenewalInWindow.
@ParallelTest
public void renewalOfStatefulSetCertificatesDelayedRenewalInWindow() throws IOException {
MockedCa mockedCa = new MockedCa(Reconciliation.DUMMY_RECONCILIATION, null, null, null, null, null, null, null, 2, 1, true, null);
mockedCa.setCertExpiring(true);
Secret initialSecret = new SecretBuilder().withNewMetadata().withName("test-secret").endMetadata().addToData("pod0.crt", Base64.getEncoder().encodeToString("old-cert".getBytes())).addToData("pod0.key", Base64.getEncoder().encodeToString("old-key".getBytes())).addToData("pod0.p12", Base64.getEncoder().encodeToString("old-keystore".getBytes())).addToData("pod0.password", Base64.getEncoder().encodeToString("old-password".getBytes())).addToData("pod1.crt", Base64.getEncoder().encodeToString("old-cert".getBytes())).addToData("pod1.key", Base64.getEncoder().encodeToString("old-key".getBytes())).addToData("pod1.p12", Base64.getEncoder().encodeToString("old-keystore".getBytes())).addToData("pod1.password", Base64.getEncoder().encodeToString("old-password".getBytes())).addToData("pod2.crt", Base64.getEncoder().encodeToString("old-cert".getBytes())).addToData("pod2.key", Base64.getEncoder().encodeToString("old-key".getBytes())).addToData("pod2.p12", Base64.getEncoder().encodeToString("old-keystore".getBytes())).addToData("pod2.password", Base64.getEncoder().encodeToString("old-password".getBytes())).build();
int replicas = 3;
Function<Integer, Subject> subjectFn = i -> new Subject.Builder().build();
Function<Integer, String> podNameFn = i -> "pod" + i;
boolean isMaintenanceTimeWindowsSatisfied = true;
Map<String, CertAndKey> newCerts = mockedCa.maybeCopyOrGenerateCerts(Reconciliation.DUMMY_RECONCILIATION, replicas, subjectFn, initialSecret, podNameFn, isMaintenanceTimeWindowsSatisfied);
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"));
}
use of io.fabric8.kubernetes.api.model.rbac.Subject in project strimzi by strimzi.
the class Ca method maybeCopyOrGenerateCerts.
/**
* Copy already existing certificates from provided Secret based on number of effective replicas
* and maybe generate new ones for new replicas (i.e. scale-up).
*/
protected Map<String, CertAndKey> maybeCopyOrGenerateCerts(Reconciliation reconciliation, int replicas, Function<Integer, Subject> subjectFn, Secret secret, Function<Integer, String> podNameFn, boolean isMaintenanceTimeWindowsSatisfied) throws IOException {
int replicasInSecret;
if (secret == null || secret.getData() == null || this.certRenewed()) {
replicasInSecret = 0;
} else {
replicasInSecret = (int) secret.getData().keySet().stream().filter(k -> k.contains(".crt")).count();
}
File brokerCsrFile = File.createTempFile("tls", "broker-csr");
File brokerKeyFile = File.createTempFile("tls", "broker-key");
File brokerCertFile = File.createTempFile("tls", "broker-cert");
File brokerKeyStoreFile = File.createTempFile("tls", "broker-p12");
int replicasInNewSecret = Math.min(replicasInSecret, replicas);
Map<String, CertAndKey> certs = new HashMap<>(replicasInNewSecret);
// scale down -> it will copy just the requested number of replicas
for (int i = 0; i < replicasInNewSecret; i++) {
String podName = podNameFn.apply(i);
LOGGER.debugCr(reconciliation, "Certificate for {} already exists", podName);
Subject subject = subjectFn.apply(i);
CertAndKey certAndKey;
if (secret.getData().get(podName + ".p12") != null && !secret.getData().get(podName + ".p12").isEmpty() && secret.getData().get(podName + ".password") != null && !secret.getData().get(podName + ".password").isEmpty()) {
certAndKey = asCertAndKey(secret, podName + ".key", podName + ".crt", podName + ".p12", podName + ".password");
} else {
// coming from an older operator version, the secret exists but without keystore and password
certAndKey = addKeyAndCertToKeyStore(subject.commonName(), Base64.getDecoder().decode(secret.getData().get(podName + ".key")), Base64.getDecoder().decode(secret.getData().get(podName + ".crt")));
}
List<String> reasons = new ArrayList<>(2);
if (certSubjectChanged(certAndKey, subject, podName)) {
reasons.add("DNS names changed");
}
if (isExpiring(secret, podName + ".crt") && isMaintenanceTimeWindowsSatisfied) {
reasons.add("certificate is expiring");
}
if (renewalType.equals(RenewalType.CREATE)) {
reasons.add("certificate added");
}
if (!reasons.isEmpty()) {
LOGGER.debugCr(reconciliation, "Certificate for pod {} need to be regenerated because: {}", podName, String.join(", ", reasons));
CertAndKey newCertAndKey = generateSignedCert(subject, brokerCsrFile, brokerKeyFile, brokerCertFile, brokerKeyStoreFile);
certs.put(podName, newCertAndKey);
} else {
certs.put(podName, certAndKey);
}
}
// scale down -> does nothing
for (int i = replicasInSecret; i < replicas; i++) {
String podName = podNameFn.apply(i);
LOGGER.debugCr(reconciliation, "Certificate for pod {} to generate", podName);
CertAndKey k = generateSignedCert(subjectFn.apply(i), brokerCsrFile, brokerKeyFile, brokerCertFile, brokerKeyStoreFile);
certs.put(podName, k);
}
delete(reconciliation, brokerCsrFile);
delete(reconciliation, brokerKeyFile);
delete(reconciliation, brokerCertFile);
delete(reconciliation, brokerKeyStoreFile);
return certs;
}
Aggregations