summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMorten Tokle <morten.tokle@gmail.com>2019-02-12 12:16:03 +0100
committerGitHub <noreply@github.com>2019-02-12 12:16:03 +0100
commit6cd73b95dcdcf95a07a726aab88147c2aa19a029 (patch)
tree99f8a7e0586727939388414ebba6ca0e082510d1
parentd0f1c4bedb471ac9d1d28f87719c6009321ddf26 (diff)
parent6d2c6b9c3b36e8bc1efd38cc2c4debffabbd3a3a (diff)
Merge pull request #8463 from vespa-engine/mortent/aws-temp-credential-support
Add support for AWS temp credentials
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/mock/ZtsClientMock.java7
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AwsRole.java44
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AwsTemporaryCredentials.java37
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/common/ClientBase.java7
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java21
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java35
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AwsTemporaryCredentialsResponseEntity.java28
7 files changed, 176 insertions, 3 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/mock/ZtsClientMock.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/mock/ZtsClientMock.java
index 486acea593b..8bb5ad12468 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/mock/ZtsClientMock.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/mock/ZtsClientMock.java
@@ -5,6 +5,8 @@ import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzRole;
import com.yahoo.vespa.athenz.api.AthenzService;
+import com.yahoo.vespa.athenz.api.AwsRole;
+import com.yahoo.vespa.athenz.api.AwsTemporaryCredentials;
import com.yahoo.vespa.athenz.api.ZToken;
import com.yahoo.vespa.athenz.client.zts.Identity;
import com.yahoo.vespa.athenz.client.zts.InstanceIdentity;
@@ -83,6 +85,11 @@ public class ZtsClientMock implements ZtsClient {
}
@Override
+ public AwsTemporaryCredentials getAwsTemporaryCredentials(AthenzDomain athenzDomain, AwsRole awsRole, Duration duration, String externalId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void close() {
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AwsRole.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AwsRole.java
new file mode 100644
index 00000000000..55305df8d26
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AwsRole.java
@@ -0,0 +1,44 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.athenz.api;
+
+import java.net.URLEncoder;
+import java.util.Objects;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * @author mortent
+ */
+public class AwsRole {
+
+ private final String name;
+ private final String encodedName;
+
+ public AwsRole(String awsRoleName) {
+ this.name = awsRoleName;
+ // Encoded twice for zts compatibility
+ this.encodedName = URLEncoder.encode(URLEncoder.encode(this.name, UTF_8), UTF_8);
+ }
+
+ public String encodedName() {
+ return encodedName;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ AwsRole awsRole = (AwsRole) o;
+ return Objects.equals(name, awsRole.name) &&
+ Objects.equals(encodedName, awsRole.encodedName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, encodedName);
+ }
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AwsTemporaryCredentials.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AwsTemporaryCredentials.java
new file mode 100644
index 00000000000..886d97630af
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AwsTemporaryCredentials.java
@@ -0,0 +1,37 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.athenz.api;
+
+import java.time.Instant;
+
+/**
+ * @author mortent
+ */
+public class AwsTemporaryCredentials {
+ private final String accessKeyId;
+ private final String secretAccessKey;
+ private final String sessionToken;
+ private final Instant expiration;
+
+ public AwsTemporaryCredentials(String accessKeyId, String secretAccessKey, String sessionToken, Instant expiration) {
+ this.accessKeyId = accessKeyId;
+ this.secretAccessKey = secretAccessKey;
+ this.sessionToken = sessionToken;
+ this.expiration = expiration;
+ }
+
+ public String accessKeyId() {
+ return accessKeyId;
+ }
+
+ public String secretAccessKey() {
+ return secretAccessKey;
+ }
+
+ public String sessionToken() {
+ return sessionToken;
+ }
+
+ public Instant expiration() {
+ return expiration;
+ }
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/common/ClientBase.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/common/ClientBase.java
index 7ff9db327d3..bda7e41c19b 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/common/ClientBase.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/common/ClientBase.java
@@ -16,7 +16,6 @@ import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
-import org.eclipse.jetty.http.HttpStatus;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
@@ -59,7 +58,7 @@ public abstract class ClientBase implements AutoCloseable {
}
protected <T> T readEntity(HttpResponse response, Class<T> entityType) throws IOException {
- if (HttpStatus.isSuccess(response.getStatusLine().getStatusCode())) {
+ if (isSuccess(response.getStatusLine().getStatusCode())) {
if (entityType.equals(Void.class)) {
return null;
} else {
@@ -71,6 +70,10 @@ public abstract class ClientBase implements AutoCloseable {
}
}
+ private boolean isSuccess(int statusCode) {
+ return statusCode>=200 && statusCode<300;
+ }
+
private static CloseableHttpClient createHttpClient(String userAgent, Supplier<SSLContext> sslContextSupplier) {
return HttpClientBuilder.create()
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, /*requestSentRetryEnabled*/true))
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 9eef2ff9903..05395947fc1 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
@@ -5,9 +5,12 @@ import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzRole;
import com.yahoo.vespa.athenz.api.AthenzService;
+import com.yahoo.vespa.athenz.api.AwsRole;
+import com.yahoo.vespa.athenz.api.AwsTemporaryCredentials;
import com.yahoo.vespa.athenz.api.NToken;
import com.yahoo.vespa.athenz.api.ZToken;
import com.yahoo.vespa.athenz.client.common.ClientBase;
+import com.yahoo.vespa.athenz.client.zts.bindings.AwsTemporaryCredentialsResponseEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.IdentityRefreshRequestEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.IdentityResponseEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.InstanceIdentityCredentials;
@@ -31,6 +34,7 @@ import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.List;
+import java.util.Optional;
import java.util.function.Supplier;
import static java.util.stream.Collectors.toList;
@@ -171,6 +175,23 @@ public class DefaultZtsClient extends ClientBase implements ZtsClient {
});
}
+ @Override
+ public AwsTemporaryCredentials getAwsTemporaryCredentials(AthenzDomain athenzDomain, AwsRole awsRole, Duration duration, String externalId) {
+ URI uri = ztsUrl.resolve(
+ String.format("domain/%s/role/%s/creds", athenzDomain.getName(), awsRole.encodedName()));
+ RequestBuilder requestBuilder = RequestBuilder.get(uri);
+
+ // Add optional durationSeconds and externalId parameters
+ Optional.ofNullable(duration).ifPresent(d -> requestBuilder.addParameter("durationSeconds", Long.toString(duration.getSeconds())));
+ Optional.ofNullable(externalId).ifPresent(s -> requestBuilder.addParameter("externalId", s));
+
+ HttpUriRequest request = requestBuilder.build();
+ return execute(request, response -> {
+ AwsTemporaryCredentialsResponseEntity entity = readEntity(response, AwsTemporaryCredentialsResponseEntity.class);
+ return entity.credentials();
+ });
+ }
+
private InstanceIdentity getInstanceIdentity(HttpResponse response) throws IOException {
InstanceIdentityCredentials entity = readEntity(response, InstanceIdentityCredentials.class);
return entity.getServiceToken() != null
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 0ca2ea2fe69..7b77fccfed6 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
@@ -1,12 +1,14 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.athenz.client.zts;
+import com.yahoo.security.Pkcs10Csr;
import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzRole;
import com.yahoo.vespa.athenz.api.AthenzService;
+import com.yahoo.vespa.athenz.api.AwsRole;
+import com.yahoo.vespa.athenz.api.AwsTemporaryCredentials;
import com.yahoo.vespa.athenz.api.ZToken;
-import com.yahoo.security.Pkcs10Csr;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
@@ -108,5 +110,36 @@ public interface ZtsClient extends AutoCloseable {
*/
List<AthenzDomain> getTenantDomains(AthenzIdentity providerIdentity, AthenzIdentity userIdentity, String roleName);
+ /**
+ * Get aws temporary credentials
+ *
+ * @param awsRole AWS role to get credentials for
+ * @return AWS temporary credentials
+ */
+ default AwsTemporaryCredentials getAwsTemporaryCredentials(AthenzDomain athenzDomain, AwsRole awsRole) {
+ return getAwsTemporaryCredentials(athenzDomain, awsRole, null, null);
+ }
+
+ /**
+ * Get aws temporary credentials
+ *
+ * @param awsRole AWS role to get credentials for
+ * @param externalId External Id to get credentials, or <code>null</code> if not required
+ * @return AWS temporary credentials
+ */
+ default AwsTemporaryCredentials getAwsTemporaryCredentials(AthenzDomain athenzDomain, AwsRole awsRole, String externalId) {
+ return getAwsTemporaryCredentials(athenzDomain, awsRole, null, externalId);
+ }
+
+ /**
+ * Get aws temporary credentials
+ *
+ * @param awsRole AWS role to get credentials for
+ * @param duration Duration for which the credentials should be valid, or <code>null</code> to use default
+ * @param externalId External Id to get credentials, or <code>null</code> if not required
+ * @return AWS temporary credentials
+ */
+ AwsTemporaryCredentials getAwsTemporaryCredentials(AthenzDomain athenzDomain, AwsRole awsRole, Duration duration, String externalId);
+
void close();
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AwsTemporaryCredentialsResponseEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AwsTemporaryCredentialsResponseEntity.java
new file mode 100644
index 00000000000..50b02730277
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AwsTemporaryCredentialsResponseEntity.java
@@ -0,0 +1,28 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.athenz.client.zts.bindings;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.yahoo.vespa.athenz.api.AwsTemporaryCredentials;
+
+import java.time.Instant;
+
+/**
+ * @author mortent
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AwsTemporaryCredentialsResponseEntity {
+ private AwsTemporaryCredentials credentials;
+
+ public AwsTemporaryCredentialsResponseEntity(
+ @JsonProperty("accessKeyId") String accessKeyId,
+ @JsonProperty("secretAccessKey") String secretAccessKey,
+ @JsonProperty("sessionToken") String sessionToken,
+ @JsonProperty("expiration") Instant expiration) {
+ this.credentials = new AwsTemporaryCredentials(accessKeyId, secretAccessKey, sessionToken, expiration);
+ }
+
+ public AwsTemporaryCredentials credentials() {
+ return credentials;
+ }
+}