in polaris-core/src/main/java/org/apache/polaris/core/storage/gcp/GcpCredentialsStorageIntegration.java [127:203]
public static CredentialAccessBoundary generateAccessBoundaryRules(
boolean allowListOperation,
@Nonnull Set<String> allowedReadLocations,
@Nonnull Set<String> allowedWriteLocations) {
Map<String, List<String>> readConditionsMap = new HashMap<>();
Map<String, List<String>> writeConditionsMap = new HashMap<>();
HashSet<String> readBuckets = new HashSet<>();
HashSet<String> writeBuckets = new HashSet<>();
Stream.concat(allowedReadLocations.stream(), allowedWriteLocations.stream())
.distinct()
.forEach(
location -> {
URI uri = URI.create(location);
String bucket = StorageUtil.getBucket(uri);
readBuckets.add(bucket);
String path = uri.getPath().substring(1);
List<String> resourceExpressions =
readConditionsMap.computeIfAbsent(bucket, key -> new ArrayList<>());
resourceExpressions.add(
String.format(
"resource.name.startsWith('projects/_/buckets/%s/objects/%s')",
bucket, path));
if (allowListOperation) {
resourceExpressions.add(
String.format(
"api.getAttribute('storage.googleapis.com/objectListPrefix', '').startsWith('%s')",
path));
}
if (allowedWriteLocations.contains(location)) {
writeBuckets.add(bucket);
List<String> writeExpressions =
writeConditionsMap.computeIfAbsent(bucket, key -> new ArrayList<>());
writeExpressions.add(
String.format(
"resource.name.startsWith('projects/_/buckets/%s/objects/%s')",
bucket, path));
}
});
CredentialAccessBoundary.Builder accessBoundaryBuilder = CredentialAccessBoundary.newBuilder();
readBuckets.forEach(
bucket -> {
List<String> readConditions = readConditionsMap.get(bucket);
if (readConditions == null || readConditions.isEmpty()) {
return;
}
CredentialAccessBoundary.AccessBoundaryRule.Builder builder =
CredentialAccessBoundary.AccessBoundaryRule.newBuilder();
builder.setAvailableResource(bucketResource(bucket));
builder.setAvailabilityCondition(
CredentialAccessBoundary.AccessBoundaryRule.AvailabilityCondition.newBuilder()
.setExpression(String.join(" || ", readConditions))
.build());
builder.setAvailablePermissions(List.of("inRole:roles/storage.legacyObjectReader"));
if (allowListOperation) {
builder.addAvailablePermission("inRole:roles/storage.objectViewer");
}
accessBoundaryBuilder.addRule(builder.build());
});
writeBuckets.forEach(
bucket -> {
List<String> writeConditions = writeConditionsMap.get(bucket);
if (writeConditions == null || writeConditions.isEmpty()) {
return;
}
CredentialAccessBoundary.AccessBoundaryRule.Builder builder =
CredentialAccessBoundary.AccessBoundaryRule.newBuilder();
builder.setAvailableResource(bucketResource(bucket));
builder.setAvailabilityCondition(
CredentialAccessBoundary.AccessBoundaryRule.AvailabilityCondition.newBuilder()
.setExpression(String.join(" || ", writeConditions))
.build());
builder.setAvailablePermissions(List.of("inRole:roles/storage.legacyBucketWriter"));
accessBoundaryBuilder.addRule(builder.build());
});
return accessBoundaryBuilder.build();
}