Skip to content

Commit

Permalink
Add SaaS App Parameters to Bicep Deployment (#190)
Browse files Browse the repository at this point in the history
* Add SaaS App Parameters to Bicep Deployment
* Include scopes parameter to SaaS App module
* Include Azure AD B2C secrets
* Add SaaS App principal id to key vault access policy

* Alias Parameters for Application
* Add Graph API disclaimer to readme
* Join scopes list in PowerShell script
* Match naming convention for SaaS App module varaible names

* PR Feedback - Remove AllowedHosts

* Add Key Vault values for SaaS App B2C secrets

* Remove Unused AllowedHosts Config

* PR Feedback

* fixes to bicep deploy

* update docs and tagging

* update container version

Co-authored-by: Landon Pierce <landonpierce@microsoft.com>
  • Loading branch information
julian-mcnichols and landonpierce committed Jun 28, 2022
1 parent 2854f99 commit 89bc358
Show file tree
Hide file tree
Showing 16 changed files with 428 additions and 57 deletions.
7 changes: 5 additions & 2 deletions docs/azure-saas-docs/content/en/quick-start.md
Expand Up @@ -14,7 +14,10 @@ On this page, you will find instructions for how to run the dev kit in your loca

This project uses [Azure Active Directory B2C](https://docs.microsoft.com/azure/active-directory-b2c/overview) for an IdP (Identity Provider). The first step in setting up this project is to configure a new Azure AD B2C instance to house your local user accounts. You will also need to deploy the [Permissions API](../components/identity/permissions-service), as Azure AD B2C will have a dependency on it.

To setup the Identity Framework, we have provided an interactive PowerShell script that automates the setup for you. Upon running, it will ask you to sign into your home azure account, ask you a few questions, and then begin the setup process. This PowerShell script will output a parameters file that you'll need to provide when deploying the solution to Azure in step 2.b.
To setup the Identity Framework, we have provided an interactive PowerShell script that automates the setup for you by calling the necessary Microsoft Graph API endpoints. Upon running, it will ask you to sign into your home azure account, ask you a few questions, and then begin the setup process. This PowerShell script will output a parameters file that you'll need to provide when deploying the solution to Azure in step 2.b.

> NOTE: The Microsoft Graph API endpoints used to perform this setup are still in beta and are subject to change. As a result, it is possible you may see issues during setup. Please report any issues with as much detail as possible by opening an issue on our [GitHub repo](https://github.com/Azure/azure-saas/issues).
<!-- > As a fallback, you can also create the Identity Framework manually by following the instructions below. -->
### Option 1: Setup Identity Framework - Docker (Recommended)

Expand Down Expand Up @@ -79,7 +82,7 @@ Deploying to Azure is easy thanks to our pre-configured ARM (Azure Resource Mana

This button will take you to the Azure portal and will pass it the ARM template. You will need the parameters file output from step 1.

1. Click here: [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-saas%2Fmain%2Fsrc%2FSaas.IaC%2Fmain.json).
1. Click here: [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-saas%2Fv1.0%2Fsrc%2FSaas.IaC%2Fmain.json).
2. Select "Edit Parameters".
3. Select "Load File" and upload the `parameters.json` file output from the Identity Framework Deployment (step 1 above). Click "Save".
4. From the dropdown, select the subscription and resource group you'd like to deploy the resources to.
Expand Down
1 change: 0 additions & 1 deletion src/Saas.Admin/Saas.Admin.Service/appsettings.json
Expand Up @@ -9,7 +9,6 @@
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"KeyVault": {
"Url": "",
"PermissionsApiCertName": "devenvcert"
Expand Down
5 changes: 5 additions & 0 deletions src/Saas.Application/Saas.Application.Web/Program.cs
Expand Up @@ -108,6 +108,11 @@
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseForwardedHeaders();
app.UseCookiePolicy(new CookiePolicyOptions
{
Secure = CookieSecurePolicy.Always
});

app.UseEndpoints(endpoints =>
{
Expand Down
3 changes: 1 addition & 2 deletions src/Saas.Application/Saas.Application.Web/appsettings.json
Expand Up @@ -16,6 +16,5 @@
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
}
4 changes: 0 additions & 4 deletions src/Saas.IaC/adminApi.bicep
Expand Up @@ -61,10 +61,6 @@ resource adminApi 'Microsoft.Web/sites@2021-03-01' = {
name: 'PermissionsApi__BaseUrl'
value: permissionsApiHostName
}
{
name: 'AllowedHosts'
value: '*'
}
{
name: 'Logging__LogLevel__Default'
value: 'Information'
Expand Down
54 changes: 53 additions & 1 deletion src/Saas.IaC/applicationWeb.bicep
Expand Up @@ -3,6 +3,18 @@
@description('The App Service Plan ID.')
param appServicePlanId string

@description('The Admin Api host name.')
param adminApiHostName string

@description('Scopes to authorize user for the admin service.')
param saasAppApiScopes string

@description('The base url for the app registration that the scopes belong to.')
param adminApiScopeBaseUrl string

@description('The URL for the keyvault that contains the application secrets')
param keyVaultUri string

@description('The location for all resources.')
param location string

Expand All @@ -29,13 +41,52 @@ resource applicationAppService 'Microsoft.Web/sites@2021-03-01' = {
alwaysOn: true
linuxFxVersion: 'DOCKER|${applicationApiContainerImageTag}'
appSettings: [
{
name: 'AppSettings__AdminServiceBaseUrl'
value: adminApiHostName
}
{
name: 'AppSettings__AdminServiceScopeBaseUrl'
value: adminApiScopeBaseUrl
}
{
name: 'AppSettings__AdminServiceScopes'
value: saasAppApiScopes
}
{
name: 'AzureAdB2C__SignedOutCallbackPath'
value: '/signout/B2C_1A_SIGNUP_SIGNIN'
}
{
name: 'AzureAdB2C__SignUpSignInPolicyId'
value: 'B2C_1A_SIGNUP_SIGNIN'
}
{
name: 'DOCKER_REGISTRY_SERVER_URL'
value: containerRegistryUrl
}
}
{
name: 'KeyVault__Url'
value: keyVaultUri
}
{
name: 'Logging__LogLevel__Default'
value: 'Information'
}
{
name: 'Logging__LogLevel__Microsoft'
value: 'Warning'
}
{
name: 'Logging__LogLevel__Microsoft.Hosting.Lifetime'
value: 'Information'
}
]
}
}
identity: {
type: 'SystemAssigned'
}
}

// Resource - Application App Service - Deployment
Expand All @@ -51,3 +102,4 @@ resource applicationAppService 'Microsoft.Web/sites@2021-03-01' = {
// Outputs
//////////////////////////////////////////////////
output applicationAppServiceHostName string = applicationAppService.properties.defaultHostName
output systemAssignedManagedIdentityPrincipalId string = applicationAppService.identity.principalId
71 changes: 71 additions & 0 deletions src/Saas.IaC/keyVault.bicep
Expand Up @@ -21,6 +21,27 @@ param azureAdB2cSignupAdminDomainSecretName string = 'signupadmin-AzureAdB2C--Do
@description('The value of the Azure AD B2C Domain Key Vault Secret.')
param azureAdB2cDomainSecretValue string

@description('The name of the Azure AD B2C SaaS App Client Id Key Vault Secret.')
param azureAdB2cSaasAppClientIdSecretName string = 'saasapplication-AzureAdB2C--ClientId'

@description('The value of the Azure AD B2C SaaS App Client Id Key Vault Secret.')
param azureAdB2cSaasAppClientIdSecretValue string

@description('The name of the Azure AD B2C SaaS App Client Secret Key Vault Secret.')
param azureAdB2cSaasAppClientSecretSecretName string = 'saasapplication-AzureAdB2C--ClientSecret'

@description('The value of the Azure AD B2C SaaS App Client Secret Key Vault Secret.')
param azureAdB2cSaasAppClientSecretSecretValue string

@description('The name of the Azure AD B2C Domain Key Vault Secret for the Saas App Site.')
param azureAdB2cSaasAppDomainSecretName string = 'saasapplication-AzureAdB2C--Domain'

@description('The name of the Azure AD B2C Instance Key Vault Secret for the Saas App Site.')
param azureAdB2cSaasAppInstanceSecretName string = 'saasapplication-AzureAdB2C--Instance'

@description('The name of the Azure AD B2C Tenant Id Key Vault Secret for the SignupAdmin site.')
param azureAdB2cSaasAppTenantIdSecretName string = 'saasapplication-AzureAdB2C--TenantId'

@description('The name of the Azure AD B2C Instance Key Vault Secre for the Admin Api.')
param azureAdB2cAdminApiInstanceSecretName string = 'admin-AzureAdB2C--Instance'

Expand Down Expand Up @@ -131,6 +152,56 @@ resource azureAdB2cSignupAdminInstanceSecret 'Microsoft.KeyVault/vaults/secrets@
}
}

// Resource - Key Vault - Secret - Azure AD B2C Client ID SaaS App
//////////////////////////////////////////////////
resource azureAdB2cSaasAppClientIdSecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
parent: keyVault
name: azureAdB2cSaasAppClientIdSecretName
properties: {
value: azureAdB2cSaasAppClientIdSecretValue
}
}

// Resource - Key Vault - Secret - Azure AD B2C Client Secret SaaS App
//////////////////////////////////////////////////
resource azureAdB2cSaasAppClientSecretSecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
parent: keyVault
name: azureAdB2cSaasAppClientSecretSecretName
properties: {
value: azureAdB2cSaasAppClientSecretSecretValue
}
}

// Resource - Key Vault - Secret - Azure AD B2C Domain SaaS App
//////////////////////////////////////////////////
resource azureAdB2cSaasAppDomainSecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
parent: keyVault
name: azureAdB2cSaasAppDomainSecretName
properties: {
value: azureAdB2cDomainSecretValue
}
}

