diff options
Diffstat (limited to 'controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificateManagerTest.java')
-rw-r--r-- | controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificateManagerTest.java | 129 |
1 files changed, 107 insertions, 22 deletions
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificateManagerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificateManagerTest.java index d7bc73adf37..d0e87056821 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificateManagerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificateManagerTest.java @@ -1,6 +1,9 @@ package com.yahoo.vespa.hosted.controller.certificate; +import com.yahoo.config.application.api.DeploymentSpec; +import com.yahoo.config.application.api.xml.DeploymentSpecXmlReader; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.security.KeyAlgorithm; @@ -25,8 +28,10 @@ import java.security.cert.X509Certificate; import java.time.Clock; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -45,20 +50,49 @@ public class EndpointCertificateManagerTest { private final EndpointCertificateManager endpointCertificateManager = new EndpointCertificateManager(zoneRegistryMock, mockCuratorDb, secretStore, endpointCertificateMock, clock, inMemoryFlagSource); + private static List<String> expectedSans = List.of( + "vt2ktgkqme5zlnp4tj4ttyor7fj3v7q5o.vespa.oath.cloud", + "default.default.global.vespa.oath.cloud", + "*.default.default.global.vespa.oath.cloud", + "default.default.aws-us-east-1a.vespa.oath.cloud", + "*.default.default.aws-us-east-1a.vespa.oath.cloud", + "default.default.us-east-1.test.vespa.oath.cloud", + "*.default.default.us-east-1.test.vespa.oath.cloud", + "default.default.us-east-3.staging.vespa.oath.cloud", + "*.default.default.us-east-3.staging.vespa.oath.cloud" + ); + + private static List<String> expectedAdditionalSans = List.of( + "default.default.ap-northeast-1.vespa.oath.cloud", + "*.default.default.ap-northeast-1.vespa.oath.cloud" + ); + + private static List<String> expectedCombinedSans = new ArrayList<>() {{ + addAll(expectedSans); + addAll(expectedAdditionalSans); + }}; + + private static List<String> expectedDevSans = List.of( + "vt2ktgkqme5zlnp4tj4ttyor7fj3v7q5o.vespa.oath.cloud", + "default.default.us-east-1.dev.vespa.oath.cloud", + "*.default.default.us-east-1.dev.vespa.oath.cloud" + ); + private static final KeyPair testKeyPair = KeyUtils.generateKeypair(KeyAlgorithm.EC, 192); - private static final X509Certificate testCertificate = X509CertificateBuilder - .fromKeypair( - testKeyPair, - new X500Principal("CN=test"), - Instant.now(), Instant.now().plus(5, ChronoUnit.MINUTES), - SignatureAlgorithm.SHA256_WITH_ECDSA, - X509CertificateBuilder.generateRandomSerialNumber()) - .addSubjectAlternativeName("vt2ktgkqme5zlnp4tj4ttyor7fj3v7q5o.vespa.oath.cloud") - .addSubjectAlternativeName("default.default.global.vespa.oath.cloud") - .addSubjectAlternativeName("*.default.default.global.vespa.oath.cloud") - .addSubjectAlternativeName("default.default.us-east-1.test.vespa.oath.cloud") - .addSubjectAlternativeName("*.default.default.us-east-1.test.vespa.oath.cloud") - .build(); + private static final X509Certificate testCertificate = makeTestCert(expectedSans); + private static final X509Certificate testCertificate2 = makeTestCert(expectedCombinedSans); + + private static X509Certificate makeTestCert(List<String> sans) { + X509CertificateBuilder x509CertificateBuilder = X509CertificateBuilder + .fromKeypair( + testKeyPair, + new X500Principal("CN=test"), + Instant.now(), Instant.now().plus(5, ChronoUnit.MINUTES), + SignatureAlgorithm.SHA256_WITH_ECDSA, + X509CertificateBuilder.generateRandomSerialNumber()); + for (String san : sans) x509CertificateBuilder = x509CertificateBuilder.addSubjectAlternativeName(san); + return x509CertificateBuilder.build(); + } private final Instance testInstance = new Instance(ApplicationId.defaultId()); private final String testKeyName = "testKeyName"; @@ -68,25 +102,37 @@ public class EndpointCertificateManagerTest { @Before public void setUp() { zoneRegistryMock.exclusiveRoutingIn(zoneRegistryMock.zones().all().zones()); - testZone = zoneRegistryMock.zones().directlyRouted().zones().stream().findFirst().orElseThrow().getId(); + testZone = zoneRegistryMock.zones().directlyRouted().in(Environment.prod).zones().stream().findFirst().orElseThrow().getId(); inMemoryFlagSource.withBooleanFlag(Flags.VALIDATE_ENDPOINT_CERTIFICATES.id(), true); } @Test - public void provisions_new_certificate() { - Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone); + public void provisions_new_certificate_in_dev() { + ZoneId testZone = zoneRegistryMock.zones().directlyRouted().in(Environment.dev).zones().stream().findFirst().orElseThrow().getId(); + Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone, Optional.empty()); + assertTrue(endpointCertificateMetadata.isPresent()); + assertTrue(endpointCertificateMetadata.get().keyName().matches("vespa.tls.default.default.*-key")); + assertTrue(endpointCertificateMetadata.get().certName().matches("vespa.tls.default.default.*-cert")); + assertEquals(0, endpointCertificateMetadata.get().version()); + assertEquals(expectedDevSans, endpointCertificateMetadata.get().requestedDnsSans().orElseThrow()); + } + + @Test + public void provisions_new_certificate_in_prod() { + Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone, Optional.empty()); assertTrue(endpointCertificateMetadata.isPresent()); assertTrue(endpointCertificateMetadata.get().keyName().matches("vespa.tls.default.default.*-key")); assertTrue(endpointCertificateMetadata.get().certName().matches("vespa.tls.default.default.*-cert")); assertEquals(0, endpointCertificateMetadata.get().version()); + assertEquals(expectedSans, endpointCertificateMetadata.get().requestedDnsSans().orElseThrow()); } @Test public void reuses_stored_certificate_metadata() { mockCuratorDb.writeEndpointCertificateMetadata(testInstance.id(), new EndpointCertificateMetadata(testKeyName, testCertName, 7)); secretStore.setSecret(testKeyName, KeyUtils.toPem(testKeyPair.getPrivate()), 7); - secretStore.setSecret(testCertName, X509CertificateUtils.toPem(testCertificate)+X509CertificateUtils.toPem(testCertificate), 7); - Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone); + secretStore.setSecret(testCertName, X509CertificateUtils.toPem(testCertificate) + X509CertificateUtils.toPem(testCertificate), 7); + Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone, Optional.empty()); assertTrue(endpointCertificateMetadata.isPresent()); assertEquals(testKeyName, endpointCertificateMetadata.get().keyName()); assertEquals(testCertName, endpointCertificateMetadata.get().certName()); @@ -101,9 +147,9 @@ public class EndpointCertificateManagerTest { secretStore.setSecret(testCertName, "cert", 7); secretStore.setSecret(testKeyName, KeyUtils.toPem(testKeyPair.getPrivate()), 8); secretStore.setSecret(testKeyName, KeyUtils.toPem(testKeyPair.getPrivate()), 9); - secretStore.setSecret(testCertName, X509CertificateUtils.toPem(testCertificate)+X509CertificateUtils.toPem(testCertificate), 8); + secretStore.setSecret(testCertName, X509CertificateUtils.toPem(testCertificate) + X509CertificateUtils.toPem(testCertificate), 8); mockCuratorDb.writeEndpointCertificateMetadata(testInstance.id(), new EndpointCertificateMetadata(testKeyName, testCertName, 7)); - Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone); + Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone, Optional.empty()); assertTrue(endpointCertificateMetadata.isPresent()); assertEquals(testKeyName, endpointCertificateMetadata.get().keyName()); assertEquals(testCertName, endpointCertificateMetadata.get().certName()); @@ -114,11 +160,50 @@ public class EndpointCertificateManagerTest { public void reprovisions_certificate_when_necessary() { mockCuratorDb.writeEndpointCertificateMetadata(testInstance.id(), new EndpointCertificateMetadata(testKeyName, testCertName, -1, Optional.of("uuid"), Optional.of(List.of()), Optional.empty())); secretStore.setSecret("vespa.tls.default.default.default-key", KeyUtils.toPem(testKeyPair.getPrivate()), 0); - secretStore.setSecret("vespa.tls.default.default.default-cert", X509CertificateUtils.toPem(testCertificate)+X509CertificateUtils.toPem(testCertificate), 0); - Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone); + secretStore.setSecret("vespa.tls.default.default.default-cert", X509CertificateUtils.toPem(testCertificate) + X509CertificateUtils.toPem(testCertificate), 0); + Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone, Optional.empty()); assertTrue(endpointCertificateMetadata.isPresent()); assertEquals(0, endpointCertificateMetadata.get().version()); assertEquals(endpointCertificateMetadata, mockCuratorDb.readEndpointCertificateMetadata(testInstance.id())); } + @Test + public void reprovisions_certificate_with_added_sans_when_deploying_to_new_zone() { + ZoneId testZone = zoneRegistryMock.zones().directlyRouted().in(Environment.prod).zones().stream().skip(1).findFirst().orElseThrow().getId(); + + mockCuratorDb.writeEndpointCertificateMetadata(testInstance.id(), new EndpointCertificateMetadata(testKeyName, testCertName, -1, Optional.of("uuid"), Optional.of(expectedSans), Optional.of("mockCa"))); + secretStore.setSecret("vespa.tls.default.default.default-key", KeyUtils.toPem(testKeyPair.getPrivate()), -1); + secretStore.setSecret("vespa.tls.default.default.default-cert", X509CertificateUtils.toPem(testCertificate) + X509CertificateUtils.toPem(testCertificate), -1); + + secretStore.setSecret("vespa.tls.default.default.default-key", KeyUtils.toPem(testKeyPair.getPrivate()), 0); + secretStore.setSecret("vespa.tls.default.default.default-cert", X509CertificateUtils.toPem(testCertificate2) + X509CertificateUtils.toPem(testCertificate2), 0); + + Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone, Optional.empty()); + assertTrue(endpointCertificateMetadata.isPresent()); + assertEquals(0, endpointCertificateMetadata.get().version()); + assertEquals(endpointCertificateMetadata, mockCuratorDb.readEndpointCertificateMetadata(testInstance.id())); + assertEquals(Set.copyOf(expectedCombinedSans), Set.copyOf(endpointCertificateMetadata.get().requestedDnsSans().orElseThrow())); + } + + @Test + public void includes_zones_in_deployment_spec_when_deploying_to_staging() { + + DeploymentSpec deploymentSpec = new DeploymentSpecXmlReader(true).read( + "<deployment version=\"1.0\">\n" + + " <instance id=\"default\">\n" + + " <prod>\n" + + " <region active=\"true\">aws-us-east-1a</region>\n" + + " <region active=\"true\">ap-northeast-1</region>\n" + + " </prod>\n" + + " </instance>\n" + + "</deployment>\n"); + + ZoneId testZone = zoneRegistryMock.zones().controllerUpgraded().in(Environment.staging).zones().stream().findFirst().orElseThrow().getId(); + Optional<EndpointCertificateMetadata> endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(testInstance, testZone, Optional.of(deploymentSpec.requireInstance("default"))); + assertTrue(endpointCertificateMetadata.isPresent()); + assertTrue(endpointCertificateMetadata.get().keyName().matches("vespa.tls.default.default.*-key")); + assertTrue(endpointCertificateMetadata.get().certName().matches("vespa.tls.default.default.*-cert")); + assertEquals(0, endpointCertificateMetadata.get().version()); + assertEquals(Set.copyOf(expectedCombinedSans), Set.copyOf(endpointCertificateMetadata.get().requestedDnsSans().orElseThrow())); + } } |