diff --git a/http/src/main/resources/init-resources/azure_vm_init_script.sh b/http/src/main/resources/init-resources/azure_vm_init_script.sh index 986c75669e6..cf2690f6593 100644 --- a/http/src/main/resources/init-resources/azure_vm_init_script.sh +++ b/http/src/main/resources/init-resources/azure_vm_init_script.sh @@ -109,6 +109,8 @@ SAMURL=$6 SAMRESOURCEID=$7 CONTENTSECURITYPOLICY_FILE=$8 +RELAY_SUFFIX=${21:-".servicebus.windows.net"} + # Envs for welder WELDER_WSM_URL=${9:-localhost} WORKSPACE_ID="${10:-dummy}" # Additionally used for welder @@ -126,11 +128,11 @@ WORKSPACE_STORAGE_CONTAINER_URL="${17:-dummy}" SERVER_APP_BASE_URL="/${RELAY_CONNECTION_NAME}/" SERVER_APP_ALLOW_ORIGIN="*" HCVAR='\$hc' -SERVER_APP_WEBSOCKET_URL="wss://${RELAY_NAME}.servicebus.windows.net/${HCVAR}/${RELAY_CONNECTION_NAME}" -SERVER_APP_WEBSOCKET_HOST="${RELAY_NAME}.servicebus.windows.net" +SERVER_APP_WEBSOCKET_URL="wss://${RELAY_NAME}${RELAY_SUFFIX}/${HCVAR}/${RELAY_CONNECTION_NAME}" +SERVER_APP_WEBSOCKET_HOST="${RELAY_NAME}${RELAY_SUFFIX}" # Relay listener configuration -RELAY_CONNECTIONSTRING="Endpoint=sb://${RELAY_NAME}.servicebus.windows.net/;SharedAccessKeyName=listener;SharedAccessKey=${RELAY_CONNECTION_POLICY_KEY};EntityPath=${RELAY_CONNECTION_NAME}" +RELAY_CONNECTIONSTRING="Endpoint=sb://${RELAY_NAME}${RELAY_SUFFIX}/;SharedAccessKeyName=listener;SharedAccessKey=${RELAY_CONNECTION_POLICY_KEY};EntityPath=${RELAY_CONNECTION_NAME}" # Relay listener configuration - setDateAccessed listener LEONARDO_URL="${18:-dummy}" @@ -143,6 +145,7 @@ echo "RELAY_NAME = ${RELAY_NAME}" echo "RELAY_CONNECTION_NAME = ${RELAY_CONNECTION_NAME}" echo "RELAY_TARGET_HOST = ${RELAY_TARGET_HOST}" echo "RELAY_CONNECTION_POLICY_KEY = ${RELAY_CONNECTION_POLICY_KEY}" +echo "RELAY_SUFFIX = ${RELAY_SUFFIX}" echo "LISTENER_DOCKER_IMAGE = ${LISTENER_DOCKER_IMAGE}" echo "SAMURL = ${SAMURL}" echo "SAMRESOURCEID = ${SAMRESOURCEID}" diff --git a/http/src/main/resources/leo.conf b/http/src/main/resources/leo.conf index da82b4b95bd..851ede9ebc1 100644 --- a/http/src/main/resources/leo.conf +++ b/http/src/main/resources/leo.conf @@ -165,7 +165,7 @@ azure { # If true, it is assumed that Leo is hosted on Azure and will use Azure managed identity for authentication. enabled = ${?AZURE_HOSTING_MODE_ENABLED} # valid values are AZURE (Azure Commercial), AZURE_US_GOVERNMENT and AZURE_CHINA - azure-environment = ${?AZURE_HOSTING_ENVIRONMENT} + azure-environment = ${?AZURE_ENVIRONMENT} managed-identity-auth-config{ token-scope = ${?AZURE_MI_TOKEN_SCOPE} token-acquisition-timeout = ${?AZURE_MI_TOKEN_ACQUISITION_TIMEOUT} diff --git a/http/src/main/resources/reference.conf b/http/src/main/resources/reference.conf index b19492de714..e10f307cceb 100644 --- a/http/src/main/resources/reference.conf +++ b/http/src/main/resources/reference.conf @@ -255,7 +255,7 @@ azure { type = "CustomScript", version = "2.1", minor-version-auto-upgrade = true, - file-uris = ["https://raw.githubusercontent.com/DataBiosphere/leonardo/8390d25ccd761fb206cf388560a571be77a42bbd/http/src/main/resources/init-resources/azure_vm_init_script.sh"] + file-uris = ["https://raw.githubusercontent.com/DataBiosphere/leonardo/f58c237b4dc235cd1c24c6dfc7500c07bdbd5bc3/http/src/main/resources/init-resources/azure_vm_init_script.sh"] } # [IA-4997] to support CHIPS by setting partitioned cookies # listener-image = "terradevacrpublic.azurecr.io/terra-azure-relay-listeners:474f157" @@ -374,7 +374,7 @@ azure { cromwell-runner-app-config { instrumentation-enabled = false chart-name = "terra-helm/cromwell-runner-app" - chart-version = "0.197.0" + chart-version = "0.198.0" release-name-suffix = "cra-rls" namespace-name-suffix = "cra-ns" ksa-name = "cra-ksa" diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellAppInstall.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellAppInstall.scala index d0f6a0cff57..9f9c7b18f56 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellAppInstall.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellAppInstall.scala @@ -7,7 +7,8 @@ import org.broadinstitute.dsde.workbench.azure.{AzureApplicationInsightsService, import org.broadinstitute.dsde.workbench.leonardo.app.AppInstall.getAzureDatabaseName import org.broadinstitute.dsde.workbench.leonardo.{AppContext, WsmControlledDatabaseResource} import org.broadinstitute.dsde.workbench.leonardo.app.Database.ControlledDatabase -import org.broadinstitute.dsde.workbench.leonardo.config.CoaAppConfig +import org.broadinstitute.dsde.workbench.leonardo.auth.SamAuthProvider +import org.broadinstitute.dsde.workbench.leonardo.config.{AzureEnvironmentConverter, CoaAppConfig} import org.broadinstitute.dsde.workbench.leonardo.dao._ import org.broadinstitute.dsde.workbench.leonardo.http._ import org.broadinstitute.dsde.workbench.leonardo.util.AppCreationException @@ -25,7 +26,8 @@ class CromwellAppInstall[F[_]](config: CoaAppConfig, cromwellDao: CromwellDAO[F], cbasDao: CbasDAO[F], azureBatchService: AzureBatchService[F], - azureApplicationInsightsService: AzureApplicationInsightsService[F] + azureApplicationInsightsService: AzureApplicationInsightsService[F], + authProvider: SamAuthProvider[F] )(implicit F: Async[F] ) extends AppInstall[F] { @@ -69,10 +71,15 @@ class CromwellAppInstall[F[_]](config: CoaAppConfig, // Get the pet userToken tokenOpt <- samDao.getCachedArbitraryPetAccessToken(params.app.auditInfo.creator) - userToken <- F.fromOption( - tokenOpt, - AppCreationException(s"Pet not found for user ${params.app.auditInfo.creator}", Some(ctx.traceId)) - ) + userToken <- ConfigReader.appConfig.azure.hostingModeConfig.enabled match { + case false => + F.fromOption( + tokenOpt, + AppCreationException(s"Pet not found for user ${params.app.auditInfo.creator}", Some(ctx.traceId)) + ) + case true => + F.pure("") // No pet user token in Azure. + } values = List( // azure resources configs @@ -85,6 +92,12 @@ class CromwellAppInstall[F[_]](config: CoaAppConfig, raw"config.subscriptionId=${params.cloudContext.subscriptionId.value}", raw"config.region=${params.landingZoneResources.region}", raw"config.applicationInsightsConnectionString=${applicationInsightsComponent.connectionString()}", + raw"config.azureEnvironment=${ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment}", + raw"config.azureManagementTokenScope=${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getResourceManagerEndpoint}.default", + raw"config.batchAccountSuffix=${AzureEnvironmentConverter + .batchAccountSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}", // relay configs raw"relay.path=${params.relayPath.renderString}", @@ -92,6 +105,9 @@ class CromwellAppInstall[F[_]](config: CoaAppConfig, // persistence configs raw"persistence.storageResourceGroup=${params.cloudContext.managedResourceGroupName.value}", raw"persistence.storageAccount=${params.landingZoneResources.storageAccountName.value}", + raw"persistence.storageAccountSuffix=${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getStorageEndpointSuffix}", raw"persistence.blobContainer=${storageContainer.name.value}", raw"persistence.leoAppInstanceName=${params.app.appName.value}", raw"persistence.workspaceManager.url=${params.config.wsmConfig.uri.renderString}", @@ -124,7 +140,8 @@ class CromwellAppInstall[F[_]](config: CoaAppConfig, // Database configs raw"postgres.podLocalDatabaseEnabled=false", - raw"postgres.host=${postgresServer.name}.postgres.database.azure.com", + raw"postgres.host=${postgresServer.name}.postgres${AzureEnvironmentConverter + .postgresSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}", raw"postgres.pgbouncer.enabled=${postgresServer.pgBouncerEnabled}", // convention is that the database user is the same as the service account name raw"postgres.user=${params.ksaName.value}", diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellRunnerAppInstall.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellRunnerAppInstall.scala index 792bd363e93..63f2d9e4b1f 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellRunnerAppInstall.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellRunnerAppInstall.scala @@ -9,7 +9,7 @@ import org.broadinstitute.dsde.workbench.leonardo.{AppContext, WsmControlledData import org.broadinstitute.dsde.workbench.leonardo.app.AppInstall.getAzureDatabaseName import org.broadinstitute.dsde.workbench.leonardo.app.Database.{ControlledDatabase, ReferenceDatabase} import org.broadinstitute.dsde.workbench.leonardo.auth.SamAuthProvider -import org.broadinstitute.dsde.workbench.leonardo.config.{CromwellRunnerAppConfig, SamConfig} +import org.broadinstitute.dsde.workbench.leonardo.config.{AzureEnvironmentConverter, CromwellRunnerAppConfig, SamConfig} import org.broadinstitute.dsde.workbench.leonardo.dao.{BpmApiClientProvider, CromwellDAO, SamDAO} import org.broadinstitute.dsde.workbench.leonardo.http._ import org.broadinstitute.dsde.workbench.leonardo.util.AppCreationException @@ -80,11 +80,6 @@ class CromwellRunnerAppInstall[F[_]](config: CromwellRunnerAppConfig, ) // Get the pet userToken - tokenOpt <- samDao.getCachedArbitraryPetAccessToken(params.app.auditInfo.creator) - userToken <- F.fromOption( - tokenOpt, - AppCreationException(s"Pet not found for user ${params.app.auditInfo.creator}", Some(ctx.traceId)) - ) leoAuth <- authProvider.getLeoAuthToken @@ -99,6 +94,18 @@ class CromwellRunnerAppInstall[F[_]](config: CromwellRunnerAppConfig, .map(v => raw"config.concurrentJobLimit=${v}") } + // Get the pet userToken + tokenOpt <- samDao.getCachedArbitraryPetAccessToken(params.app.auditInfo.creator) + userToken <- ConfigReader.appConfig.azure.hostingModeConfig.enabled match { + case false => + F.fromOption( + tokenOpt, + AppCreationException(s"Pet not found for user ${params.app.auditInfo.creator}", Some(ctx.traceId)) + ) + case true => + F.pure("") // No pet user token in Azure. + } + values = List( // azure resources configs raw"config.resourceGroup=${params.cloudContext.managedResourceGroupName.value}", @@ -110,12 +117,21 @@ class CromwellRunnerAppInstall[F[_]](config: CromwellRunnerAppConfig, raw"config.subscriptionId=${params.cloudContext.subscriptionId.value}", raw"config.region=${params.landingZoneResources.region}", raw"config.applicationInsightsConnectionString=${applicationInsightsComponent.connectionString()}", + raw"config.azureEnvironment=${ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment}", + raw"config.azureManagementTokenScope=${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getResourceManagerEndpoint}.default", + raw"config.batchAccountSuffix=${AzureEnvironmentConverter + .batchAccountSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}", // relay configs raw"relay.path=${params.relayPath.renderString}", // persistence configs raw"persistence.storageAccount=${params.landingZoneResources.storageAccountName.value}", + raw"persistence.storageAccountSuffix=${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getStorageEndpointSuffix}", raw"persistence.blobContainer=${storageContainer.name.value}", raw"persistence.leoAppInstanceName=${params.app.appName.value}", raw"persistence.workspaceManager.url=${params.config.wsmConfig.uri.renderString}", @@ -138,7 +154,8 @@ class CromwellRunnerAppInstall[F[_]](config: CromwellRunnerAppConfig, // database configs raw"postgres.podLocalDatabaseEnabled=false", - raw"postgres.host=${postgresServer.name}.postgres.database.azure.com", + raw"postgres.host=${postgresServer.name}.postgres${AzureEnvironmentConverter + .postgresSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}", raw"postgres.pgbouncer.enabled=${postgresServer.pgBouncerEnabled}", // convention is that the database user is the same as the service account name raw"postgres.user=${params.ksaName.value}", diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/HailBatchAppInstall.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/HailBatchAppInstall.scala index c8170143dc0..5e91371de5e 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/HailBatchAppInstall.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/HailBatchAppInstall.scala @@ -3,8 +3,9 @@ import cats.effect.Async import cats.mtl.Ask import cats.syntax.all._ import org.broadinstitute.dsde.workbench.leonardo.AppContext -import org.broadinstitute.dsde.workbench.leonardo.config.HailBatchAppConfig +import org.broadinstitute.dsde.workbench.leonardo.config.{AzureEnvironmentConverter, HailBatchAppConfig} import org.broadinstitute.dsde.workbench.leonardo.dao.HailBatchDAO +import org.broadinstitute.dsde.workbench.leonardo.http.ConfigReader import org.broadinstitute.dsde.workbench.leonardo.util.AppCreationException import org.broadinstitute.dsp.Values import org.http4s.Uri @@ -34,7 +35,9 @@ class HailBatchAppInstall[F[_]](config: HailBatchAppConfig, hailBatchDao: HailBa raw"persistence.workspaceManager.url=${params.config.wsmConfig.uri.renderString}", raw"persistence.workspaceManager.workspaceId=${params.workspaceId.value}", raw"persistence.workspaceManager.containerResourceId=${storageContainer.resourceId.value.toString}", - raw"persistence.workspaceManager.storageContainerUrl=https://${params.landingZoneResources.storageAccountName.value}.blob.core.windows.net/${storageContainer.name.value}", + raw"persistence.workspaceManager.storageContainerUrl=https://${params.landingZoneResources.storageAccountName.value}.blob${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getStorageEndpointSuffix}/${storageContainer.name.value}", raw"persistence.leoAppName=${params.app.appName.value}", // identity configs diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/WdsAppInstall.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/WdsAppInstall.scala index d8a1c71e3a0..c7ddb183cdb 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/WdsAppInstall.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/WdsAppInstall.scala @@ -7,7 +7,8 @@ import cats.mtl.Ask import cats.syntax.all._ import org.broadinstitute.dsde.workbench.azure.AzureApplicationInsightsService import org.broadinstitute.dsde.workbench.leonardo.app.Database.ControlledDatabase -import org.broadinstitute.dsde.workbench.leonardo.config.WdsAppConfig +import org.broadinstitute.dsde.workbench.leonardo.auth.SamAuthProvider +import org.broadinstitute.dsde.workbench.leonardo.config.{AzureEnvironmentConverter, WdsAppConfig} import org.broadinstitute.dsde.workbench.leonardo.dao._ import org.broadinstitute.dsde.workbench.leonardo.http._ import org.broadinstitute.dsde.workbench.leonardo.util.AppCreationException @@ -23,7 +24,8 @@ class WdsAppInstall[F[_]](config: WdsAppConfig, tdrConfig: TdrConfig, samDao: SamDAO[F], wdsDao: WdsDAO[F], - azureApplicationInsightsService: AzureApplicationInsightsService[F] + azureApplicationInsightsService: AzureApplicationInsightsService[F], + authProvider: SamAuthProvider[F] )(implicit F: Async[F] ) extends AppInstall[F] { @@ -54,15 +56,22 @@ class WdsAppInstall[F[_]](config: WdsAppConfig, ) // Get the pet userToken - tokenOpt <- samDao.getCachedArbitraryPetAccessToken(params.app.auditInfo.creator) - userToken <- F.fromOption( - tokenOpt, - AppCreationException(s"Pet not found for user ${params.app.auditInfo.creator}", Some(ctx.traceId)) - ) // Get Vpa enabled tag vpaEnabled <- F.pure(params.landingZoneResources.aksCluster.tags.getOrElse("aks-cost-vpa-enabled", false)) + // Get the pet userToken + tokenOpt <- samDao.getCachedArbitraryPetAccessToken(params.app.auditInfo.creator) + userToken <- ConfigReader.appConfig.azure.hostingModeConfig.enabled match { + case false => + F.fromOption( + tokenOpt, + AppCreationException(s"Pet not found for user ${params.app.auditInfo.creator}", Some(ctx.traceId)) + ) + case true => + F.pure("") // No pet user token in Azure. + } + valuesList = List( // pass enviiroment information to wds so it can properly pick its config @@ -96,7 +105,8 @@ class WdsAppInstall[F[_]](config: WdsAppConfig, raw"provenance.sourceWorkspaceId=${params.app.sourceWorkspaceId.map(_.value).getOrElse("")}", // database configs - raw"postgres.host=${postgresServer.name}.postgres.database.azure.com", + raw"postgres.host=${postgresServer.name}.postgres${AzureEnvironmentConverter + .postgresSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}", raw"postgres.pgbouncer.enabled=${postgresServer.pgBouncerEnabled}", raw"postgres.dbname=$dbName", // convention is that the database user is the same as the service account name diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/WorkflowsAppInstall.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/WorkflowsAppInstall.scala index 634ad37badf..abaf0cf8973 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/WorkflowsAppInstall.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/app/WorkflowsAppInstall.scala @@ -8,7 +8,7 @@ import org.broadinstitute.dsde.workbench.azure.{AzureApplicationInsightsService, import org.broadinstitute.dsde.workbench.leonardo.{AppContext, WsmControlledDatabaseResource} import org.broadinstitute.dsde.workbench.leonardo.app.AppInstall.getAzureDatabaseName import org.broadinstitute.dsde.workbench.leonardo.app.Database.ControlledDatabase -import org.broadinstitute.dsde.workbench.leonardo.config.WorkflowsAppConfig +import org.broadinstitute.dsde.workbench.leonardo.config.{AzureEnvironmentConverter, WorkflowsAppConfig} import org.broadinstitute.dsde.workbench.leonardo.dao._ import org.broadinstitute.dsde.workbench.leonardo.http._ import org.broadinstitute.dsde.workbench.leonardo.util.AppCreationException @@ -69,10 +69,15 @@ class WorkflowsAppInstall[F[_]](config: WorkflowsAppConfig, // Get the pet userToken tokenOpt <- samDao.getCachedArbitraryPetAccessToken(params.app.auditInfo.creator) - userToken <- F.fromOption( - tokenOpt, - AppCreationException(s"Pet not found for user ${params.app.auditInfo.creator}", Some(ctx.traceId)) - ) + userToken <- ConfigReader.appConfig.azure.hostingModeConfig.enabled match { + case false => + F.fromOption( + tokenOpt, + AppCreationException(s"Pet not found for user ${params.app.auditInfo.creator}", Some(ctx.traceId)) + ) + case true => + F.pure("") // No pet user token in Azure. + } values = List( @@ -111,7 +116,8 @@ class WorkflowsAppInstall[F[_]](config: WorkflowsAppConfig, // database configs raw"postgres.podLocalDatabaseEnabled=false", - raw"postgres.host=${postgresServer.name}.postgres.database.azure.com", + raw"postgres.host=${postgresServer.name}.postgres${AzureEnvironmentConverter + .postgresSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}", raw"postgres.pgbouncer.enabled=${postgresServer.pgBouncerEnabled}", // convention is that the database user is the same as the service account name raw"postgres.user=${params.ksaName.value}", diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/config/AzureHostingModeConfig.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/config/AzureHostingModeConfig.scala index 8d7bc4b6b1f..e4a50812d9b 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/config/AzureHostingModeConfig.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/config/AzureHostingModeConfig.scala @@ -17,15 +17,46 @@ case class AzureManagedIdentityAuthConfig( ) object AzureEnvironmentConverter { - val Azure: String = "AZURE" - val AzureGov: String = "AZURE_US_GOVERNMENT" - val AzureChina: String = "AZURE_CHINA" + val Azure: String = "AzureCloud" + val AzureGov: String = "AzureUSGovernmentCloud" def fromString(s: String): AzureEnvironment = s match { - case AzureGov => AzureEnvironment.AZURE_US_GOVERNMENT - case AzureChina => AzureEnvironment.AZURE_CHINA + case AzureGov => AzureEnvironment.AZURE_US_GOVERNMENT // a bit redundant, but I want to have a explicit case for Azure for clarity, even though it's the default case Azure => AzureEnvironment.AZURE case _ => AzureEnvironment.AZURE } + + // servicebus suffix not currently provided by AzureEnvironment library, values found here + def relaySuffixFromEnvironment(azureEnvironment: AzureEnvironment): String = azureEnvironment match { + case AzureEnvironment.AZURE_US_GOVERNMENT => ".servicebus.usgovcloudapi.net" + // a bit redundant, but I want to have a explicit case for Azure for clarity, even though it's the default + case AzureEnvironment.AZURE => ".servicebus.windows.net" + case _ => ".servicebus.windows.net" + } + + def relaySuffixFromString(s: String): String = + relaySuffixFromEnvironment(fromString(s)) + + // database suffix not currently provided by AzureEnvironment library, values found here + def postgresSuffixFromEnvironment(azureEnvironment: AzureEnvironment): String = azureEnvironment match { + case AzureEnvironment.AZURE_US_GOVERNMENT => ".database.usgovcloudapi.net" + // a bit redundant, but I want to have a explicit case for Azure for clarity, even though it's the default + case AzureEnvironment.AZURE => ".database.azure.com" + case _ => ".database.azure.com" + } + + def postgresSuffixFromString(s: String): String = + postgresSuffixFromEnvironment(fromString(s)) + + // batchAccount suffix not currently provided by AzureEnvironment library, values found here + def batchAccountSuffixFromEnvironment(azureEnvironment: AzureEnvironment): String = azureEnvironment match { + case AzureEnvironment.AZURE_US_GOVERNMENT => ".batch.usgovcloudapi.net" + // a bit redundant, but I want to have a explicit case for Azure for clarity, even though it's the default + case AzureEnvironment.AZURE => ".batch.azure.com" + case _ => ".batch.azure.com" + } + + def batchAccountSuffixFromString(s: String): String = + batchAccountSuffixFromEnvironment(fromString(s)) } diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/http/AppDependenciesBuilder.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/http/AppDependenciesBuilder.scala index e2f908a0a0f..e8bbbe6fb65 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/http/AppDependenciesBuilder.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/http/AppDependenciesBuilder.scala @@ -189,7 +189,8 @@ class AppDependenciesBuilder(baselineDependenciesBuilder: BaselineDependenciesBu baselineDependencies.cromwellDAO, baselineDependencies.cbasDAO, baselineDependencies.azureBatchService, - baselineDependencies.azureApplicationInsightsService + baselineDependencies.azureApplicationInsightsService, + baselineDependencies.authProvider ) val cromwellRunnerAppInstall = @@ -211,7 +212,8 @@ class AppDependenciesBuilder(baselineDependenciesBuilder: BaselineDependenciesBu ConfigReader.appConfig.azure.tdr, baselineDependencies.samDAO, baselineDependencies.wdsDAO, - baselineDependencies.azureApplicationInsightsService + baselineDependencies.azureApplicationInsightsService, + baselineDependencies.authProvider ) val workflowsAppInstall = new WorkflowsAppInstall[IO]( diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/http/service/LeoAppServiceInterp.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/http/service/LeoAppServiceInterp.scala index 7d64ef2810b..a40d3b5d054 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/http/service/LeoAppServiceInterp.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/http/service/LeoAppServiceInterp.scala @@ -163,12 +163,15 @@ final class LeoAppServiceInterp[F[_]: Parallel](config: AppServiceConfig, // Retrieve parent workspaceId for the google project parentWorkspaceId <- samService.lookupWorkspaceParentForGoogleProject(userInfo.accessToken.token, googleProject) + // Leo email used to give permissions when running in Azure. + leoToken <- authProvider.getLeoAuthToken + leoEmail <- samService.getUserEmail(leoToken) notifySamAndCreate = for { _ <- samService.createResource(userInfo.accessToken.token, samResourceId, Some(googleProject), None, - getAppSamPolicyMap(userEmail, req.accessScope) + getAppSamPolicyMap(userEmail, leoEmail, req.accessScope) ) saveCluster <- F.fromEither( getSavableCluster(userEmail, cloudContext, req.autopilot.isDefined, ctx.now) @@ -783,11 +786,13 @@ final class LeoAppServiceInterp[F[_]: Parallel](config: AppServiceConfig, samResourceId <- F.delay(AppSamResourceId(UUID.randomUUID().toString, req.accessScope)) // Create kubernetes-app Sam resource with a creator policy and the workspace as the parent + leoToken <- authProvider.getLeoAuthToken + leoEmail <- samService.getUserEmail(leoToken) _ <- samService.createResource(userInfo.accessToken.token, samResourceId, None, Some(workspaceId), - getAppSamPolicyMap(userEmail, req.accessScope) + getAppSamPolicyMap(userEmail, leoEmail, req.accessScope) ) // Save or retrieve a KubernetesCluster record for the app @@ -1692,13 +1697,14 @@ object LeoAppServiceInterp { * Private apps are represented as kubernetes-app resources in Sam and have a "creator" role. */ private[http] def getAppSamPolicyMap(userEmail: WorkbenchEmail, + leoEmail: WorkbenchEmail, accessScope: Option[AppAccessScope] ): Map[String, SamPolicyData] = accessScope match { case Some(AppAccessScope.WorkspaceShared) => - Map("owner" -> SamPolicyData(List(userEmail), List(SharedAppRole.Owner.asString))) + Map("owner" -> SamPolicyData(List(userEmail, leoEmail), List(SharedAppRole.Owner.asString))) case _ => - Map("creator" -> SamPolicyData(List(userEmail), List(AppRole.Creator.asString))) + Map("creator" -> SamPolicyData(List(userEmail, leoEmail), List(AppRole.Creator.asString))) } } diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/monitor/LeoMetricsMonitor.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/monitor/LeoMetricsMonitor.scala index 08bc4e48877..d98e069d309 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/monitor/LeoMetricsMonitor.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/monitor/LeoMetricsMonitor.scala @@ -167,11 +167,22 @@ class LeoMetricsMonitor[F[_]](config: LeoMetricsMonitorConfig, appDAO.isProxyAvailable(project, app.appName, serviceName, ctx.traceId) case CloudContext.Azure(_) => for { - tokenOpt <- samDAO.getCachedArbitraryPetAccessToken(app.auditInfo.creator) - token <- F.fromOption( - tokenOpt, - AppCreationException(s"Pet not found for user ${app.auditInfo.creator}", Some(ctx.traceId)) - ) + token <- ConfigReader.appConfig.azure.hostingModeConfig.enabled match { + case false => + for { + tokenOpt <- samDAO.getCachedArbitraryPetAccessToken(app.auditInfo.creator) + token <- F.fromOption( + tokenOpt, + AppCreationException(s"Pet not found for user ${app.auditInfo.creator}", Some(ctx.traceId)) + ) + } yield token + case true => + for { + leoAuth <- samDAO.getLeoAuthToken + token = leoAuth.credentials.toString().split(" ")(1) + } yield token + } + authHeader = Authorization(Credentials.Token(AuthScheme.Bearer, token)) relayPath = Uri .unsafeFromString(baseUri.asString) / s"${app.appName.value}-${app.workspaceId.map(_.value.toString).getOrElse("")}" diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/monitor/MonitorAtBoot.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/monitor/MonitorAtBoot.scala index 10162ad575b..91f20b03a16 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/monitor/MonitorAtBoot.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/monitor/MonitorAtBoot.scala @@ -222,10 +222,11 @@ class MonitorAtBoot[F[_]](publisherQueue: Queue[F, LeoPubsubMessage], appContext.traceId ) ) - tokenOpt <- samDAO.getCachedArbitraryPetAccessToken(app.auditInfo.creator) - workspaceDescOpt <- tokenOpt.flatTraverse { token => - wsmClientProvider.getWorkspace(token, workspaceId) - } + token <- getAuthToken(app.auditInfo.creator) + workspaceDescOpt <- wsmClientProvider.getWorkspace( + token, + workspaceId + ) workspaceDesc <- F.fromOption(workspaceDescOpt, WorkspaceNotFoundException(workspaceId, appContext.traceId) ) @@ -264,10 +265,11 @@ class MonitorAtBoot[F[_]](publisherQueue: Queue[F, LeoPubsubMessage], appContext.traceId ) ) - tokenOpt <- samDAO.getCachedArbitraryPetAccessToken(app.auditInfo.creator) - workspaceDescOpt <- tokenOpt.flatTraverse { token => - wsmClientProvider.getWorkspace(token, workspaceId) - } + token <- getAuthToken(app.auditInfo.creator) + workspaceDescOpt <- wsmClientProvider.getWorkspace( + token, + workspaceId + ) workspaceDesc <- F.fromOption(workspaceDescOpt, WorkspaceNotFoundException(workspaceId, appContext.traceId) ) @@ -375,9 +377,7 @@ class MonitorAtBoot[F[_]](publisherQueue: Queue[F, LeoPubsubMessage], case x => F.raiseError(MonitorAtBootException(s"Unexpected status for runtime ${runtime.id}: ${x}", traceId)) } - private def runtimeStatusToMessageAzure(runtime: RuntimeToMonitor, traceId: TraceId)(implicit - ev: Ask[F, TraceId] - ): F[LeoPubsubMessage] = + private def runtimeStatusToMessageAzure(runtime: RuntimeToMonitor, traceId: TraceId): F[LeoPubsubMessage] = runtime.status match { case RuntimeStatus.Stopping => F.pure( @@ -394,10 +394,11 @@ class MonitorAtBoot[F[_]](publisherQueue: Queue[F, LeoPubsubMessage], MonitorAtBootException(s"no workspaceId found for ${runtime.id.toString}", traceId) ) controlledResourceOpt = WsmControlledResourceId(UUID.fromString(runtime.internalId)) - tokenOpt <- samDAO.getCachedArbitraryPetAccessToken(runtime.auditInfo.creator) - workspaceDescOpt <- tokenOpt.flatTraverse { token => - wsmClientProvider.getWorkspace(token, wid) - } + leoAuth <- samDAO.getLeoAuthToken + workspaceDescOpt <- wsmClientProvider.getWorkspace( + leoAuth.credentials.renderString, + wid + ) workspaceDesc <- F.fromOption(workspaceDescOpt, WorkspaceNotFoundException(wid, traceId)) } yield LeoPubsubMessage.DeleteAzureRuntimeMessage( runtimeId = runtime.id, @@ -422,10 +423,13 @@ class MonitorAtBoot[F[_]](publisherQueue: Queue[F, LeoPubsubMessage], wid <- F.fromOption(runtime.workspaceId, MonitorAtBootException(s"no workspaceId found for ${runtime.id.toString}", traceId) ) - tokenOpt <- samDAO.getCachedArbitraryPetAccessToken(runtime.auditInfo.creator) - workspaceDescOpt <- tokenOpt.flatTraverse { token => - wsmClientProvider.getWorkspace(token, wid) - } + leoAuth <- samDAO.getLeoAuthToken + token = leoAuth.credentials.toString().split(" ")(1) + workspaceDescOpt <- wsmClientProvider.getWorkspace( + token, + wid + ) + workspaceDesc <- F.fromOption(workspaceDescOpt, WorkspaceNotFoundException(wid, traceId)) } yield LeoPubsubMessage.CreateAzureRuntimeMessage( runtime.id, @@ -437,6 +441,26 @@ class MonitorAtBoot[F[_]](publisherQueue: Queue[F, LeoPubsubMessage], ) case x => F.raiseError(MonitorAtBootException(s"Unexpected status for runtime ${runtime.id}: ${x}", traceId)) } + + private def getAuthToken(creator: WorkbenchEmail)(implicit + ev: Ask[F, TraceId] + ): F[String] = + ConfigReader.appConfig.azure.hostingModeConfig.enabled match { + case false => + for { + traceId <- ev.ask + tokenOpt <- samDAO.getCachedArbitraryPetAccessToken(creator) + token <- F.fromOption( + tokenOpt, + MonitorAtBootException(s"Pet not found for user ${creator}", traceId) + ) + } yield token + case true => + for { + leoAuth <- samDAO.getLeoAuthToken + token = leoAuth.credentials.toString().split(" ")(1) + } yield token + } } final case class RuntimeToMonitor( diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/AKSInterpreter.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/AKSInterpreter.scala index e027d1c0eab..3313aebec29 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/AKSInterpreter.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/AKSInterpreter.scala @@ -28,8 +28,7 @@ import org.broadinstitute.dsde.workbench.leonardo.http._ import org.broadinstitute.dsde.workbench.leonardo.http.service.AppNotFoundException import org.broadinstitute.dsde.workbench.model.{IP, WorkbenchEmail} import org.broadinstitute.dsp._ -import org.http4s.headers.Authorization -import org.http4s.{AuthScheme, Credentials, Uri} +import org.http4s.Uri import org.typelevel.log4cats.StructuredLogger import java.net.URL @@ -110,14 +109,11 @@ class AKSInterpreter[F[_]](config: AKSInterpreterConfig, } // Get the optional storage container for the workspace - tokenOpt <- samDao.getCachedArbitraryPetAccessToken(app.auditInfo.creator) storageContainerOpt <- childSpan("getWorkspaceStorageContainer").use { implicit ev => - tokenOpt.flatTraverse { token => - wsmDao.getWorkspaceStorageContainer( - params.workspaceId, - org.http4s.headers.Authorization(org.http4s.Credentials.Token(AuthScheme.Bearer, token)) - ) - } + wsmDao.getWorkspaceStorageContainer( + params.workspaceId, + leoAuth + ) } wsmResourceApi <- buildWsmResourceApiClient @@ -187,7 +183,7 @@ class AKSInterpreter[F[_]](config: AKSInterpreterConfig, relayPrimaryKey <- childSpan("createRelayHybridConnection").use { implicit ev => azureRelayService.createRelayHybridConnection(landingZoneResources.relayNamespace, hcName, params.cloudContext) } - relayDomain = s"${landingZoneResources.relayNamespace.value}.servicebus.windows.net" + relayDomain = s"${landingZoneResources.relayNamespace.value}${AzureEnvironmentConverter.relaySuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}" relayEndpoint = s"https://${relayDomain}/" relayPath = Uri.unsafeFromString(relayEndpoint) / hcName.value @@ -421,7 +417,7 @@ class AKSInterpreter[F[_]](config: AKSInterpreterConfig, // Get relay hybrid connection information hcName = RelayHybridConnectionName(s"${params.appName.value}-${workspaceId.value}") - relayDomain = s"${landingZoneResources.relayNamespace.value}.servicebus.windows.net" + relayDomain = s"${landingZoneResources.relayNamespace.value}${AzureEnvironmentConverter.relaySuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}" relayEndpoint = s"https://${relayDomain}/" relayPath = Uri.unsafeFromString(relayEndpoint) / hcName.value relayPrimaryKey <- azureRelayService.getRelayHybridConnectionKey(landingZoneResources.relayNamespace, @@ -543,6 +539,7 @@ class AKSInterpreter[F[_]](config: AKSInterpreterConfig, // Query the Landing Zone service for the landing zone resources leoAuth <- samDao.getLeoAuthToken + token = leoAuth.credentials.toString().split(" ")(1) landingZoneResources <- childSpan("getLandingZoneResources").use { implicit ev => legacyWsmDao.getLandingZoneResources(billingProfileId, leoAuth) } @@ -632,11 +629,9 @@ class AKSInterpreter[F[_]](config: AKSInterpreterConfig, } } - // Delete the Sam resource - userEmail = app.auditInfo.creator - petToken <- samService.getArbitraryPetServiceAccountToken(userEmail) + // Delete the Sam resource getCachedArbitraryPetAccessToken _ <- childSpan("deleteSamResource").use { implicit ev => - samService.deleteResource(petToken, dbApp.app.samResourceId) + samService.deleteResource(token, dbApp.app.samResourceId) } _ <- logger.info( @@ -652,10 +647,7 @@ class AKSInterpreter[F[_]](config: AKSInterpreterConfig, private[util] def pollApp(userEmail: WorkbenchEmail, relayBaseUri: Uri, appInstall: AppInstall[F])(implicit ev: Ask[F, AppContext] ): F[Boolean] = for { - ctx <- ev.ask - tokenOpt <- samDao.getCachedArbitraryPetAccessToken(userEmail) - token <- F.fromOption(tokenOpt, AppCreationException(s"Pet not found for user ${userEmail}", Some(ctx.traceId))) - authHeader = Authorization(Credentials.Token(AuthScheme.Bearer, token)) + authHeader <- samDao.getLeoAuthToken res <- appInstall.checkStatus(relayBaseUri, authHeader) } yield res diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/AzurePubsubHandler.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/AzurePubsubHandler.scala index 323e410009c..026971cbbc8 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/AzurePubsubHandler.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/AzurePubsubHandler.scala @@ -51,7 +51,6 @@ import org.broadinstitute.dsde.workbench.leonardo.monitor.PubsubHandleMessageErr import org.broadinstitute.dsde.workbench.model.{IP, WorkbenchEmail} import org.broadinstitute.dsde.workbench.util2.InstanceName import org.broadinstitute.dsp.ChartVersion -import org.http4s.AuthScheme import org.typelevel.log4cats.StructuredLogger import reactor.core.publisher.Mono @@ -136,13 +135,11 @@ class AzurePubsubHandlerInterp[F[_]: Parallel]( s"[AzurePubsubHandler/createAndPollRuntime] getting workspace storage container from WSM for runtime ${msg.runtimeId}" ) // Get the optional storage container for the workspace - tokenOpt <- samDAO.getCachedArbitraryPetAccessToken(runtime.auditInfo.creator) - workspaceStorageContainerOpt <- tokenOpt.flatTraverse { token => - wsmDao.getWorkspaceStorageContainer( - msg.workspaceId, - org.http4s.headers.Authorization(org.http4s.Credentials.Token(AuthScheme.Bearer, token)) - ) - } + workspaceStorageContainerOpt <- wsmDao.getWorkspaceStorageContainer( + msg.workspaceId, + leoAuth + ) + workspaceStorageContainer <- F.fromOption( workspaceStorageContainerOpt, AzureRuntimeCreationError( @@ -160,14 +157,11 @@ class AzurePubsubHandlerInterp[F[_]: Parallel]( // Get optional action managed identity from Sam for the private_azure_storage_account/read action. // Identities must be passed to WSM for application-managed resources. - tokenOpt <- samDAO.getCachedArbitraryPetAccessToken(runtime.auditInfo.creator) - actionIdentityOpt <- tokenOpt.flatTraverse { token => - samDAO.getAzureActionManagedIdentity( - org.http4s.headers.Authorization(org.http4s.Credentials.Token(AuthScheme.Bearer, token)), - PrivateAzureStorageAccountSamResourceId(msg.billingProfileId.value), - PrivateAzureStorageAccountAction.Read - ) - } + actionIdentityOpt <- samDAO.getAzureActionManagedIdentity( + leoAuth, + PrivateAzureStorageAccountSamResourceId(msg.billingProfileId.value), + PrivateAzureStorageAccountAction.Read + ) _ <- logger.info( s"[AzurePubsubHandler/createAndPollRuntime] beginning to monitor runtime creation for runtime ${msg.runtimeId}" @@ -234,7 +228,8 @@ class AzurePubsubHandlerInterp[F[_]: Parallel]( wsStorageContainerUrl, applicationConfig.leoUrlBase, params.runtime.runtimeName.asString, - s"'${refererConfig.validHosts.mkString("','")}'" + s"'${refererConfig.validHosts.mkString("','")}'", + AzureEnvironmentConverter.relaySuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) ) val cmdToExecute = s"touch /var/log/azure_vm_init_script.log && chmod 400 /var/log/azure_vm_init_script.log &&" + @@ -898,7 +893,8 @@ class AzurePubsubHandlerInterp[F[_]: Parallel]( ) ) case JobReport.StatusEnum.SUCCEEDED => - val hostIp = s"${params.landingZoneResources.relayNamespace.value}.servicebus.windows.net" + val hostIp = s"${params.landingZoneResources.relayNamespace.value}${AzureEnvironmentConverter + .relaySuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}" for { now <- nowInstant _ <- clusterQuery.updateClusterHostIp(params.runtime.id, Some(IP(hostIp)), now).transaction diff --git a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/BuildHelmChartValues.scala b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/BuildHelmChartValues.scala index ab11f42ccb9..25ad63b9cdb 100644 --- a/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/BuildHelmChartValues.scala +++ b/http/src/main/scala/org/broadinstitute/dsde/workbench/leonardo/util/BuildHelmChartValues.scala @@ -8,9 +8,9 @@ import org.broadinstitute.dsde.workbench.google2.GKEModels.NodepoolName import org.broadinstitute.dsde.workbench.google2.KubernetesSerializableName.{NamespaceName, ServiceAccountName} import org.broadinstitute.dsde.workbench.leonardo.AppRestore.GalaxyRestore import org.broadinstitute.dsde.workbench.leonardo.SamResourceId.AppSamResourceId -import org.broadinstitute.dsde.workbench.leonardo.config.SamConfig +import org.broadinstitute.dsde.workbench.leonardo.config.{AzureEnvironmentConverter, SamConfig} import org.broadinstitute.dsde.workbench.leonardo.dao.CustomAppService -import org.broadinstitute.dsde.workbench.leonardo.http.kubernetesProxyHost +import org.broadinstitute.dsde.workbench.leonardo.http.{kubernetesProxyHost, ConfigReader} import org.broadinstitute.dsde.workbench.model.WorkbenchEmail import org.broadinstitute.dsde.workbench.model.google.GcsBucketName import org.broadinstitute.dsp.{Release, Values} @@ -275,9 +275,12 @@ private[leonardo] object BuildHelmChartValues { Values( List( raw"""connection.removeEntityPathFromHttpUrl="${removeEntityPathFromHttpUrl.toString}"""", - raw"connection.connectionString=Endpoint=sb://${relayNamespace.value}.servicebus.windows.net/;SharedAccessKeyName=listener;SharedAccessKey=${relayPrimaryKey.value};EntityPath=${relayHcName.value}", + raw"connection.connectionString=Endpoint=sb://${relayNamespace.value}${AzureEnvironmentConverter.relaySuffixFromString( + ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment + )}/;SharedAccessKeyName=listener;SharedAccessKey=${relayPrimaryKey.value};EntityPath=${relayHcName.value}", raw"connection.connectionName=${relayHcName.value}", - raw"connection.endpoint=https://${relayNamespace.value}.servicebus.windows.net", + raw"connection.endpoint=https://${relayNamespace.value}${AzureEnvironmentConverter + .relaySuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}", raw"connection.targetHost=$relayTargetHost", raw"sam.url=${samConfig.server}", raw"sam.resourceId=${samResourceId.resourceId}", diff --git a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellAppInstallSpec.scala b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellAppInstallSpec.scala index 867d708cd9c..12be250fe1f 100644 --- a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellAppInstallSpec.scala +++ b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellAppInstallSpec.scala @@ -10,6 +10,7 @@ import org.broadinstitute.dsde.workbench.leonardo.CommonTestData.{ } import org.broadinstitute.dsde.workbench.leonardo.{ManagedIdentityName, PostgresServer, WsmControlledDatabaseResource} import org.broadinstitute.dsde.workbench.leonardo.TestUtils.appContext +import org.broadinstitute.dsde.workbench.leonardo.config.AzureEnvironmentConverter import org.broadinstitute.dsde.workbench.leonardo.http.ConfigReader import org.broadinstitute.dsde.workbench.leonardo.util.AppCreationException import org.http4s.Uri @@ -23,7 +24,8 @@ class CromwellAppInstallSpec extends BaseAppInstallSpec { mockCromwellDAO, mockCbasDAO, mockAzureBatchService, - mockAzureApplicationInsightsService + mockAzureApplicationInsightsService, + mockSamAuthProvider ) val cromwellAzureDbName = "cromwell_tghfgi" @@ -49,9 +51,18 @@ class CromwellAppInstallSpec extends BaseAppInstallSpec { "config.subscriptionId=sub," + s"config.region=${azureRegion}," + "config.applicationInsightsConnectionString=applicationInsightsConnectionString," + + s"config.azureEnvironment=${ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment}," + + s"config.azureManagementTokenScope=${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getResourceManagerEndpoint}.default," + + s"config.batchAccountSuffix=${AzureEnvironmentConverter + .batchAccountSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}," + "relay.path=https://relay.com/app," + "persistence.storageResourceGroup=mrg," + "persistence.storageAccount=storage," + + s"persistence.storageAccountSuffix=${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getStorageEndpointSuffix}," + "persistence.blobContainer=sc-container," + "persistence.leoAppInstanceName=app1," + s"persistence.workspaceManager.url=${ConfigReader.appConfig.azure.wsm.uri.renderString}," + @@ -70,7 +81,8 @@ class CromwellAppInstallSpec extends BaseAppInstallSpec { "instrumentationEnabled=false," + s"provenance.userAccessToken=${petUserInfo.accessToken.token}," + "postgres.podLocalDatabaseEnabled=false," + - s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres.database.azure.com," + + s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres${AzureEnvironmentConverter + .postgresSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}," + "postgres.pgbouncer.enabled=true," + "postgres.user=ksa-1," + s"postgres.dbnames.cromwell=$cromwellAzureDbName," + @@ -105,9 +117,18 @@ class CromwellAppInstallSpec extends BaseAppInstallSpec { "config.subscriptionId=sub," + s"config.region=${azureRegion}," + "config.applicationInsightsConnectionString=applicationInsightsConnectionString," + + s"config.azureEnvironment=${ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment}," + + s"config.azureManagementTokenScope=${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getResourceManagerEndpoint}.default," + + s"config.batchAccountSuffix=${AzureEnvironmentConverter + .batchAccountSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}," + "relay.path=https://relay.com/app," + "persistence.storageResourceGroup=mrg," + "persistence.storageAccount=storage," + + s"persistence.storageAccountSuffix=${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getStorageEndpointSuffix}," + "persistence.blobContainer=sc-container," + "persistence.leoAppInstanceName=app1," + s"persistence.workspaceManager.url=${ConfigReader.appConfig.azure.wsm.uri.renderString}," + @@ -126,7 +147,8 @@ class CromwellAppInstallSpec extends BaseAppInstallSpec { "instrumentationEnabled=false," + s"provenance.userAccessToken=${petUserInfo.accessToken.token}," + "postgres.podLocalDatabaseEnabled=false," + - s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres.database.azure.com," + + s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres${AzureEnvironmentConverter + .postgresSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}," + "postgres.pgbouncer.enabled=false," + "postgres.user=ksa-1," + s"postgres.dbnames.cromwell=$cromwellAzureDbName," + diff --git a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellRunnerAppInstallSpec.scala b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellRunnerAppInstallSpec.scala index 85925b83d83..59df8bffd11 100644 --- a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellRunnerAppInstallSpec.scala +++ b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/CromwellRunnerAppInstallSpec.scala @@ -4,6 +4,7 @@ import cats.effect.IO import org.broadinstitute.dsde.workbench.leonardo.CommonTestData.{azureRegion, landingZoneResources, petUserInfo} import org.broadinstitute.dsde.workbench.leonardo.http.ConfigReader import org.broadinstitute.dsde.workbench.leonardo.TestUtils.appContext +import org.broadinstitute.dsde.workbench.leonardo.config.AzureEnvironmentConverter import org.broadinstitute.dsde.workbench.leonardo.{BillingProfileId, WsmControlledDatabaseResource} import org.broadinstitute.dsde.workbench.leonardo.config.Config.samConfig import org.broadinstitute.dsde.workbench.leonardo.util.AppCreationException @@ -42,8 +43,17 @@ class CromwellRunnerAppInstallSpec extends BaseAppInstallSpec { "config.subscriptionId=sub," + s"config.region=${azureRegion}," + "config.applicationInsightsConnectionString=applicationInsightsConnectionString," + + s"config.azureEnvironment=${ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment}," + + s"config.azureManagementTokenScope=${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getResourceManagerEndpoint}.default," + + s"config.batchAccountSuffix=${AzureEnvironmentConverter + .batchAccountSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}," + "relay.path=https://relay.com/app," + "persistence.storageAccount=storage," + + s"persistence.storageAccountSuffix=${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getStorageEndpointSuffix}," + "persistence.blobContainer=sc-container," + "persistence.leoAppInstanceName=app1," + s"persistence.workspaceManager.url=${ConfigReader.appConfig.azure.wsm.uri.renderString}," + @@ -56,7 +66,8 @@ class CromwellRunnerAppInstallSpec extends BaseAppInstallSpec { "instrumentationEnabled=false," + s"provenance.userAccessToken=${petUserInfo.accessToken.token}," + "postgres.podLocalDatabaseEnabled=false," + - s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres.database.azure.com," + + s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres${AzureEnvironmentConverter + .postgresSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}," + "postgres.pgbouncer.enabled=true," + "postgres.user=ksa-1," + s"postgres.dbnames.cromwell=$cromwellAzureDbName," + diff --git a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/HailBatchAppInstallSpec.scala b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/HailBatchAppInstallSpec.scala index df91a85f2fc..e0b0dd34c14 100644 --- a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/HailBatchAppInstallSpec.scala +++ b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/HailBatchAppInstallSpec.scala @@ -2,6 +2,7 @@ package org.broadinstitute.dsde.workbench.leonardo.app import cats.effect.IO import org.broadinstitute.dsde.workbench.leonardo.TestUtils.appContext +import org.broadinstitute.dsde.workbench.leonardo.config.AzureEnvironmentConverter import org.broadinstitute.dsde.workbench.leonardo.dao.HailBatchDAO import org.broadinstitute.dsde.workbench.leonardo.http.ConfigReader import org.mockito.ArgumentMatchers.any @@ -26,7 +27,9 @@ class HailBatchAppInstallSpec extends BaseAppInstallSpec { s"persistence.workspaceManager.url=${ConfigReader.appConfig.azure.wsm.uri.renderString}," + s"persistence.workspaceManager.workspaceId=${workspaceId.value}," + s"persistence.workspaceManager.containerResourceId=${storageContainer.resourceId.value.toString}," + - s"persistence.workspaceManager.storageContainerUrl=https://${lzResources.storageAccountName.value}.blob.core.windows.net/${storageContainer.name.value}," + + s"persistence.workspaceManager.storageContainerUrl=https://${lzResources.storageAccountName.value}.blob${AzureEnvironmentConverter + .fromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment) + .getStorageEndpointSuffix}/${storageContainer.name.value}," + "persistence.leoAppName=app1," + "workloadIdentity.serviceAccountName=ksa-1," + s"relay.domain=relay.com," + diff --git a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/WdsAppInstallSpec.scala b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/WdsAppInstallSpec.scala index 8905af7a2b5..990995c8ac3 100644 --- a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/WdsAppInstallSpec.scala +++ b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/WdsAppInstallSpec.scala @@ -3,6 +3,7 @@ package org.broadinstitute.dsde.workbench.leonardo.app import cats.effect.IO import org.broadinstitute.dsde.workbench.leonardo.CommonTestData.{azureRegion, landingZoneResources, petUserInfo} import org.broadinstitute.dsde.workbench.leonardo.TestUtils.appContext +import org.broadinstitute.dsde.workbench.leonardo.config.AzureEnvironmentConverter import org.broadinstitute.dsde.workbench.leonardo.{WorkspaceId, WsmControlledDatabaseResource} import org.broadinstitute.dsde.workbench.leonardo.dao.WdsDAO import org.broadinstitute.dsde.workbench.leonardo.http.ConfigReader @@ -20,7 +21,8 @@ class WdsAppInstallSpec extends BaseAppInstallSpec { ConfigReader.appConfig.azure.tdr, mockSamDAO, mockWdsDAO, - mockAzureApplicationInsightsService + mockAzureApplicationInsightsService, + mockSamAuthProvider ) val wdsAzureDbName = "wds_rtyjga" @@ -50,7 +52,8 @@ class WdsAppInstallSpec extends BaseAppInstallSpec { "instrumentationEnabled=false," + s"provenance.userAccessToken=${petUserInfo.accessToken.token}," + "provenance.sourceWorkspaceId=," + - s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres.database.azure.com," + + s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres${AzureEnvironmentConverter + .postgresSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}," + "postgres.pgbouncer.enabled=true," + s"postgres.dbname=$wdsAzureDbName," + "postgres.user=ksa-1" @@ -81,7 +84,8 @@ class WdsAppInstallSpec extends BaseAppInstallSpec { "instrumentationEnabled=false," + s"provenance.userAccessToken=${petUserInfo.accessToken.token}," + s"provenance.sourceWorkspaceId=${sourceWorkspaceId.value}," + - s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres.database.azure.com," + + s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres${AzureEnvironmentConverter + .postgresSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}," + "postgres.pgbouncer.enabled=true," + s"postgres.dbname=$wdsAzureDbName," + "postgres.user=ksa-1" diff --git a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/WorkflowsAppInstallSpec.scala b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/WorkflowsAppInstallSpec.scala index 84ff8d58be6..20cc7a1c46a 100644 --- a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/WorkflowsAppInstallSpec.scala +++ b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/app/WorkflowsAppInstallSpec.scala @@ -4,6 +4,7 @@ import cats.effect.IO import org.broadinstitute.dsde.workbench.leonardo.CommonTestData.{landingZoneResources, petUserInfo} import org.broadinstitute.dsde.workbench.leonardo.TestUtils.appContext import org.broadinstitute.dsde.workbench.leonardo.WsmControlledDatabaseResource +import org.broadinstitute.dsde.workbench.leonardo.config.AzureEnvironmentConverter import org.broadinstitute.dsde.workbench.leonardo.http.ConfigReader import org.broadinstitute.dsde.workbench.leonardo.util.AppCreationException @@ -48,7 +49,8 @@ class WorkflowsAppInstallSpec extends BaseAppInstallSpec { "instrumentationEnabled=false," + s"provenance.userAccessToken=${petUserInfo.accessToken.token}," + "postgres.podLocalDatabaseEnabled=false," + - s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres.database.azure.com," + + s"postgres.host=${lzResources.postgresServer.map(_.name).get}.postgres${AzureEnvironmentConverter + .postgresSuffixFromString(ConfigReader.appConfig.azure.hostingModeConfig.azureEnvironment)}," + "postgres.pgbouncer.enabled=true," + "postgres.user=ksa-1," + s"postgres.dbnames.cromwellMetadata=$cromwellMetadataAzureDbName," + diff --git a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/auth/AllowlistAuthProvider.scala b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/auth/AllowlistAuthProvider.scala index b7ee1e8bf7f..85558acd82f 100644 --- a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/auth/AllowlistAuthProvider.scala +++ b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/auth/AllowlistAuthProvider.scala @@ -168,5 +168,5 @@ class AllowlistAuthProvider(config: Config) extends LeoAuthProvider[IO] { override def isSasAppAllowed(userEmail: WorkbenchEmail)(implicit ev: Ask[IO, TraceId]): IO[Boolean] = IO.pure(true) - override def getLeoAuthToken: IO[String] = ??? + override def getLeoAuthToken: IO[String] = IO.pure("") } diff --git a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/dao/MockSamDAO.scala b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/dao/MockSamDAO.scala index 68736235f64..74d04d7163b 100644 --- a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/dao/MockSamDAO.scala +++ b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/dao/MockSamDAO.scala @@ -445,7 +445,7 @@ class MockSamDAO extends SamDAO[IO] { } override def getLeoAuthToken: IO[Authorization] = - IO.pure(Authorization(Credentials.Token(AuthScheme.Bearer, ""))) + IO.pure(Authorization(Credentials.Token(AuthScheme.Bearer, "dummytoken"))) override def getSamUserInfo(token: String)(implicit ev: Ask[IO, TraceId]): IO[Option[SamUserInfo]] = if (token == OAuth2BearerToken(s"TokenFor${MockSamDAO.disabledUserEmail}").token) diff --git a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/http/ConfigReaderSpec.scala b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/http/ConfigReaderSpec.scala index 36f22b0a711..4cae79f5b8e 100644 --- a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/http/ConfigReaderSpec.scala +++ b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/http/ConfigReaderSpec.scala @@ -74,7 +74,7 @@ class ConfigReaderSpec extends AnyFlatSpec with Matchers { "2.1", true, List( - "https://raw.githubusercontent.com/DataBiosphere/leonardo/8390d25ccd761fb206cf388560a571be77a42bbd/http/src/main/resources/init-resources/azure_vm_init_script.sh" + "https://raw.githubusercontent.com/DataBiosphere/leonardo/f58c237b4dc235cd1c24c6dfc7500c07bdbd5bc3/http/src/main/resources/init-resources/azure_vm_init_script.sh" ) ), // [IA-4997] to support CHIPS by setting partitioned cookies @@ -152,7 +152,7 @@ class ConfigReaderSpec extends AnyFlatSpec with Matchers { ), CromwellRunnerAppConfig( ChartName("terra-helm/cromwell-runner-app"), - ChartVersion("0.197.0"), + ChartVersion("0.198.0"), ReleaseNameSuffix("cra-rls"), NamespaceNameSuffix("cra-ns"), KsaName("cra-ksa"), @@ -267,9 +267,28 @@ class ConfigReaderSpec extends AnyFlatSpec with Matchers { val expectedGovEnv = AzureEnvironment.AZURE_US_GOVERNMENT govEnv shouldBe expectedGovEnv - val chinaEnv = AzureEnvironmentConverter.fromString(AzureEnvironmentConverter.AzureChina) - val expectedChinaEnv = AzureEnvironment.AZURE_CHINA - chinaEnv shouldBe expectedChinaEnv - } + val govRelay = AzureEnvironmentConverter.relaySuffixFromString(AzureEnvironmentConverter.AzureGov) + val expectedGovRelay = AzureEnvironmentConverter.relaySuffixFromEnvironment(AzureEnvironment.AZURE_US_GOVERNMENT) + govRelay shouldBe expectedGovRelay + + val govPostgres = AzureEnvironmentConverter.postgresSuffixFromString(AzureEnvironmentConverter.AzureGov) + val expGovPostgres = AzureEnvironmentConverter.postgresSuffixFromEnvironment(AzureEnvironment.AZURE_US_GOVERNMENT) + govPostgres shouldBe expGovPostgres + + val govBatch = AzureEnvironmentConverter.batchAccountSuffixFromString(AzureEnvironmentConverter.AzureGov) + val expGovBatch = AzureEnvironmentConverter.batchAccountSuffixFromEnvironment(AzureEnvironment.AZURE_US_GOVERNMENT) + govBatch shouldBe expGovBatch + val defaultRelay = AzureEnvironmentConverter.relaySuffixFromString("") + val expectedDefaultRelay = AzureEnvironmentConverter.relaySuffixFromEnvironment(AzureEnvironment.AZURE) + defaultRelay shouldBe expectedDefaultRelay + + val defaultPostgres = AzureEnvironmentConverter.postgresSuffixFromString("") + val expectedDefaultPostgres = AzureEnvironmentConverter.postgresSuffixFromEnvironment(AzureEnvironment.AZURE) + defaultPostgres shouldBe expectedDefaultPostgres + + val defaultBatch = AzureEnvironmentConverter.batchAccountSuffixFromString(AzureEnvironmentConverter.Azure) + val expectedDefaultBatch = AzureEnvironmentConverter.batchAccountSuffixFromEnvironment(AzureEnvironment.AZURE) + defaultBatch shouldBe expectedDefaultBatch + } } diff --git a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/http/service/AppServiceInterpSpec.scala b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/http/service/AppServiceInterpSpec.scala index 84f17055227..f5528ae07f0 100644 --- a/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/http/service/AppServiceInterpSpec.scala +++ b/http/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/http/service/AppServiceInterpSpec.scala @@ -306,6 +306,7 @@ class AppServiceInterpTest extends AnyFlatSpec with AppServiceInterpSpec with Le val mockAuthProvider = mock[LeoAuthProvider[IO]] when(mockAuthProvider.hasPermission(any, any, any)(any, any)).thenReturn(IO.pure(true)) when(mockAuthProvider.lookupOriginatingUserEmail(any)(any)).thenReturn(IO.pure(userInfo.userEmail)) + when(mockAuthProvider.getLeoAuthToken).thenReturn(IO.pure("")) val publisherQueue = QueueFactory.makePublisherQueue() val mockSamService = mock[SamService[IO]] when(mockSamService.createResource(any, any, any, any, any)(any)).thenReturn(IO.unit) @@ -3349,19 +3350,20 @@ class AppServiceInterpTest extends AnyFlatSpec with AppServiceInterpSpec with Le } it should "get a correct sam policy map for apps" in { - val map1 = LeoAppServiceInterp.getAppSamPolicyMap(userEmail, None) + val leoEmail = WorkbenchEmail("leonardo") + val map1 = LeoAppServiceInterp.getAppSamPolicyMap(userEmail, leoEmail, None) map1 should have size 1 map1 should contain key "creator" - map1("creator") shouldBe SamPolicyData(List(userEmail), List(AppRole.Creator.asString)) + map1("creator") shouldBe SamPolicyData(List(userEmail, leoEmail), List(AppRole.Creator.asString)) - val map2 = LeoAppServiceInterp.getAppSamPolicyMap(userEmail, Some(AppAccessScope.UserPrivate)) + val map2 = LeoAppServiceInterp.getAppSamPolicyMap(userEmail, leoEmail, Some(AppAccessScope.UserPrivate)) map2 should have size 1 map2 should contain key "creator" - map2("creator") shouldBe SamPolicyData(List(userEmail), List(AppRole.Creator.asString)) + map2("creator") shouldBe SamPolicyData(List(userEmail, leoEmail), List(AppRole.Creator.asString)) - val map3 = LeoAppServiceInterp.getAppSamPolicyMap(userEmail, Some(AppAccessScope.WorkspaceShared)) + val map3 = LeoAppServiceInterp.getAppSamPolicyMap(userEmail, leoEmail, Some(AppAccessScope.WorkspaceShared)) map3 should have size 1 map3 should contain key "owner" - map3("owner") shouldBe SamPolicyData(List(userEmail), List(SharedAppRole.Owner.asString)) + map3("owner") shouldBe SamPolicyData(List(userEmail, leoEmail), List(SharedAppRole.Owner.asString)) } } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index e1c2d47b3de..b5fd8c41acb 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -24,7 +24,7 @@ object Dependencies { val workbenchGoogle2V = s"0.36-$workbenchLibsHash" val workbenchOpenTelemetryV = s"0.8-$workbenchLibsHash" val workbenchOauth2V = "0.8-3e0cf25" - val workbenchAzureV = s"0.8-$workbenchLibsHash" + val workbenchAzureV = s"0.10-b25c29d" val helmScalaSdkV = "0.0.9.1"