// Resource - Key Vault - Secret - Azure AD B2C Instance SaaS App
//////////////////////////////////////////////////
resource azureAdB2cSaasAppInstanceSecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
parent: keyVault
name: azureAdB2cSaasAppInstanceSecretName
properties: {
value: azureAdB2cInstanceSecretValue
}
}

// Resource - Key Vault - Secret - Azure AD B2C Instance SaaS App
//////////////////////////////////////////////////
resource azureAdB2cSaasAppTenantIdSecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
parent: keyVault
name: azureAdB2cSaasAppTenantIdSecretName
properties: {
value: azureAdB2cTenantIdSecretValue
}
}

// Resource - Key Vault - Secret - Azure AD B2C Domain Admin Api
//////////////////////////////////////////////////
resource azureAdB2cAdminApiDomainSecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
Expand Down
16 changes: 16 additions & 0 deletions src/Saas.IaC/keyVaultAccessPolicies.bicep
Expand Up @@ -12,6 +12,12 @@ param modulesToDeploy object
@description('The Principal Id of the Signup Admin App Service System Assigned Managed Identity.')
param signupAdminAppServicePrincipalId string


@description('The Principal Id of the Saas App Service System Assigned Managed Identity.')
param applicationAppServicePrincipalId string



// Existing Resource - Key Vault
//////////////////////////////////////////////////
resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = {
Expand Down Expand Up @@ -45,6 +51,16 @@ resource accessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2021-11-01-previ
]
}
} : {}
(modulesToDeploy.applicationWeb) ? {
objectId: applicationAppServicePrincipalId
tenantId: subscription().tenantId
permissions: {
secrets: [
'get'
'list'
]
}
} : {}
]
}
}
22 changes: 19 additions & 3 deletions src/Saas.IaC/main.bicep
Expand Up @@ -7,10 +7,10 @@ param adminApiScopes string
param adminApiScopeBaseUrl string

