Search in sources :

Example 1 with InternalServerErrorException

use of bio.terra.common.exception.InternalServerErrorException in project terra-workspace-manager by DataBiosphere.

the class SamService method initializeWsmServiceAccount.

/**
 * Register WSM's service account as a user in Sam if it isn't already. This should only need to
 * register with Sam once per environment, so it is implemented lazily.
 */
private void initializeWsmServiceAccount() throws InterruptedException {
    if (!wsmServiceAccountInitialized) {
        String wsmAccessToken = null;
        try {
            wsmAccessToken = getWsmServiceAccountToken();
        } catch (InternalServerErrorException e) {
            // In cases where WSM is not running as a service account (e.g. unit tests), the above call
            // will throw. This can be ignored now and later when the credentials are used again.
            logger.warn("Failed to register WSM service account in Sam. This is expected for tests.", e);
            return;
        }
        UsersApi usersApi = samUsersApi(wsmAccessToken);
        // If registering the service account fails, all we can do is to keep trying.
        if (!wsmServiceAccountRegistered(usersApi)) {
            // retries internally
            registerWsmServiceAccount(usersApi);
        }
        wsmServiceAccountInitialized = true;
    }
}
Also used : UsersApi(org.broadinstitute.dsde.workbench.client.sam.api.UsersApi) InternalServerErrorException(bio.terra.common.exception.InternalServerErrorException)

Example 2 with InternalServerErrorException

use of bio.terra.common.exception.InternalServerErrorException in project terra-workspace-manager by DataBiosphere.

the class SamService method getOrCreatePetSaCredentials.

/**
 * Fetch credentials of a user's pet service account in a given project. This request to Sam will
 * create the pet SA if it doesn't already exist.
 */
public AuthenticatedUserRequest getOrCreatePetSaCredentials(String projectId, AuthenticatedUserRequest userRequest) throws InterruptedException {
    GoogleApi samGoogleApi = samGoogleApi(userRequest.getRequiredToken());
    try {
        String petEmail = getOrCreatePetSaEmail(projectId, userRequest.getRequiredToken());
        String petToken = SamRetry.retry(() -> samGoogleApi.getPetServiceAccountToken(projectId, PET_SA_OAUTH_SCOPES));
        // This should never happen, but it's more informative than an NPE from Optional.of
        if (petToken == null) {
            throw new InternalServerErrorException("Sam returned null pet service account token");
        }
        return new AuthenticatedUserRequest().email(petEmail).token(Optional.of(petToken));
    } catch (ApiException apiException) {
        throw SamExceptionFactory.create("Error getting pet service account token from Sam", apiException);
    }
}
Also used : GoogleApi(org.broadinstitute.dsde.workbench.client.sam.api.GoogleApi) InternalServerErrorException(bio.terra.common.exception.InternalServerErrorException) ApiException(org.broadinstitute.dsde.workbench.client.sam.ApiException)

Example 3 with InternalServerErrorException

use of bio.terra.common.exception.InternalServerErrorException in project terra-workspace-manager by DataBiosphere.

the class PetSaService method enablePetServiceAccountImpersonationWithEtag.

/**
 * Grant a user's proxy group permission to impersonate their pet service account in a given
 * workspace. Unlike other operations, this does not run as a flight because it only requires one
 * write operation. This operation is idempotent.
 *
 * <p>The provided workspace must have a GCP context.
 *
 * <p>This method does not authenticate that the user should have access to impersonate their pet
 * SA, callers should validate this first.
 *
 * <p>userToEnableEmail is separate from token because of RevokePetUsagePermissionStep.undoStep().
 * If User A removes B from workspace, userToEnableEmail is B and token is from A's userRequest.
 *
 * @param workspaceId ID of the workspace to enable pet SA in
 * @param userToEnableEmail The user whose proxy group will be granted permission.
 * @param token Token for calling SAM.
 * @param eTag GCP eTag which must match the pet SA's current policy. If null, this is ignored.
 * @return The new IAM policy on the user's pet service account, or empty if the eTag value
 *     provided is non-null and does not match current IAM policy on the pet SA.
 */
