in sources/src/main/java/com/google/solutions/jitaccess/catalog/provisioning/Provisioner.java [377:453]
void provisionAccess(
@NotNull GroupId groupId,
@NotNull Set<IamRoleBinding> roleBindings
) throws AccessException, IOException {
var groupDetails = this.groupsClient.getGroup(groupId);
var expectedChecksum = IamBindingChecksum.fromBindings(roleBindings);
var actualChecksum = IamBindingChecksum.fromTaggedDescription(groupDetails.getDescription());
if (actualChecksum.equals(expectedChecksum)) {
//
// The checksums match, indicating that the role bindings we provisioned
// previously are still current.
//
}
else {
this.logger.info(
EventIds.PROVISION_IAM_BINDINGS,
"IAM role bindings for group %s have changed (expected checksum: %s, actual: %s), provisioning...",
groupId,
expectedChecksum,
actualChecksum);
//
// One or more role bindings must have changed, so we need to
// re-provision all bindings.
//
// If there are multiple roles for a single resource, we can
// provision them at once.
//
var future = CompletableFutures.mapAsync(
roleBindings
.stream()
.collect(Collectors.groupingBy(b -> b.resource()))
.entrySet(),
bindingsForResource -> {
this.resourceManagerClient.modifyIamPolicy(
bindingsForResource.getKey(),
policy -> replaceBindingsForPrincipals(policy, groupId, bindingsForResource.getValue()),
"Provisioning JIT group");
return bindingsForResource.getKey();
},
this.executor);
try {
future.get();
//
// Update group.
//
this.groupsClient.patchGroup(
new GroupKey(groupDetails.getName()),
expectedChecksum.toTaggedDescription(groupDetails.getDescription()));
this.logger.info(
EventIds.PROVISION_IAM_BINDINGS,
"IAM role bindings for group %s provisioned",
groupId,
expectedChecksum,
actualChecksum);
}
catch (InterruptedException | ExecutionException e) {
if (Exceptions.unwrap(e) instanceof AccessException accessException) {
this.logger.error(
EventIds.PROVISION_IAM_BINDINGS,
String.format("Provisioning IAM role bindings for group %s failed", groupId),
accessException);
throw (AccessException) accessException.fillInStackTrace();
}
else {
throw new UncheckedExecutionException(e);
}
}
}
}