@description('The tag of the container image to deploy to the Admin api app service.')
param adminApiContainerImageTag string = 'ghcr.io/azure/azure-saas/asdk-admin:latest'
param adminApiContainerImageTag string = 'ghcr.io/azure/azure-saas/asdk-admin:v1.0'

@description('The tag of the container image to deploy to the SaaS Application api app service.')
param applicationContainerImageTag string = 'ghcr.io/azure/azure-saas/asdk-web:latest'
param applicationContainerImageTag string = 'ghcr.io/azure/azure-saas/asdk-web:v1.0'

@description('The value of the Azure AD B2C Admin Api Client Id Key Vault Secret.')
param azureAdB2cAdminApiClientIdSecretValue string
Expand All @@ -21,6 +21,12 @@ param azureAdB2cDomainSecretValue string
@description('The value of the Azure AD B2C Instance Key Vault Secret.')
param azureAdB2cInstanceSecretValue string

@description('The value of the Azure AD B2C SaaS App Client Id Key Vault Secret.')
param azureAdB2cSaasAppClientIdSecretValue string

@description('The value of the Azure AD B2C SaaS App Client Secret Key Vault Secret.')
param azureAdB2cSaasAppClientSecretSecretValue string

@description('The value of the Azure AD B2C Signup Admin Client Id Key Vault Secret.')
param azureAdB2cSignupAdminClientIdSecretValue string

