aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorEirik Nygaard <eirik.nygaard@yahooinc.com>2022-05-25 14:19:29 +0200
committerGitHub <noreply@github.com>2022-05-25 14:19:29 +0200
commit9bd5c77ab39308e3fe99ab540c1113d974d4b3a0 (patch)
treeb654f5f3dc6bfd250d2a882e10b33e845f97c834 /controller-server
parentbf23637096106ff0a16019f25d3b3b19040ff512 (diff)
parent340bdc4f860e934f1a3eb11084661c13900bdb28 (diff)
Merge pull request #22746 from vespa-engine/ean/user-permission-to-archive-bucket
Ean/user permission to archive bucket
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java28
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainer.java38
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java31
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainerTest.java13
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java54
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java5
8 files changed, 122 insertions, 57 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java
index 7a0e60aacb4..4f58e87035b 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java
@@ -8,11 +8,11 @@ import com.yahoo.config.provision.TenantName;
import com.yahoo.security.KeyUtils;
import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.athenz.api.AthenzDomain;
-import com.yahoo.vespa.curator.Lock;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore;
+import com.yahoo.vespa.hosted.controller.tenant.ArchiveAccess;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
import com.yahoo.vespa.hosted.controller.tenant.DeletedTenant;
@@ -128,26 +128,26 @@ public abstract class LockedTenant {
private final BiMap<PublicKey, Principal> developerKeys;
private final TenantInfo info;
private final List<TenantSecretStore> tenantSecretStores;
- private final Optional<String> archiveAccessRole;
+ private final ArchiveAccess archiveAccess;
private Cloud(TenantName name, Instant createdAt, LastLoginInfo lastLoginInfo, Optional<Principal> creator,
BiMap<PublicKey, Principal> developerKeys, TenantInfo info,
- List<TenantSecretStore> tenantSecretStores, Optional<String> archiveAccessRole) {
+ List<TenantSecretStore> tenantSecretStores, ArchiveAccess archiveAccess) {
super(name, createdAt, lastLoginInfo);
this.developerKeys = ImmutableBiMap.copyOf(developerKeys);
this.creator = creator;
this.info = info;
this.tenantSecretStores = tenantSecretStores;
- this.archiveAccessRole = archiveAccessRole;
+ this.archiveAccess = archiveAccess;
}
private Cloud(CloudTenant tenant) {
- this(tenant.name(), tenant.createdAt(), tenant.lastLoginInfo(), tenant.creator(), tenant.developerKeys(), tenant.info(), tenant.tenantSecretStores(), tenant.archiveAccessRole());
+ this(tenant.name(), tenant.createdAt(), tenant.lastLoginInfo(), tenant.creator(), tenant.developerKeys(), tenant.info(), tenant.tenantSecretStores(), tenant.archiveAccess());
}
@Override
public CloudTenant get() {
- return new CloudTenant(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccessRole);
+ return new CloudTenant(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess);
}
public Cloud withDeveloperKey(PublicKey key, Principal principal) {
@@ -155,38 +155,38 @@ public abstract class LockedTenant {
if (keys.containsKey(key))
throw new IllegalArgumentException("Key " + KeyUtils.toPem(key) + " is already owned by " + keys.get(key));
keys.put(key, principal);
- return new Cloud(name, createdAt, lastLoginInfo, creator, keys, info, tenantSecretStores, archiveAccessRole);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, keys, info, tenantSecretStores, archiveAccess);
}
public Cloud withoutDeveloperKey(PublicKey key) {
BiMap<PublicKey, Principal> keys = HashBiMap.create(developerKeys);
keys.remove(key);
- return new Cloud(name, createdAt, lastLoginInfo, creator, keys, info, tenantSecretStores, archiveAccessRole);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, keys, info, tenantSecretStores, archiveAccess);
}
public Cloud withInfo(TenantInfo newInfo) {
- return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, newInfo, tenantSecretStores, archiveAccessRole);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, newInfo, tenantSecretStores, archiveAccess);
}
@Override
public LockedTenant with(LastLoginInfo lastLoginInfo) {
- return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccessRole);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess);
}
public Cloud withSecretStore(TenantSecretStore tenantSecretStore) {
ArrayList<TenantSecretStore> secretStores = new ArrayList<>(tenantSecretStores);
secretStores.add(tenantSecretStore);
- return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, secretStores, archiveAccessRole);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, secretStores, archiveAccess);
}
public Cloud withoutSecretStore(TenantSecretStore tenantSecretStore) {
ArrayList<TenantSecretStore> secretStores = new ArrayList<>(tenantSecretStores);
secretStores.remove(tenantSecretStore);
- return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, secretStores, archiveAccessRole);
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, secretStores, archiveAccess);
}
- public Cloud withArchiveAccessRole(Optional<String> role) {
- return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, role);
+ public Cloud withArchiveAccess(ArchiveAccess archiveAccess) {
+ return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess);
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainer.java
index 9691b45de7d..788360996ff 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainer.java
@@ -10,6 +10,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.archive.ArchiveBucket;
import com.yahoo.vespa.hosted.controller.api.integration.archive.ArchiveService;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry;
import com.yahoo.vespa.hosted.controller.archive.CuratorArchiveBucketDb;
+import com.yahoo.vespa.hosted.controller.tenant.ArchiveAccess;
import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
@@ -53,41 +54,26 @@ public class ArchiveAccessMaintainer extends ControllerMaintainer {
"cloud", z.getCloudName().value()))));
zoneRegistry.zonesIncludingSystem().controllerUpgraded().zones().forEach(z -> {
- ZoneId zoneId = z.getVirtualId();
- try {
- var tenantArchiveAccessRoles = cloudTenantArchiveExternalAccessRoles();
- archiveBucketDb.buckets(zoneId).forEach(archiveBucket ->
- archiveService.updateBucketPolicy(zoneId, archiveBucket,
- Maps.filterEntries(tenantArchiveAccessRoles,
- entry -> archiveBucket.tenants().contains(entry.getKey())))
- );
- Map<String, List<ArchiveBucket>> bucketsPerKey = archiveBucketDb.buckets(zoneId).stream()
- .collect(groupingBy(ArchiveBucket::keyArn));
- bucketsPerKey.forEach((keyArn, buckets) -> {
- Set<String> authorizedIamRolesForKey = buckets.stream()
- .flatMap(b -> b.tenants().stream())
- .filter(tenantArchiveAccessRoles::containsKey)
- .map(tenantArchiveAccessRoles::get)
- .collect(Collectors.toSet());
- archiveService.updateKeyPolicy(zoneId, keyArn, authorizedIamRolesForKey);
- });
- } catch (Exception e) {
- throw new RuntimeException("Failed to maintain archive access in " + zoneId.value(), e);
- }
- }
- );
+ ZoneId zoneId = z.getVirtualId();
+ try {
+ var tenantArchiveAccessRoles = cloudTenantArchiveExternalAccessRoles();
+ var buckets = archiveBucketDb.buckets(zoneId);
+ archiveService.updatePolicies(zoneId, buckets, tenantArchiveAccessRoles);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to maintain archive access in " + zoneId.value(), e);
+ }
+ });
return 1.0;
}
- private Map<TenantName, String> cloudTenantArchiveExternalAccessRoles() {
+ private Map<TenantName, ArchiveAccess> cloudTenantArchiveExternalAccessRoles() {
List<Tenant> tenants = controller().tenants().asList();
return tenants.stream()
.filter(t -> t instanceof CloudTenant)
.map(t -> (CloudTenant) t)
- .filter(t -> t.archiveAccessRole().isPresent())
.collect(Collectors.toUnmodifiableMap(
- Tenant::name, cloudTenant -> cloudTenant.archiveAccessRole().orElseThrow()));
+ Tenant::name, cloudTenant -> cloudTenant.archiveAccess()));
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
index 00e38abcba7..f00e179cfcf 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
@@ -17,6 +17,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.organization.BillingInf
import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore;
import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal;
+import com.yahoo.vespa.hosted.controller.tenant.ArchiveAccess;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
import com.yahoo.vespa.hosted.controller.tenant.DeletedTenant;
@@ -77,6 +78,10 @@ public class TenantSerializer {
private static final String lastLoginInfoField = "lastLoginInfo";
private static final String secretStoresField = "secretStores";
private static final String archiveAccessRoleField = "archiveAccessRole";
+ private static final String archiveAccessField = "archiveAccess";
+ private static final String awsArchiveAccessRoleField = "awsArchiveAccessRole";
+ private static final String gcpArchiveAccessMemberField = "gcpArchiveAccessMember";
+
private static final String awsIdField = "awsId";
private static final String roleField = "role";
@@ -117,7 +122,13 @@ public class TenantSerializer {
toSlime(legacyBillingInfo, root.setObject(billingInfoField));
toSlime(tenant.info(), root);
toSlime(tenant.tenantSecretStores(), root);
- tenant.archiveAccessRole().ifPresent(role -> root.setString(archiveAccessRoleField, role));
+ toSlime(tenant.archiveAccess(), root);
+ }
+
+ private void toSlime(ArchiveAccess archiveAccess, Cursor root) {
+ Cursor object = root.setObject(archiveAccessField);
+ archiveAccess.awsRole().ifPresent(role -> object.setString(awsArchiveAccessRoleField, role));
+ archiveAccess.gcpMember().ifPresent(member -> object.setString(gcpArchiveAccessMemberField, member));
}
private void toSlime(DeletedTenant tenant, Cursor root) {
@@ -175,8 +186,8 @@ public class TenantSerializer {
BiMap<PublicKey, Principal> developerKeys = developerKeysFromSlime(tenantObject.field(pemDeveloperKeysField));
TenantInfo info = tenantInfoFromSlime(tenantObject.field(tenantInfoField));
List<TenantSecretStore> tenantSecretStores = secretStoresFromSlime(tenantObject.field(secretStoresField));
- Optional<String> archiveAccessRole = SlimeUtils.optionalString(tenantObject.field(archiveAccessRoleField));
- return new CloudTenant(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccessRole);
+ ArchiveAccess archiveAccess = archiveAccessFromSlime(tenantObject);
+ return new CloudTenant(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccess);
}
private DeletedTenant deletedTenantFrom(Inspector tenantObject) {
@@ -195,6 +206,20 @@ public class TenantSerializer {
return keys.build();
}
+ ArchiveAccess archiveAccessFromSlime(Inspector tenantObject) {
+ // TODO(enygaard, 2022-05-24): Remove when all tenants have been rewritten to use ArchiveAccess object
+ Optional<String> archiveAccessRole = SlimeUtils.optionalString(tenantObject.field(archiveAccessRoleField));
+ if (archiveAccessRole.isPresent()) {
+ return new ArchiveAccess(archiveAccessRole, Optional.empty());
+ }
+ Inspector object = tenantObject.field(archiveAccessField);
+ if (!object.valid()) {
+ return new ArchiveAccess();
+ }
+ Optional<String> awsArchiveAccessRole = SlimeUtils.optionalString(object.field(awsArchiveAccessRoleField));
+ Optional<String> gcpArchiveAccessMember = SlimeUtils.optionalString(object.field(gcpArchiveAccessMemberField));
+ return new ArchiveAccess(awsArchiveAccessRole, gcpArchiveAccessMember);
+ }
TenantInfo tenantInfoFromSlime(Inspector infoObject) {
if (!infoObject.valid()) return TenantInfo.empty();
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
index 59ba5cc8443..18391815499 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
@@ -109,6 +109,7 @@ import com.yahoo.vespa.hosted.controller.routing.rotation.RotationStatus;
import com.yahoo.vespa.hosted.controller.security.AccessControlRequests;
import com.yahoo.vespa.hosted.controller.security.Credentials;
import com.yahoo.vespa.hosted.controller.support.access.SupportAccess;
+import com.yahoo.vespa.hosted.controller.tenant.ArchiveAccess;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
import com.yahoo.vespa.hosted.controller.tenant.DeletedTenant;
@@ -1039,7 +1040,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
}
controller.tenants().lockOrThrow(TenantName.from(tenantName), LockedTenant.Cloud.class, lockedTenant -> {
- lockedTenant = lockedTenant.withArchiveAccessRole(Optional.of(role));
+ lockedTenant = lockedTenant.withArchiveAccess(new ArchiveAccess(Optional.of(role), Optional.empty()));
controller.tenants().store(lockedTenant);
});
@@ -1051,7 +1052,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
throw new IllegalArgumentException("Tenant '" + tenantName + "' is not a cloud tenant");
controller.tenants().lockOrThrow(TenantName.from(tenantName), LockedTenant.Cloud.class, lockedTenant -> {
- lockedTenant = lockedTenant.withArchiveAccessRole(Optional.empty());
+ lockedTenant = lockedTenant.withArchiveAccess(new ArchiveAccess());
controller.tenants().store(lockedTenant);
});
@@ -2353,7 +2354,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
log.warning(String.format("Failed to get quota for tenant %s: %s", tenant.name(), Exceptions.toMessageString(e)));
}
- cloudTenant.archiveAccessRole().ifPresent(role -> object.setString("archiveAccessRole", role));
+ cloudTenant.archiveAccess().awsRole().ifPresent(role -> object.setString("archiveAccessRole", role));
break;
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainerTest.java
index b97743f4d44..b2451161f34 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainerTest.java
@@ -9,6 +9,7 @@ import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.vespa.hosted.controller.LockedTenant;
import com.yahoo.vespa.hosted.controller.api.integration.archive.ArchiveBucket;
import com.yahoo.vespa.hosted.controller.api.integration.archive.MockArchiveService;
+import com.yahoo.vespa.hosted.controller.tenant.ArchiveAccess;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import org.junit.Test;
@@ -33,19 +34,19 @@ public class ArchiveAccessMaintainerTest {
String tenant1role = "arn:aws:iam::123456789012:role/my-role";
String tenant2role = "arn:aws:iam::210987654321:role/my-role";
var tenant1 = createTenantWithAccessRole(tester, "tenant1", tenant1role);
- createTenantWithAccessRole(tester, "tenant2", tenant2role);
+ var tenant2 = createTenantWithAccessRole(tester, "tenant2", tenant2role);
ZoneId testZone = ZoneId.from("prod.aws-us-east-1c");
tester.controller().archiveBucketDb().archiveUriFor(testZone, tenant1, true);
var testBucket = new ArchiveBucket("bucketName", "keyArn").withTenant(tenant1);
MockArchiveService archiveService = (MockArchiveService) tester.controller().serviceRegistry().archiveService();
- assertNull(archiveService.authorizedIamRolesForBucket.get(testBucket));
- assertNull(archiveService.authorizedIamRolesForKey.get(testBucket.keyArn()));
+
+ assertEquals(0, archiveService.authorizeAccessByTenantName.size());
MockMetric metric = new MockMetric();
new ArchiveAccessMaintainer(tester.controller(), metric, Duration.ofMinutes(10)).maintain();
- assertEquals(Map.of(tenant1, tenant1role), archiveService.authorizedIamRolesForBucket.get(testBucket));
- assertEquals(Set.of(tenant1role), archiveService.authorizedIamRolesForKey.get(testBucket.keyArn()));
+ assertEquals(new ArchiveAccess(Optional.of(tenant1role), Optional.empty()), archiveService.authorizeAccessByTenantName.get(tenant1));
+ assertEquals(new ArchiveAccess(Optional.of(tenant2role), Optional.empty()), archiveService.authorizeAccessByTenantName.get(tenant2));
var expected = Map.of("archive.bucketCount",
tester.controller().zoneRegistry().zonesIncludingSystem().all().ids().stream()
@@ -59,7 +60,7 @@ public class ArchiveAccessMaintainerTest {
private TenantName createTenantWithAccessRole(ControllerTester tester, String tenantName, String role) {
var tenant = tester.createTenant(tenantName, Tenant.Type.cloud);
tester.controller().tenants().lockOrThrow(tenant, LockedTenant.Cloud.class, lockedTenant -> {
- lockedTenant = lockedTenant.withArchiveAccessRole(Optional.of(role));
+ lockedTenant = lockedTenant.withArchiveAccess(new ArchiveAccess(Optional.of(role), Optional.empty()));
tester.controller().tenants().store(lockedTenant);
});
return tenant;
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java
index 75dbebe96ff..5666f8bafd8 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java
@@ -20,6 +20,7 @@ import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
import com.yahoo.vespa.hosted.controller.deployment.DeploymentContext;
import com.yahoo.vespa.hosted.controller.integration.ZoneRegistryMock;
import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb;
+import com.yahoo.vespa.hosted.controller.tenant.ArchiveAccess;
import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
import com.yahoo.vespa.hosted.controller.tenant.LastLoginInfo;
import com.yahoo.vespa.hosted.controller.tenant.TenantContacts;
@@ -60,7 +61,7 @@ public class NotificationsDbTest {
List.of(TenantContacts.Audience.NOTIFICATIONS),
email)))),
List.of(),
- Optional.empty());
+ new ArchiveAccess());
private static final List<Notification> notifications = List.of(
notification(1001, Type.deployment, Level.error, NotificationSource.from(tenant), "tenant msg"),
notification(1101, Type.applicationPackage, Level.warning, NotificationSource.from(TenantAndApplicationId.from(tenant.value(), "app1")), "app msg"),
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
index e0d14f19f21..431cfbbcbad 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
@@ -6,12 +6,14 @@ import com.yahoo.config.provision.TenantName;
import com.yahoo.security.KeyUtils;
import com.yahoo.slime.Cursor;
import com.yahoo.slime.Slime;
+import com.yahoo.slime.SlimeUtils;
import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore;
import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal;
+import com.yahoo.vespa.hosted.controller.tenant.ArchiveAccess;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
import com.yahoo.vespa.hosted.controller.tenant.DeletedTenant;
@@ -101,7 +103,7 @@ public class TenantSerializerTest {
otherPublicKey, new SimplePrincipal("jane")),
TenantInfo.empty(),
List.of(),
- Optional.empty()
+ new ArchiveAccess()
);
CloudTenant serialized = (CloudTenant) serializer.tenantFrom(serializer.toSlime(tenant));
assertEquals(tenant.name(), serialized.name());
@@ -123,13 +125,61 @@ public class TenantSerializerTest {
new TenantSecretStore("ss1", "123", "role1"),
new TenantSecretStore("ss2", "124", "role2")
),
- Optional.of("arn:aws:iam::123456789012:role/my-role")
+ new ArchiveAccess(Optional.of("arn:aws:iam::123456789012:role/my-role"), Optional.empty())
);
CloudTenant serialized = (CloudTenant) serializer.tenantFrom(serializer.toSlime(tenant));
assertEquals(tenant.info(), serialized.info());
assertEquals(tenant.tenantSecretStores(), serialized.tenantSecretStores());
}
+ @Test
+ public void cloud_tenant_with_old_archive_access_serialization() {
+ var json = "{\n" +
+ " \"name\": \"elderly-lady\",\n" +
+ " \"type\": \"cloud\",\n" +
+ " \"createdAt\": 1234,\n" +
+ " \"lastLoginInfo\": {\n" +
+ " \"user\": 123,\n" +
+ " \"developer\": 456\n" +
+ " },\n" +
+ " \"creator\": \"foobar-user\",\n" +
+ " \"pemDeveloperKeys\": [\n" +
+ " {\n" +
+ " \"key\": \"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuKVFA8dXk43kVfYKzkUqhEY2rDT9\\nz/4jKSTHwbYR8wdsOSrJGVEUPbS2nguIJ64OJH7gFnxM6sxUVj+Nm2HlXw==\\n-----END PUBLIC KEY-----\\n\",\n" +
+ " \"user\": \"joe\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"key\": \"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFELzPyinTfQ/sZnTmRp5E4Ve/sbE\\npDhJeqczkyFcT2PysJ5sZwm7rKPEeXDOhzTPCyRvbUqc2SGdWbKUGGa/Yw==\\n-----END PUBLIC KEY-----\\n\",\n" +
+ " \"user\": \"jane\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"billingInfo\": {\n" +
+ " \"customerId\": \"customer\",\n" +
+ " \"productCode\": \"Vespa\"\n" +
+ " },\n" +
+ " \"archiveAccessRole\": \"arn:aws:iam::123456789012:role/my-role\"\n" +
+ "}";
+ var tenant = (CloudTenant) serializer.tenantFrom(SlimeUtils.jsonToSlime(json));
+ assertEquals("arn:aws:iam::123456789012:role/my-role", tenant.archiveAccess().awsRole().get());
+ assertFalse(tenant.archiveAccess().gcpMember().isPresent());
+ }
+
+ @Test
+ public void cloud_tenant_with_archive_access() {
+ CloudTenant tenant = new CloudTenant(TenantName.from("elderly-lady"),
+ Instant.ofEpochMilli(1234L),
+ lastLoginInfo(123L, 456L, null),
+ Optional.of(new SimplePrincipal("foobar-user")),
+ ImmutableBiMap.of(publicKey, new SimplePrincipal("joe"),
+ otherPublicKey, new SimplePrincipal("jane")),
+ TenantInfo.empty(),
+ List.of(),
+ new ArchiveAccess(Optional.of("arn:aws:iam::123456789012:role/my-role"), Optional.of("user:foo@example.com"))
+ );
+ CloudTenant serialized = (CloudTenant) serializer.tenantFrom(serializer.toSlime(tenant));
+ assertEquals(serialized.archiveAccess().awsRole().get(), "arn:aws:iam::123456789012:role/my-role");
+ assertEquals(serialized.archiveAccess().gcpMember().get(), "user:foo@example.com");
+ }
@Test
public void cloud_tenant_with_tenant_info_partial() {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java
index 15c7dbf73ab..9024d7c8e7e 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilterTest.java
@@ -16,6 +16,7 @@ import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal;
import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
import com.yahoo.vespa.hosted.controller.restapi.ApplicationRequestToDiscFilterRequestWrapper;
+import com.yahoo.vespa.hosted.controller.tenant.ArchiveAccess;
import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
import com.yahoo.vespa.hosted.controller.tenant.LastLoginInfo;
import com.yahoo.vespa.hosted.controller.tenant.TenantInfo;
@@ -76,7 +77,7 @@ public class SignatureFilterTest {
ImmutableBiMap.of(),
TenantInfo.empty(),
List.of(),
- Optional.empty()));
+ new ArchiveAccess()));
tester.curator().writeApplication(new Application(appId, tester.clock().instant()));
}
@@ -122,7 +123,7 @@ public class SignatureFilterTest {
ImmutableBiMap.of(publicKey, () -> "user"),
TenantInfo.empty(),
List.of(),
- Optional.empty()));
+ new ArchiveAccess()));
verifySecurityContext(requestOf(signer.signed(request.copy(), Method.POST, () -> new ByteArrayInputStream(hiBytes)), hiBytes),
new SecurityContext(new SimplePrincipal("user"),
Set.of(Role.reader(id.tenant()),