diff options
7 files changed, 57 insertions, 13 deletions
diff --git a/container-disc/abi-spec.json b/container-disc/abi-spec.json index aae37552283..968cef8e88f 100644 --- a/container-disc/abi-spec.json +++ b/container-disc/abi-spec.json @@ -17,6 +17,7 @@ "public abstract java.lang.String getAccessToken(java.lang.String)", "public abstract java.lang.String getAccessToken(java.lang.String, java.util.List)", "public abstract java.util.List getIdentityCertificate()", + "public abstract java.security.cert.X509Certificate getRoleCertificate(java.lang.String, java.lang.String)", "public abstract java.security.PrivateKey getPrivateKey()", "public abstract java.nio.file.Path trustStorePath()" ], diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/AthenzIdentityProviderProvider.java b/container-disc/src/main/java/com/yahoo/container/jdisc/AthenzIdentityProviderProvider.java index 33d357e8b6b..f04e2291ee8 100644 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/AthenzIdentityProviderProvider.java +++ b/container-disc/src/main/java/com/yahoo/container/jdisc/AthenzIdentityProviderProvider.java @@ -76,6 +76,11 @@ public class AthenzIdentityProviderProvider implements Provider<AthenzIdentityPr } @Override + public X509Certificate getRoleCertificate(String domain, String role) { + throw new UnsupportedOperationException(message); + } + + @Override public PrivateKey getPrivateKey() { throw new UnsupportedOperationException(message); } diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java index c1c60612b37..af5133eceac 100644 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java +++ b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java @@ -21,6 +21,7 @@ public interface AthenzIdentityProvider { String getAccessToken(String domain); String getAccessToken(String domain, List<String> roles); List<X509Certificate> getIdentityCertificate(); + X509Certificate getRoleCertificate(String domain, String role); PrivateKey getPrivateKey(); Path trustStorePath(); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZtsClientMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZtsClientMock.java index 0efa225a437..7322c8e15f8 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZtsClientMock.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZtsClientMock.java @@ -65,12 +65,12 @@ public class ZtsClientMock implements ZtsClient { } @Override - public ZToken getRoleToken(AthenzDomain domain) { + public ZToken getRoleToken(AthenzDomain domain, Duration expiry) { throw new UnsupportedOperationException(); } @Override - public ZToken getRoleToken(AthenzRole athenzRole) { + public ZToken getRoleToken(AthenzRole athenzRole, Duration expiry) { throw new UnsupportedOperationException(); } diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java index 13a61d65d78..197af753442 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java @@ -116,22 +116,23 @@ public class DefaultZtsClient extends ClientBase implements ZtsClient { } @Override - public ZToken getRoleToken(AthenzDomain domain) { - return getRoleToken(domain, null); + public ZToken getRoleToken(AthenzDomain domain, Duration expiry) { + return getRoleToken(domain, null, expiry); } @Override - public ZToken getRoleToken(AthenzRole athenzRole) { - return getRoleToken(athenzRole.domain(), athenzRole.roleName()); + public ZToken getRoleToken(AthenzRole athenzRole, Duration expiry) { + return getRoleToken(athenzRole.domain(), athenzRole.roleName(), expiry); } - private ZToken getRoleToken(AthenzDomain domain, String roleName) { + private ZToken getRoleToken(AthenzDomain domain, String roleName, Duration expiry) { URI uri = ztsUrl.resolve(String.format("domain/%s/token", domain.getName())); RequestBuilder requestBuilder = RequestBuilder.get(uri) .addHeader("Content-Type", "application/json"); if (roleName != null) { requestBuilder.addParameter("role", roleName); } + requestBuilder.addParameter("maxExpiryTime", Long.toString(expiry.getSeconds())); HttpUriRequest request = requestBuilder.build(); return execute(request, response -> { RoleTokenResponseEntity roleTokenResponseEntity = readEntity(response, RoleTokenResponseEntity.class); diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java index e52abc4193b..30c8ab2fd50 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java @@ -68,15 +68,37 @@ public interface ZtsClient extends AutoCloseable { * @param domain Target domain * @return A role token */ - ZToken getRoleToken(AthenzDomain domain); + default ZToken getRoleToken(AthenzDomain domain) { + return getRoleToken(domain, Duration.ofHours(1)); + } + + /** + * Fetch a role token for the target domain + * + * @param domain Target domain + * @param tokenExpiry Token expiry + * @return A role token + */ + ZToken getRoleToken(AthenzDomain domain, Duration tokenExpiry); + + /** + * Fetch a role token for the target role + * + * @param athenzRole Target role + * @return A role token + */ + default ZToken getRoleToken(AthenzRole athenzRole) { + return getRoleToken(athenzRole, Duration.ofHours(1)); + } /** * Fetch a role token for the target role * * @param athenzRole Target role + * @param tokenExpiry Token expiry * @return A role token */ - ZToken getRoleToken(AthenzRole athenzRole); + ZToken getRoleToken(AthenzRole athenzRole, Duration tokenExpiry); /** * Fetch an access token for the target domain diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java index 418f7ec024b..ac211779fad 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java @@ -68,7 +68,8 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen static final Duration UPDATE_PERIOD = Duration.ofDays(1); static final Duration AWAIT_TERMINTATION_TIMEOUT = Duration.ofSeconds(90); private final static Duration ROLE_SSL_CONTEXT_EXPIRY = Duration.ofHours(2); - private final static Duration ROLE_TOKEN_EXPIRY = Duration.ofMinutes(30); + // TODO CMS expects 10min or less token ttl. Use 10min default until we have configurable expiry + private final static Duration ROLE_TOKEN_EXPIRY = Duration.ofMinutes(10); // TODO Make path to trust store paths config private static final Path CLIENT_TRUST_STORE = Paths.get("/opt/yahoo/share/ssl/certs/yahoo_certificate_bundle.pem"); @@ -213,7 +214,7 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen try { AthenzRole athenzRole = new AthenzRole(new AthenzDomain(domain), role); // Make sure to request a certificate which triggers creating a new key manager for this role - X509Certificate x509Certificate = roleSslCertCache.get(athenzRole); + X509Certificate x509Certificate = getRoleCertificate(athenzRole); MutableX509KeyManager keyManager = roleKeyManagerCache.get(athenzRole); return new SslContextBuilder() .withKeyManager(keyManager) @@ -278,6 +279,19 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen return Collections.singletonList(credentials.getCertificate()); } + @Override + public X509Certificate getRoleCertificate(String domain, String role) { + return getRoleCertificate(new AthenzRole(new AthenzDomain(domain), role)); + } + + private X509Certificate getRoleCertificate(AthenzRole athenzRole) { + try { + return roleSslCertCache.get(athenzRole); + } catch (Exception e) { + throw new AthenzIdentityProviderException("Could not retrieve role certificate: " + e.getMessage(), e); + } + } + private void updateIdentityCredentials(AthenzCredentials credentials) { this.credentials = credentials; this.identityKeyManager.updateKeystore( @@ -308,13 +322,13 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen private ZToken createRoleToken(AthenzRole athenzRole) { try (ZtsClient client = createZtsClient()) { - return client.getRoleToken(athenzRole); + return client.getRoleToken(athenzRole, ROLE_TOKEN_EXPIRY); } } private ZToken createRoleToken(AthenzDomain domain) { try (ZtsClient client = createZtsClient()) { - return client.getRoleToken(domain); + return client.getRoleToken(domain, ROLE_TOKEN_EXPIRY); } } |