Skip to content

Commit

Permalink
Support for deployment in Azure Government Cloud (BPM) (#505)
Browse files Browse the repository at this point in the history
* Add Support for AzureGov hosting

* Update AzureConfiguration.java

* specify azureEnvironment

* debug azureEnvironment

* remove debug logs

* Update ProfileApiController.java

* Update PolicyServiceConfiguration.java

* Revert "Update ProfileApiController.java"

This reverts commit 1315166.

* Reapply "Update ProfileApiController.java"

This reverts commit 56bab1a.

* remove

* cleanup

* tests

* spotless
  • Loading branch information
bennettn4 authored Jan 21, 2025
1 parent 863d611 commit 79bc839
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package bio.terra.profile.app.configuration;

import com.azure.core.credential.TokenCredential;
import com.azure.core.management.AzureEnvironment;
import com.azure.identity.*;
import java.util.Set;
import org.slf4j.Logger;
Expand All @@ -9,6 +10,7 @@

@ConfigurationProperties(prefix = "profile.azure")
public record AzureConfiguration(
String azureEnvironment,
String managedAppClientId,
String managedAppClientSecret,
String managedAppTenantId,
Expand Down Expand Up @@ -71,6 +73,7 @@ public TokenCredential buildManagedAppCredentials() {

ClientSecretCredential servicePrincipalCredential =
new ClientSecretCredentialBuilder()
.authorityHost(getAzureEnvironment().getActiveDirectoryEndpoint())
.clientId(managedAppClientId)
.clientSecret(managedAppClientSecret)
.tenantId(managedAppTenantId)
Expand Down Expand Up @@ -109,4 +112,16 @@ public Set<String> getRequiredProviders() {
public Boolean getControlPlaneEnabled() {
return controlPlaneEnabled;
}

public AzureEnvironment getAzureEnvironment() {
switch (azureEnvironment) {
case "AZURE":
return AzureEnvironment.AZURE;
case "AZURE_GOV":
return AzureEnvironment.AZURE_US_GOVERNMENT;
default:
throw new IllegalArgumentException(
String.format("Unknown Azure environment: %s", azureEnvironment));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ public String getClientCredentialFilePath() {

public String getAccessToken() throws IOException {
if (azureConfiguration.controlPlaneEnabled()) {
TokenCredential credential = new DefaultAzureCredentialBuilder().build();

TokenCredential credential =
new DefaultAzureCredentialBuilder()
.authorityHost(azureConfiguration.getAzureEnvironment().getActiveDirectoryEndpoint())
.build();

// The Microsoft Authentication Library (MSAL) currently specifies offline_access, openid,
// profile, and email by default in authorization and token requests.
com.azure.core.credential.AccessToken token =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -23,6 +25,8 @@ public class ProfileApiController implements ProfileApi {
private final ProfileService profileService;
private final AuthenticatedUserRequestFactory authenticatedUserRequestFactory;

private static final Logger logger = LoggerFactory.getLogger(ProfileApiController.class);

@Autowired
public ProfileApiController(
HttpServletRequest request,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import bio.terra.cloudres.common.ClientConfig;
import bio.terra.profile.app.configuration.AzureConfiguration;
import com.azure.core.management.AzureEnvironment;
import com.azure.core.management.profile.AzureProfile;
import com.azure.resourcemanager.containerservice.ContainerServiceManager;
import com.azure.resourcemanager.costmanagement.CostManagementManager;
Expand Down Expand Up @@ -33,7 +32,10 @@ public ResourceManager getResourceManager(UUID subscriptionId) {
/** Returns an Azure {@link ResourceManager} configured for use with CRL. */
public ResourceManager getResourceManager(UUID tenantId, UUID subscriptionId) {
AzureProfile azureProfile =
new AzureProfile(tenantId.toString(), subscriptionId.toString(), AzureEnvironment.AZURE);
new AzureProfile(
tenantId.toString(),
subscriptionId.toString(),
azureConfiguration.getAzureEnvironment());

// We must use FQDN because there are two `Defaults` symbols imported otherwise.
return bio.terra.cloudres.azure.resourcemanager.common.Defaults.crlConfigure(
Expand All @@ -44,23 +46,23 @@ public ResourceManager getResourceManager(UUID tenantId, UUID subscriptionId) {

public ApplicationManager getApplicationManager(UUID subscriptionId) {
AzureProfile azureProfile =
new AzureProfile(null, subscriptionId.toString(), AzureEnvironment.AZURE);
new AzureProfile(null, subscriptionId.toString(), azureConfiguration.getAzureEnvironment());

return ApplicationManager.authenticate(
azureConfiguration.buildManagedAppCredentials(), azureProfile);
}

public CostManagementManager getCostManagementManager(UUID subscriptionId) {
AzureProfile azureProfile =
new AzureProfile(null, subscriptionId.toString(), AzureEnvironment.AZURE);
new AzureProfile(null, subscriptionId.toString(), azureConfiguration.getAzureEnvironment());

return CostManagementManager.authenticate(
azureConfiguration.buildManagedAppCredentials(), azureProfile);
}

public ContainerServiceManager getContainerServiceManager(UUID subscriptionId) {
AzureProfile azureProfile =
new AzureProfile(null, subscriptionId.toString(), AzureEnvironment.AZURE);
new AzureProfile(null, subscriptionId.toString(), azureConfiguration.getAzureEnvironment());

return ContainerServiceManager.authenticate(
azureConfiguration.buildManagedAppCredentials(), azureProfile);
Expand Down
4 changes: 4 additions & 0 deletions service/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ env:
basePath: ${SAM_ADDRESS:https://sam.dsde-dev.broadinstitute.org/}
adminsGroupEmail: ${SAM_ADMINS_GROUP_EMAIL:admin-group}
azure:
azureEnvironment: ${AZURE_ENVIRONMENT:AZURE}
managedAppClientId: ${MANAGED_APP_CLIENT_ID:app-client}
managedAppClientSecret: ${MANAGED_APP_CLIENT_SECRET:app-secret}
managedAppTenantId: ${MANAGED_APP_TENANT_ID:app-tenant}
Expand Down Expand Up @@ -112,6 +113,9 @@ profile:
username: ${env.db.profile.user}

azure:
# azure hosting environment: AZURE for commercial and AZURE_GOV for govcloud
azure-environment: ${env.azure.azureEnvironment}

managed-app-clientId: ${env.azure.managedAppClientId}
managed-app-client-secret: ${env.azure.managedAppClientSecret}
managed-app-tenant-id: ${env.azure.managedAppTenantId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@ void getManagedApps() {
new AzureService(
crlService,
new AzureConfiguration(
"fake", "fake", "fake", "fake", false, ".default", offers, ImmutableSet.of()),
"AZURE",
"fake",
"fake",
"fake",
"fake",
false,
".default",
offers,
ImmutableSet.of()),
profileDao);

var result = azureService.getAuthorizedManagedAppDeployments(subId, true, user);
Expand Down Expand Up @@ -219,7 +227,15 @@ void getServiceCatalogManagedApps() {
new AzureService(
crlService,
new AzureConfiguration(
"fake", "fake", "fake", "fake", true, ".default", offers, ImmutableSet.of()),
"AZURE",
"fake",
"fake",
"fake",
"fake",
true,
".default",
offers,
ImmutableSet.of()),
profileDao);

var result = azureService.getAuthorizedManagedAppDeployments(subId, true, user);
Expand Down Expand Up @@ -265,7 +281,15 @@ void getManagedApps_dedupesApps() {
new AzureService(
crlService,
new AzureConfiguration(
"fake", "fake", "fake", "fake", false, ".default", offers, ImmutableSet.of()),
"AZURE",
"fake",
"fake",
"fake",
"fake",
false,
".default",
offers,
ImmutableSet.of()),
profileDao);

var result = azureService.getAuthorizedManagedAppDeployments(subId, true, user);
Expand Down Expand Up @@ -336,7 +360,15 @@ void getManagedApps_excludingAssignedApplications() {
new AzureService(
crlService,
new AzureConfiguration(
"fake", "fake", "fake", "fake", false, ".default", offers, ImmutableSet.of()),
"AZURE",
"fake",
"fake",
"fake",
"fake",
false,
".default",
offers,
ImmutableSet.of()),
profileDao);

var result = azureService.getAuthorizedManagedAppDeployments(subId, false, user);
Expand Down Expand Up @@ -387,7 +419,15 @@ void getManagedApps_includingAssignedApplications() {
new AzureService(
crlService,
new AzureConfiguration(
"fake", "fake", "fake", "fake", false, ".default", offers, ImmutableSet.of()),
"AZURE",
"fake",
"fake",
"fake",
"fake",
false,
".default",
offers,
ImmutableSet.of()),
profileDao);

AzureManagedAppModel assignedAzureManagedAppModel =
Expand Down Expand Up @@ -448,7 +488,15 @@ void getManagedApps_handlesDifferentEmailFormats(String authorizedEmails) {
new AzureService(
crlService,
new AzureConfiguration(
"fake", "fake", "fake", "fake", false, ".default", offers, ImmutableSet.of()),
"AZURE",
"fake",
"fake",
"fake",
"fake",
false,
".default",
offers,
ImmutableSet.of()),
profileDao);

var result = azureService.getAuthorizedManagedAppDeployments(subId, true, user);
Expand Down Expand Up @@ -478,6 +526,7 @@ void getTenantForSubscription_inaccessibleSubscription() {
new AzureService(
crlService,
new AzureConfiguration(
"AZURE",
"fake",
"fake",
"fake",
Expand All @@ -504,6 +553,7 @@ void getTenantForSubscription_otherMgmtError() {
new AzureService(
crlService,
new AzureConfiguration(
"AZURE",
"fake",
"fake",
"fake",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ void before() {
"creator");
var azureConfiguration =
new AzureConfiguration(
"AZURE",
"fake_appid",
"fake_client",
"fake_secret",
Expand Down

0 comments on commit 79bc839

Please sign in to comment.