Expand Down Expand Up @@ -58,8 +64,11 @@ param permissionsApiCertificateSecretValue string
@secure()
param permissionsApiCertificatePassphraseSecretValue string

@description('Scopes to authorize SaaS App user for the admin service.')
param saasAppApiScopes string

@description('The tag of the container image to deploy to the SignupAdmin app service.')
param signupAdminContainerImageTag string = 'ghcr.io/azure/azure-saas/asdk-signup:latest'
param signupAdminContainerImageTag string = 'ghcr.io/azure/azure-saas/asdk-signup:v1.0'

@description('The SaaS Provider name.')
param saasProviderName string
Expand Down Expand Up @@ -147,6 +156,8 @@ module keyVaultModule 'keyVault.bicep' = {
azureAdB2cAdminApiClientIdSecretValue: azureAdB2cAdminApiClientIdSecretValue
azureAdB2cDomainSecretValue: azureAdB2cDomainSecretValue
azureAdB2cInstanceSecretValue: azureAdB2cInstanceSecretValue
azureAdB2cSaasAppClientIdSecretValue: azureAdB2cSaasAppClientIdSecretValue
azureAdB2cSaasAppClientSecretSecretValue: azureAdB2cSaasAppClientSecretSecretValue
azureAdB2cSignupAdminClientIdSecretValue: azureAdB2cSignupAdminClientIdSecretValue
azureAdB2cSignupAdminClientSecretSecretValue: azureAdB2cSignupAdminClientSecretSecretValue
azureAdB2cTenantIdSecretValue: azureAdB2cTenantIdSecretValue
Expand Down Expand Up @@ -195,8 +206,12 @@ module signupAdminAppServiceModule 'signupAdminWeb.bicep' = if (modulesToDeploy.
module applicationAppServiceModule 'applicationWeb.bicep' = if (modulesToDeploy.applicationWeb) {
name: 'applicationAppServiceDeployment'
params: {
adminApiHostName: (modulesToDeploy.adminService) ? adminApiModule.outputs.adminApiHostName : messageToUpdate
saasAppApiScopes: saasAppApiScopes
adminApiScopeBaseUrl: adminApiScopeBaseUrl
applicationAppServiceName: applicationAppServiceName
appServicePlanId: appServicePlanModule.outputs.appServicePlanId
keyVaultUri: keyVaultModule.outputs.keyVaultUri
location: location
applicationApiContainerImageTag: applicationContainerImageTag
containerRegistryUrl: containerRegistryUrl
Expand All @@ -211,6 +226,7 @@ module keyVaultAccessPolicyModule 'keyVaultAccessPolicies.bicep' = {
adminApiPrincipalId: adminApiModule.outputs.systemAssignedManagedIdentityPrincipalId
keyVaultName: keyVaultName
modulesToDeploy: modulesToDeploy
applicationAppServicePrincipalId: applicationAppServiceModule.outputs.systemAssignedManagedIdentityPrincipalId
signupAdminAppServicePrincipalId: signupAdminAppServiceModule.outputs.systemAssignedManagedIdentityPrincipalId
}
}

0 comments on commit 89bc358

Please sign in to comment.