public Optional<Policy> enablePetServiceAccountImpersonationWithEtag(UUID workspaceId, String userToEnableEmail, String token, @Nullable String eTag) {
    String petSaEmail = SamRethrow.onInterrupted(() -> samService.getOrCreatePetSaEmail(gcpCloudContextService.getRequiredGcpProject(workspaceId), token), "enablePet");
    String proxyGroupEmail = SamRethrow.onInterrupted(() -> samService.getProxyGroupEmail(userToEnableEmail, token), "enablePet");
    String projectId = gcpCloudContextService.getRequiredGcpProject(workspaceId);
    ServiceAccountName petSaName = ServiceAccountName.builder().email(petSaEmail).projectId(projectId).build();
    try {
        Policy saPolicy = crlService.getIamCow().projects().serviceAccounts().getIamPolicy(petSaName).execute();
        // clobbering other changes.
        if (eTag != null && !saPolicy.getEtag().equals(eTag)) {
            logger.warn("GCP IAM policy eTag did not match expected value when granting pet SA access for user {} in workspace {}. This is normal for Step retries.", userToEnableEmail, workspaceId);
            return Optional.empty();
        }
        Binding saUserBinding = new Binding().setRole(SERVICE_ACCOUNT_USER_ROLE).setMembers(ImmutableList.of("group:" + proxyGroupEmail));
        // If no bindings exist, getBindings() returns null instead of an empty list.
        List<Binding> bindingList = Optional.ofNullable(saPolicy.getBindings()).orElse(new ArrayList<>());
        // GCP automatically de-duplicates bindings, so this will have no effect if the user already
        // has permission to use their pet service account.
        bindingList.add(saUserBinding);
        saPolicy.setBindings(bindingList);
        SetIamPolicyRequest request = new SetIamPolicyRequest().setPolicy(saPolicy);
        return Optional.of(crlService.getIamCow().projects().serviceAccounts().setIamPolicy(petSaName, request).execute());
    } catch (IOException e) {
        throw new InternalServerErrorException("Error enabling user's proxy group to impersonate pet SA", e);
    }
}
Also used : Policy(com.google.api.services.iam.v1.model.Policy) Binding(com.google.api.services.iam.v1.model.Binding) SetIamPolicyRequest(com.google.api.services.iam.v1.model.SetIamPolicyRequest) InternalServerErrorException(bio.terra.common.exception.InternalServerErrorException) ServiceAccountName(bio.terra.cloudres.google.iam.ServiceAccountName) IOException(java.io.IOException)

Example 4 with InternalServerErrorException

use of bio.terra.common.exception.InternalServerErrorException in project terra-workspace-manager by DataBiosphere.

the class PetSaService method disablePetServiceAccountImpersonationWithEtag.

/**
 * Revoke the permission to impersonate a pet service account granted by {@code
 * enablePetServiceAccountImpersonation}. Unlike other operations, this does not run in a flight
 * because it only requires one write operation. This operation is idempotent.
 *
 * <p>This method requires a user's pet service account email as input. As a transitive
 * dependency, this also means the provided workspace must have a GCP context.
 *
 * <p>This method does not authenticate that the user should have access to impersonate their pet
 * SA, callers should validate this first.
 *
 * @param workspaceId ID of the workspace to disable pet SA in
 * @param userToDisableEmail The user losing access to pet SA
 * @param userRequest This request's token will be used to authenticate SAM requests
 * @param eTag GCP eTag which must match the pet SA's current policy. If null, this is ignored.
 */
