diff options
author | Morten Tokle <mortent@yahooinc.com> | 2023-03-03 12:18:51 +0100 |
---|---|---|
committer | Morten Tokle <mortent@yahooinc.com> | 2023-03-03 12:18:51 +0100 |
commit | ebf52b0c236f8b6075491283a43d14cfc4732341 (patch) | |
tree | 1d7d77f5409a89a5e5a229736847054daa86683c /vespa-athenz/src | |
parent | 89cbc487884329348cfd0ccabd65703edc83a531 (diff) |
Add service identity to identity document
Diffstat (limited to 'vespa-athenz/src')
5 files changed, 52 insertions, 13 deletions
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java index 067e8a6b00f..2d77d2ceda1 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java @@ -4,8 +4,10 @@ package com.yahoo.vespa.athenz.identityprovider.api; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.athenz.identityprovider.api.bindings.SignedIdentityDocumentEntity; +import com.yahoo.vespa.athenz.utils.AthenzIdentities; import java.io.IOException; import java.io.InputStream; @@ -59,6 +61,7 @@ public class EntityBindingsMapper { IdentityType.fromId(entity.identityType()), Optional.ofNullable(entity.clusterType()).map(ClusterType::from).orElse(null), entity.ztsUrl(), + Optional.ofNullable(entity.serviceIdentity()).map(AthenzIdentities::from).orElse(null), entity.unknownAttributes()); } @@ -76,6 +79,7 @@ public class EntityBindingsMapper { model.identityType().id(), Optional.ofNullable(model.clusterType()).map(ClusterType::toConfigValue).orElse(null), model.ztsUrl(), + Optional.ofNullable(model.serviceIdentity()).map(AthenzIdentity::getFullName).orElse(null), model.unknownAttributes()); } diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java index eba89b72d87..ac37bb3368e 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java @@ -1,6 +1,7 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.athenz.identityprovider.api; +import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzService; import java.net.URL; @@ -18,7 +19,8 @@ import java.util.Set; public record SignedIdentityDocument(String signature, int signingKeyVersion, VespaUniqueInstanceId providerUniqueId, AthenzService providerService, int documentVersion, String configServerHostname, String instanceHostname, Instant createdAt, Set<String> ipAddresses, - IdentityType identityType, ClusterType clusterType, String ztsUrl, Map<String, Object> unknownAttributes) { + IdentityType identityType, ClusterType clusterType, String ztsUrl, + AthenzIdentity serviceIdentity, Map<String, Object> unknownAttributes) { public SignedIdentityDocument { ipAddresses = Set.copyOf(ipAddresses); @@ -34,12 +36,12 @@ public record SignedIdentityDocument(String signature, int signingKeyVersion, Ve public SignedIdentityDocument(String signature, int signingKeyVersion, VespaUniqueInstanceId providerUniqueId, AthenzService providerService, int documentVersion, String configServerHostname, String instanceHostname, Instant createdAt, Set<String> ipAddresses, - IdentityType identityType, ClusterType clusterType, String ztsUrl) { + IdentityType identityType, ClusterType clusterType, String ztsUrl, AthenzIdentity serviceIdentity) { this(signature, signingKeyVersion, providerUniqueId, providerService, documentVersion, configServerHostname, - instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, Map.of()); + instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, serviceIdentity, Map.of()); } - public static final int DEFAULT_DOCUMENT_VERSION = 2; + public static final int DEFAULT_DOCUMENT_VERSION = 3; public boolean outdated() { return documentVersion < DEFAULT_DOCUMENT_VERSION; } diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java index edbe032ec26..fc0dff3b97b 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.athenz.identityprovider.api.bindings; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import java.time.Instant; @@ -14,10 +15,11 @@ import java.util.Set; /** * @author bjorncs */ +@JsonInclude(JsonInclude.Include.NON_NULL) public record SignedIdentityDocumentEntity( String signature, int signingKeyVersion, String providerUniqueId, String providerService, int documentVersion, String configServerHostname, String instanceHostname, Instant createdAt, Set<String> ipAddresses, - String identityType, String clusterType, String ztsUrl, Map<String, Object> unknownAttributes) { + String identityType, String clusterType, String ztsUrl, String serviceIdentity, Map<String, Object> unknownAttributes) { @JsonCreator public SignedIdentityDocumentEntity(@JsonProperty("signature") String signature, @@ -31,9 +33,10 @@ public record SignedIdentityDocumentEntity( @JsonProperty("ip-addresses") Set<String> ipAddresses, @JsonProperty("identity-type") String identityType, @JsonProperty("cluster-type") String clusterType, - @JsonProperty("zts-url") String ztsUrl) { + @JsonProperty("zts-url") String ztsUrl, + @JsonProperty("service-identity") String serviceIdentity) { this(signature, signingKeyVersion, providerUniqueId, providerService, documentVersion, configServerHostname, - instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, new HashMap<>()); + instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, serviceIdentity, new HashMap<>()); } @JsonProperty("signature") @Override public String signature() { return signature; } @@ -48,6 +51,7 @@ public record SignedIdentityDocumentEntity( @JsonProperty("identity-type") @Override public String identityType() { return identityType; } @JsonProperty("cluster-type") @Override public String clusterType() { return clusterType; } @JsonProperty("zts-url") @Override public String ztsUrl() { return ztsUrl; } + @JsonProperty("service-identity") @Override public String serviceIdentity() { return serviceIdentity; } @JsonAnyGetter @Override public Map<String, Object> unknownAttributes() { return unknownAttributes; } @JsonAnySetter public void set(String name, Object value) { unknownAttributes.put(name, value); } } diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java index 14d06fe83f2..019f73fc6bf 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.athenz.identityprovider.client; import com.yahoo.security.SignatureUtils; +import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.athenz.identityprovider.api.IdentityType; import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument; @@ -18,6 +19,7 @@ import java.util.Base64; import java.util.Set; import java.util.TreeSet; +import static com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument.DEFAULT_DOCUMENT_VERSION; import static java.nio.charset.StandardCharsets.UTF_8; /** @@ -35,13 +37,15 @@ public class IdentityDocumentSigner { Instant createdAt, Set<String> ipAddresses, IdentityType identityType, - PrivateKey privateKey) { + PrivateKey privateKey, + AthenzIdentity serviceIdentity) { try { Signature signer = SignatureUtils.createSigner(privateKey); signer.initSign(privateKey); writeToSigner( signer, providerUniqueId, providerService, configServerHostname, instanceHostname, createdAt, ipAddresses, identityType); + writeToSigner(signer, serviceIdentity); byte[] signature = signer.sign(); return Base64.getEncoder().encodeToString(signature); } catch (GeneralSecurityException e) { @@ -56,6 +60,9 @@ public class IdentityDocumentSigner { writeToSigner( signer, doc.providerUniqueId(), doc.providerService(), doc.configServerHostname(), doc.instanceHostname(), doc.createdAt(), doc.ipAddresses(), doc.identityType()); + if (doc.documentVersion() >= DEFAULT_DOCUMENT_VERSION) { + writeToSigner(signer, doc.serviceIdentity()); + } return signer.verify(Base64.getDecoder().decode(doc.signature())); } catch (GeneralSecurityException e) { throw new RuntimeException(e); @@ -82,4 +89,8 @@ public class IdentityDocumentSigner { } signer.update(identityType.id().getBytes(UTF_8)); } + + private static void writeToSigner(Signature signer, AthenzIdentity serviceIdentity) throws SignatureException{ + signer.update(serviceIdentity.getFullName().getBytes(UTF_8)); + } } diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java index 72798b03fa8..ff85cb79f02 100644 --- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java +++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java @@ -3,11 +3,13 @@ package com.yahoo.vespa.athenz.identityprovider.client; import com.yahoo.security.KeyAlgorithm; import com.yahoo.security.KeyUtils; +import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.athenz.identityprovider.api.ClusterType; import com.yahoo.vespa.athenz.identityprovider.api.IdentityType; import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument; import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId; +import com.yahoo.vespa.athenz.utils.AthenzIdentities; import org.junit.jupiter.api.Test; import java.security.KeyPair; @@ -37,17 +39,18 @@ public class IdentityDocumentSignerTest { private static final HashSet<String> ipAddresses = new HashSet<>(Arrays.asList("1.2.3.4", "::1")); private static final ClusterType clusterType = ClusterType.CONTAINER; private static final String ztsUrl = "https://foo"; + private static final AthenzIdentity serviceIdentity = new AthenzService("vespa", "node"); @Test void generates_and_validates_signature() { IdentityDocumentSigner signer = new IdentityDocumentSigner(); String signature = signer.generateSignature(id, providerService, configserverHostname, instanceHostname, createdAt, - ipAddresses, identityType, keyPair.getPrivate()); + ipAddresses, identityType, keyPair.getPrivate(), serviceIdentity); SignedIdentityDocument signedIdentityDocument = new SignedIdentityDocument( signature, KEY_VERSION, id, providerService, DEFAULT_DOCUMENT_VERSION, configserverHostname, - instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl); + instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, serviceIdentity); assertTrue(signer.hasValidSignature(signedIdentityDocument, keyPair.getPublic())); } @@ -57,17 +60,32 @@ public class IdentityDocumentSignerTest { IdentityDocumentSigner signer = new IdentityDocumentSigner(); String signature = signer.generateSignature(id, providerService, configserverHostname, instanceHostname, createdAt, - ipAddresses, identityType, keyPair.getPrivate()); + ipAddresses, identityType, keyPair.getPrivate(), serviceIdentity); var docWithoutIgnoredFields = new SignedIdentityDocument( signature, KEY_VERSION, id, providerService, DEFAULT_DOCUMENT_VERSION, configserverHostname, - instanceHostname, createdAt, ipAddresses, identityType, null, null); + instanceHostname, createdAt, ipAddresses, identityType, null, null, serviceIdentity); var docWithIgnoredFields = new SignedIdentityDocument( signature, KEY_VERSION, id, providerService, DEFAULT_DOCUMENT_VERSION, configserverHostname, - instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl); + instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, serviceIdentity); assertTrue(signer.hasValidSignature(docWithoutIgnoredFields, keyPair.getPublic())); assertEquals(docWithIgnoredFields.signature(), docWithoutIgnoredFields.signature()); } + @Test + void validates_signature_for_new_and_old_versions() { + IdentityDocumentSigner signer = new IdentityDocumentSigner(); + String signature = + signer.generateSignature(id, providerService, configserverHostname, instanceHostname, createdAt, + ipAddresses, identityType, keyPair.getPrivate(), serviceIdentity); + + SignedIdentityDocument signedIdentityDocument = new SignedIdentityDocument( + signature, KEY_VERSION, id, providerService, DEFAULT_DOCUMENT_VERSION, configserverHostname, + instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, serviceIdentity); + + assertTrue(signer.hasValidSignature(signedIdentityDocument, keyPair.getPublic())); + + } + }
\ No newline at end of file |