public Optional<Policy> disablePetServiceAccountImpersonationWithEtag(UUID workspaceId, String userToDisableEmail, AuthenticatedUserRequest userRequest, @Nullable String eTag) {
    String proxyGroupEmail = SamRethrow.onInterrupted(() -> samService.getProxyGroupEmail(userToDisableEmail, userRequest.getRequiredToken()), "disablePet");
    String projectId = gcpCloudContextService.getRequiredGcpProject(workspaceId);
    try {
        Optional<ServiceAccountName> userToDisablePetSA = getUserPetSa(projectId, userToDisableEmail, userRequest);
        if (userToDisablePetSA.isEmpty()) {
            return Optional.empty();
        }
        Policy saPolicy = crlService.getIamCow().projects().serviceAccounts().getIamPolicy(userToDisablePetSA.get()).execute();
        // clobbering other changes.
        if (eTag != null && !saPolicy.getEtag().equals(eTag)) {
            logger.warn("GCP IAM policy eTag did not match expected value when revoking pet SA access for user {} in workspace {}. This is normal for Step retries.", userToDisableEmail, workspaceId);
            return Optional.empty();
        }
        Binding bindingToRemove = new Binding().setRole(SERVICE_ACCOUNT_USER_ROLE).setMembers(ImmutableList.of("group:" + proxyGroupEmail));
        // If no bindings exist, getBindings() returns null instead of an empty list. If there are
        // no policies, there is nothing to revoke, so this method is finished.
        List<Binding> oldBindingList = saPolicy.getBindings();
        if (oldBindingList == null) {
            return Optional.empty();
        }
        List<Binding> newBindingsList = removeBinding(oldBindingList, bindingToRemove);
        saPolicy.setBindings(newBindingsList);
        SetIamPolicyRequest request = new SetIamPolicyRequest().setPolicy(saPolicy);
        return Optional.of(crlService.getIamCow().projects().serviceAccounts().setIamPolicy(userToDisablePetSA.get(), request).execute());
    } catch (IOException e) {
        throw new InternalServerErrorException("Error disabling user's proxy group to impersonate pet SA", e);
    }
}
Also used : Policy(com.google.api.services.iam.v1.model.Policy) Binding(com.google.api.services.iam.v1.model.Binding) SetIamPolicyRequest(com.google.api.services.iam.v1.model.SetIamPolicyRequest) InternalServerErrorException(bio.terra.common.exception.InternalServerErrorException) ServiceAccountName(bio.terra.cloudres.google.iam.ServiceAccountName) IOException(java.io.IOException)

Example 5 with InternalServerErrorException

use of bio.terra.common.exception.InternalServerErrorException in project terra-workspace-manager by DataBiosphere.

the class ControlledResourceSamPolicyBuilder method addWsmResourceOwnerPolicy.

/**
 * Add WSM's service account as the owner of a controlled resource in Sam. Used for admin
 * reassignment of resources. This assumes samService.initialize() has already been called, which
 * should happen on start.
 */
private void addWsmResourceOwnerPolicy(CreateResourceRequestV2 request) {
    try {
        AccessPolicyMembershipV2 ownerPolicy = new AccessPolicyMembershipV2().addRolesItem(ControlledResourceIamRole.OWNER.toSamRole()).addMemberEmailsItem(GcpUtils.getWsmSaEmail());
        request.putPoliciesItem(ControlledResourceIamRole.OWNER.toSamRole(), ownerPolicy);
    } catch (InternalServerErrorException e) {
        // In cases where WSM is not running as a service account (e.g. unit tests), the above call to
        // get application default credentials will fail. This is fine, as those cases don't create
        // real resources.
        logger.warn("Failed to add WSM service account as resource owner Sam. This is expected for tests.", e);
    }
}
Also used : AccessPolicyMembershipV2(org.broadinstitute.dsde.workbench.client.sam.model.AccessPolicyMembershipV2) InternalServerErrorException(bio.terra.common.exception.InternalServerErrorException)

Aggregations

InternalServerErrorException (bio.terra.common.exception.InternalServerErrorException)10 IOException (java.io.IOException)4 Resource (bio.terra.buffer.common.Resource)2 ServiceAccountName (bio.terra.cloudres.google.iam.ServiceAccountName)2 Binding (com.google.api.services.iam.v1.model.Binding)2 Policy (com.google.api.services.iam.v1.model.Policy)2 SetIamPolicyRequest (com.google.api.services.iam.v1.model.SetIamPolicyRequest)2 AccessPolicyMembershipV2 (org.broadinstitute.dsde.workbench.client.sam.model.AccessPolicyMembershipV2)2 Pool (bio.terra.buffer.common.Pool)1 NotFoundException (bio.terra.buffer.common.exception.NotFoundException)1 BadRequestException (bio.terra.common.exception.BadRequestException)1 Binding (com.google.api.services.cloudresourcemanager.v3.model.Binding)1 GetIamPolicyRequest (com.google.api.services.cloudresourcemanager.v3.model.GetIamPolicyRequest)1 Policy (com.google.api.services.cloudresourcemanager.v3.model.Policy)1 SetIamPolicyRequest (com.google.api.services.cloudresourcemanager.v3.model.SetIamPolicyRequest)1 GoogleCredentials (com.google.auth.oauth2.GoogleCredentials)1 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 ApiException (org.broadinstitute.dsde.workbench.client.sam.ApiException)1 GoogleApi (org.broadinstitute.dsde.workbench.client.sam.api.GoogleApi)1 UsersApi (org.broadinstitute.dsde.workbench.client.sam.api.UsersApi)1