diff --git a/.azuredevops/modulePipelines/ms.web.staticsites.yml b/.azuredevops/modulePipelines/ms.web.staticsites.yml new file mode 100644 index 0000000000..ce57e715f4 --- /dev/null +++ b/.azuredevops/modulePipelines/ms.web.staticsites.yml @@ -0,0 +1,52 @@ +name: 'Web - StaticSites' + +parameters: + - name: removeDeployment + displayName: Remove deployed module + type: boolean + default: true + - name: prerelease + displayName: Publish prerelease module + type: boolean + default: false + +trigger: + batch: true + branches: + include: + - main + paths: + include: + - '/.azuredevops/modulePipelines/ms.web.staticsites.yml' + - '/.azuredevops/pipelineTemplates/module.*.yml' + - '/arm/Microsoft.Web/staticSites/*' + exclude: + - '/**/*.md' + +variables: + - template: '/.azuredevops/pipelineVariables/global.variables.yml' + - group: 'PLATFORM_VARIABLES' + - name: modulePath + value: '/arm/Microsoft.Web/staticSites' + +stages: + - stage: Validation + displayName: Pester tests + jobs: + - template: /.azuredevops/pipelineTemplates/jobs.validateModulePester.yml + + - stage: Deployment + displayName: Deployment tests + jobs: + - template: /.azuredevops/pipelineTemplates/jobs.validateModuleDeployment.yml + parameters: + removeDeployment: '${{ parameters.removeDeployment }}' + deploymentBlocks: + - path: $(modulePath)/.parameters/min.parameters.json + - path: $(modulePath)/.parameters/parameters.json + + - stage: Publishing + displayName: Publish module + condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq('${{ parameters.prerelease }}', 'true'))) + jobs: + - template: /.azuredevops/pipelineTemplates/jobs.publishModule.yml diff --git a/.github/workflows/ms.web.staticsites.yml b/.github/workflows/ms.web.staticsites.yml new file mode 100644 index 0000000000..2d35caab4b --- /dev/null +++ b/.github/workflows/ms.web.staticsites.yml @@ -0,0 +1,139 @@ +name: 'Web: StaticSites' + +on: + workflow_dispatch: + inputs: + removeDeployment: + type: boolean + description: 'Remove deployed module' + required: false + default: true + prerelease: + type: boolean + description: 'Publish prerelease module' + required: false + default: false + push: + branches: + - main + paths: + - '.github/actions/templates/**' + - '.github/workflows/ms.web.staticsites.yml' + - 'arm/Microsoft.Web/staticSites/**' + - '!*/**/readme.md' + - 'utilities/pipelines/**' + - '!utilities/pipelines/dependencies/**' + +env: + modulePath: 'arm/Microsoft.Web/staticSites' + workflowPath: '.github/workflows/ms.web.staticsites.yml' + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + ARM_SUBSCRIPTION_ID: '${{ secrets.ARM_SUBSCRIPTION_ID }}' + ARM_MGMTGROUP_ID: '${{ secrets.ARM_MGMTGROUP_ID }}' + ARM_TENANT_ID: '${{ secrets.ARM_TENANT_ID }}' + DEPLOYMENT_SP_ID: '${{ secrets.DEPLOYMENT_SP_ID }}' + +jobs: + ############################ + # SET INPUT PARAMETERS # + ############################ + job_set_workflow_param: + runs-on: ubuntu-20.04 + name: 'Set input parameters to output variables' + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: 'Set input parameters' + id: get-workflow-param + uses: ./.github/actions/templates/getWorkflowInput + with: + workflowPath: '${{ env.workflowPath}}' + outputs: + removeDeployment: ${{ steps.get-workflow-param.outputs.removeDeployment }} + + #################### + # Pester Tests # + #################### + job_module_pester_validation: + runs-on: ubuntu-20.04 + name: 'Pester tests' + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: 'Run tests' + uses: ./.github/actions/templates/validateModulePester + with: + modulePath: '${{ env.modulePath }}' + + #################### + # Deployment tests # + #################### + job_module_deploy_validation: + runs-on: ubuntu-20.04 + name: 'Deployment tests' + needs: + - job_set_workflow_param + - job_module_pester_validation + strategy: + fail-fast: false + matrix: + parameterFilePaths: + [ + 'min.parameters.json', + 'parameters.json' + ] + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Set environment variables + uses: deep-mm/set-variables@v1.0 + with: + variableFileName: 'global.variables' + - name: 'Using parameter file [${{ matrix.parameterFilePaths }}]' + uses: ./.github/actions/templates/validateModuleDeployment + with: + templateFilePath: '${{ env.modulePath }}/deploy.bicep' + parameterFilePath: '${{ env.modulePath }}/.parameters/${{ matrix.parameterFilePaths }}' + location: '${{ env.defaultLocation }}' + resourceGroupName: '${{ env.resourceGroupName }}' + subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}' + managementGroupId: '${{ secrets.ARM_MGMTGROUP_ID }}' + removeDeployment: '${{ needs.job_set_workflow_param.outputs.removeDeployment }}' + + ############### + # PUBLISH # + ############### + job_publish_module: + name: 'Publish module' + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.event.inputs.prerelease == 'true' + runs-on: ubuntu-20.04 + needs: + - job_set_workflow_param + - job_module_deploy_validation + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Set environment variables + uses: deep-mm/set-variables@v1.0 + with: + variableFileName: 'global.variables' + - name: 'Publish module' + uses: ./.github/actions/templates/publishModule + with: + templateFilePath: '${{ env.modulePath }}/deploy.bicep' + templateSpecsRGName: '${{ env.templateSpecsRGName }}' + templateSpecsRGLocation: '${{ env.templateSpecsRGLocation }}' + templateSpecsDescription: '${{ env.templateSpecsDescription }}' + templateSpecsDoPublish: '${{ env.templateSpecsDoPublish }}' + bicepRegistryName: '${{ env.bicepRegistryName }}' + bicepRegistryRGName: '${{ env.bicepRegistryRGName }}' + bicepRegistryRgLocation: '${{ env.bicepRegistryRgLocation }}' + bicepRegistryDoPublish: '${{ env.bicepRegistryDoPublish }}' diff --git a/arm/Microsoft.Web/staticSites/.bicep/nested_cuaId.bicep b/arm/Microsoft.Web/staticSites/.bicep/nested_cuaId.bicep new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/arm/Microsoft.Web/staticSites/.bicep/nested_cuaId.bicep @@ -0,0 +1 @@ + diff --git a/arm/Microsoft.Web/staticSites/.bicep/nested_privateEndpoint.bicep b/arm/Microsoft.Web/staticSites/.bicep/nested_privateEndpoint.bicep new file mode 100644 index 0000000000..517bc60383 --- /dev/null +++ b/arm/Microsoft.Web/staticSites/.bicep/nested_privateEndpoint.bicep @@ -0,0 +1,49 @@ +param privateEndpointResourceId string +param privateEndpointVnetLocation string +param privateEndpointObj object +param tags object + +var privateEndpointResourceName = last(split(privateEndpointResourceId, '/')) +var privateEndpoint_var = { + name: contains(privateEndpointObj, 'name') ? (!empty(privateEndpointObj.name) ? privateEndpointObj.name : '${privateEndpointResourceName}-${privateEndpointObj.service}') : '${privateEndpointResourceName}-${privateEndpointObj.service}' + subnetResourceId: privateEndpointObj.subnetResourceId + service: [ + privateEndpointObj.service + ] + privateDnsZoneResourceIds: contains(privateEndpointObj, 'privateDnsZoneResourceIds') ? (!empty(privateEndpointObj.privateDnsZoneResourceIds) ? privateEndpointObj.privateDnsZoneResourceIds : []) : [] + customDnsConfigs: contains(privateEndpointObj, 'customDnsConfigs') ? (!empty(privateEndpointObj.customDnsConfigs) ? privateEndpointObj.customDnsConfigs : null) : null +} + +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2021-05-01' = { + name: privateEndpoint_var.name + location: privateEndpointVnetLocation + tags: tags + properties: { + privateLinkServiceConnections: [ + { + name: privateEndpoint_var.name + properties: { + privateLinkServiceId: privateEndpointResourceId + groupIds: privateEndpoint_var.service + } + } + ] + manualPrivateLinkServiceConnections: [] + subnet: { + id: privateEndpoint_var.subnetResourceId + } + customDnsConfigs: privateEndpoint_var.customDnsConfigs + } +} + +resource privateDnsZoneGroups 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2021-05-01' = if (!empty(privateEndpoint_var.privateDnsZoneResourceIds)) { + name: '${privateEndpoint.name}/default' + properties: { + privateDnsZoneConfigs: [for privateDnsZoneResourceId in privateEndpoint_var.privateDnsZoneResourceIds: { + name: last(split(privateDnsZoneResourceId, '/')) + properties: { + privateDnsZoneId: privateDnsZoneResourceId + } + }] + } +} diff --git a/arm/Microsoft.Web/staticSites/.bicep/nested_rbac.bicep b/arm/Microsoft.Web/staticSites/.bicep/nested_rbac.bicep new file mode 100644 index 0000000000..e836ef8554 --- /dev/null +++ b/arm/Microsoft.Web/staticSites/.bicep/nested_rbac.bicep @@ -0,0 +1,32 @@ +param principalIds array +param roleDefinitionIdOrName string +param resourceId string + +var builtInRoleNames = { + 'Owner': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Log Analytics Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','92aaf0da-9dab-42b6-94a3-d43ce8d16293') + 'Log Analytics Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','73c42c96-874c-492b-b04d-ab87d138a893') + 'Managed Application Contributor Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','641177b8-a67a-45b9-a033-47bc880bb21e') + 'Managed Application Operator Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','c7393b34-138c-406f-901b-d8cf2b17e6ae') + 'Managed Applications Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','b9331d33-8a36-4f8c-b097-4f54124fdb44') + 'Monitoring Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','749f88d5-cbae-40b8-bcfc-e573ddc772fa') + 'Monitoring Metrics Publisher': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','3913510d-42f4-4e42-8a64-420c390055eb') + 'Monitoring Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','43d0d8ad-25c7-4714-9337-8ba259a9fe05') + 'Resource Policy Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','36243c78-bf99-498c-9df9-86d9f8d28608') + 'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions','18d7d88d-d35e-4fb5-a5c3-7773c20a72d9') +} + +resource staticSite 'Microsoft.Web/staticSites@2021-02-01' existing = { + name: last(split(resourceId, '/')) +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2021-04-01-preview' = [for principalId in principalIds: { + name: guid(staticSite.name, principalId, roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleDefinitionIdOrName) ? builtInRoleNames[roleDefinitionIdOrName] : roleDefinitionIdOrName + principalId: principalId + } + scope: staticSite +}] diff --git a/arm/Microsoft.Web/staticSites/.parameters/min.parameters.json b/arm/Microsoft.Web/staticSites/.parameters/min.parameters.json new file mode 100644 index 0000000000..b5781f46f0 --- /dev/null +++ b/arm/Microsoft.Web/staticSites/.parameters/min.parameters.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "<>-az-wss-min-001" + } + } +} diff --git a/arm/Microsoft.Web/staticSites/.parameters/parameters.json b/arm/Microsoft.Web/staticSites/.parameters/parameters.json new file mode 100644 index 0000000000..46d43ca75f --- /dev/null +++ b/arm/Microsoft.Web/staticSites/.parameters/parameters.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "<>-az-wss-x-001" + }, + "sku": { + "value": "Standard" + }, + "stagingEnvironmentPolicy": { + "value": "Enabled" + }, + "allowConfigFileUpdates": { + "value": true + }, + "enterpriseGradeCdnStatus": { + "value": "Disabled" + }, + "systemAssignedIdentity": { + "value": true + }, + "userAssignedIdentities": { + "value": { + "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001": {} + } + }, + "roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Reader", + "principalIds": [ + "<>" + ] + } + ] + }, + "privateEndpoints": { + "value": [ + { + "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-001/subnets/<>-az-subnet-x-005-privateEndpoints", + "service": "staticSites" + } + ] + } + } +} diff --git a/arm/Microsoft.Web/staticSites/deploy.bicep b/arm/Microsoft.Web/staticSites/deploy.bicep new file mode 100644 index 0000000000..03ff5d5251 --- /dev/null +++ b/arm/Microsoft.Web/staticSites/deploy.bicep @@ -0,0 +1,152 @@ +@description('Required. Name of the static site.') +@minLength(1) +@maxLength(40) +param name string + +@allowed([ + 'Free' + 'Standard' +]) +@description('Optional. Type of static site to deploy.') +param sku string = 'Free' + +@description('Optional. If config file is locked for this static web app.') +param allowConfigFileUpdates bool = true + +@description('Optional. Location to deploy static site. The following locations are supported: CentralUS, EastUS2, EastAsia, WestEurope, WestUS2') +param location string = resourceGroup().location + +@allowed([ + 'Enabled' + 'Disabled' +]) +@description('Optional. State indicating whether staging environments are allowed or not allowed for a static web app.') +param stagingEnvironmentPolicy string = 'Enabled' + +@allowed([ + 'Disabled' + 'Disabling' + 'Enabled' + 'Enabling' +]) +@description('Optional. State indicating the status of the enterprise grade CDN serving traffic to the static web app.') +param enterpriseGradeCdnStatus string = 'Disabled' + +@description('Optional. Build properties for the static site.') +param buildProperties object = {} + +@description('Optional. Template Options for the static site.') +param templateProperties object = {} + +@description('Optional. The provider that submitted the last deployment to the primary environment of the static site.') +param provider string = 'None' + +@secure() +@description('Optional. The Personal Access Token for accessing the GitHub repo.') +param repositoryToken string = '' + +@description('Optional. The name of the GitHub repo.') +param repositoryUrl string = '' + +@description('Optional. The branch name of the GitHub repo.') +param branch string = '' + +@description('Optional. Enables system assigned managed identity on the resource.') +param systemAssignedIdentity bool = false + +@description('Optional. The ID(s) to assign to the resource.') +param userAssignedIdentities object = {} + +@allowed([ + 'CanNotDelete' + 'NotSpecified' + 'ReadOnly' +]) +@description('Optional. Specify the type of lock.') +param lock string = 'NotSpecified' + +@description('Optional. Configuration details for private endpoints.') +param privateEndpoints array = [] + +@description('Optional. Tags of the resource.') +param tags object = {} + +@description('Optional. Customer Usage Attribution ID (GUID). This GUID must be previously registered.') +param cuaId string = '' + +@description('Optional. Array of role assignment objects that contain the \'roleDefinitionIdOrName\' and \'principalId\' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') +param roleAssignments array = [] + +var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None') + +var identity = identityType != 'None' ? { + type: identityType + userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +} : null + +module pid_cuaId '.bicep/nested_cuaId.bicep' = if (!empty(cuaId)) { + name: 'pid-${cuaId}' + params: {} +} + +resource staticSite 'Microsoft.Web/staticSites@2021-03-01' = { + name: name + location: location + tags: tags + identity: identity + sku: { + name: sku + tier: sku + } + properties: { + allowConfigFileUpdates: allowConfigFileUpdates + stagingEnvironmentPolicy: stagingEnvironmentPolicy + enterpriseGradeCdnStatus: enterpriseGradeCdnStatus + provider: !empty(provider) ? provider : 'None' + branch: !empty(branch) ? branch : null + buildProperties: !empty(buildProperties) ? buildProperties : null + repositoryToken: !empty(repositoryToken) ? repositoryToken : null + repositoryUrl: !empty(repositoryUrl) ? repositoryUrl : null + templateProperties: !empty(templateProperties) ? templateProperties : null + } +} + +resource staticSite_lock 'Microsoft.Authorization/locks@2017-04-01' = if (lock != 'NotSpecified') { + name: '${staticSite.name}-${lock}-lock' + properties: { + level: lock + notes: lock == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot modify the resource or child resources.' + } + scope: staticSite +} + +module staticSite_rbac '.bicep/nested_rbac.bicep' = [for (roleAssignment, index) in roleAssignments: { + name: '${uniqueString(deployment().name, location)}-StaticSite-Rbac-${index}' + params: { + principalIds: roleAssignment.principalIds + roleDefinitionIdOrName: roleAssignment.roleDefinitionIdOrName + resourceId: staticSite.id + } +}] + +module staticSite_privateEndpoint '.bicep/nested_privateEndpoint.bicep' = [for (privateEndpoint, index) in privateEndpoints: { + name: '${uniqueString(deployment().name, location)}-StaticSite-PrivateEndpoints-${index}' + params: { + privateEndpointResourceId: staticSite.id + privateEndpointVnetLocation: reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location + privateEndpointObj: privateEndpoint + tags: tags + } +}] + +@description('The name of the static site.') +output name string = staticSite.name + +@description('The resource ID of the static site.') +output resourceId string = staticSite.id + +@description('The resource group the static site was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The principal ID of the system assigned identity.') +output systemAssignedPrincipalId string = systemAssignedIdentity && contains(staticSite.identity, 'principalId') ? staticSite.identity.principalId : '' diff --git a/arm/Microsoft.Web/staticSites/readme.md b/arm/Microsoft.Web/staticSites/readme.md new file mode 100644 index 0000000000..1a00541c38 --- /dev/null +++ b/arm/Microsoft.Web/staticSites/readme.md @@ -0,0 +1,176 @@ +# Web StaticSites `[Microsoft.Web/staticSites]` + +This module deploys Web StaticSites. + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | 2017-04-01 | +| `Microsoft.Authorization/roleAssignments` | 2021-04-01-preview | +| `Microsoft.Network/privateEndpoints` | 2021-05-01 | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | 2021-05-01 | +| `Microsoft.Web/staticSites` | 2021-03-01 | + +## Parameters + +| Parameter Name | Type | Default Value | Possible Values | Description | +| :-- | :-- | :-- | :-- | :-- | +| `allowConfigFileUpdates` | bool | `True` | | Optional. If config file is locked for this static web app. | +| `branch` | string | | | Optional. The branch name of the GitHub repo. | +| `buildProperties` | object | `{object}` | | Optional. Build properties for the static site. | +| `cuaId` | string | | | Optional. Customer Usage Attribution ID (GUID). This GUID must be previously registered. | +| `enterpriseGradeCdnStatus` | string | `Disabled` | `[Disabled, Disabling, Enabled, Enabling]` | Optional. State indicating the status of the enterprise grade CDN serving traffic to the static web app. | +| `location` | string | `[resourceGroup().location]` | | Optional. Location to deploy static site. The following locations are supported: CentralUS, EastUS2, EastAsia, WestEurope, WestUS2 | +| `lock` | string | `NotSpecified` | `[CanNotDelete, NotSpecified, ReadOnly]` | Optional. Specify the type of lock. | +| `name` | string | | | Required. Name of the static site. | +| `privateEndpoints` | array | `[]` | | Optional. Configuration details for private endpoints. | +| `provider` | string | `None` | | Optional. The provider that submitted the last deployment to the primary environment of the static site. | +| `repositoryToken` | secureString | | | Optional. The Personal Access Token for accessing the GitHub repo. | +| `repositoryUrl` | string | | | Optional. The name of the GitHub repo. | +| `roleAssignments` | array | `[]` | | Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | +| `sku` | string | `Free` | `[Free, Standard]` | Optional. Type of static site to deploy. | +| `stagingEnvironmentPolicy` | string | `Enabled` | `[Enabled, Disabled]` | Optional. State indicating whether staging environments are allowed or not allowed for a static web app. | +| `systemAssignedIdentity` | bool | `False` | | Optional. Enables system assigned managed identity on the resource. | +| `tags` | object | `{object}` | | Optional. Tags of the resource. | +| `templateProperties` | object | `{object}` | | Optional. Template Options for the static site. | +| `userAssignedIdentities` | object | `{object}` | | Optional. The ID(s) to assign to the resource. | + +### Parameter Usage: `buildProperties` + +[StaticSiteBuildProperties - Microsoft.Web/staticSites 2021-03-01 - Bicep & ARM template reference | Microsoft Docs](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Web/2021-03-01/staticSites?tabs=bicep#staticsitebuildproperties) + +```bicep + buildProperties: { + apiBuildCommand: 'string' + apiLocation: 'string' + appArtifactLocation: 'string' + appBuildCommand: 'string' + appLocation: 'string' + githubActionSecretNameOverride: 'string' + outputLocation: 'string' + skipGithubActionWorkflowGeneration: bool + } +``` + +### Parameter Usage: `templateProperties` + +[StaticSiteTemplateOptions - Microsoft.Web/staticSites 2021-03-01 - Bicep & ARM template reference | Microsoft Docs](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Web/2021-03-01/staticSites?tabs=bicep#staticsitetemplateoptions) + +```bicep + buildProperties: { + apiBuildCommand: 'string' + apiLocation: 'string' + appArtifactLocation: 'string' + appBuildCommand: 'string' + appLocation: 'string' + githubActionSecretNameOverride: 'string' + outputLocation: 'string' + skipGithubActionWorkflowGeneration: bool + } +``` + +### Parameter Usage: `privateEndpoints` + +To use Private Endpoint the following dependencies must be deployed: + +- Destination subnet must be created with the following configuration option - `"privateEndpointNetworkPolicies": "Disabled"`. Setting this option acknowledges that NSG rules are not applied to Private Endpoints (this capability is coming soon). A full example is available in the Virtual Network Module. +- Although not strictly required, it is highly recommended to first create a private DNS Zone to host Private Endpoint DNS records. See [Azure Private Endpoint DNS configuration](https://docs.microsoft.com/en-us/azure/private-link/private-endpoint-dns) for more information. + +```json +"privateEndpoints": { + "value": [ + // Example showing all available fields + { + "name": "sxx-az-pe", // Optional: Name will be automatically generated if one is not provided here + "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/sxx-az-vnet-x-001/subnets/sxx-az-subnet-x-001", + "service": "blob", + "privateDnsZoneResourceIds": [ // Optional: No DNS record will be created if a private DNS zone Resource ID is not specified + "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/privateDnsZones/privatelink.blob.core.windows.net" + ], + "customDnsConfigs": [ // Optional + { + "fqdn": "customname.test.local", + "ipAddresses": [ + "10.10.10.10" + ] + } + ] + }, + // Example showing only mandatory fields + { + "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/sxx-az-vnet-x-001/subnets/sxx-az-subnet-x-001", + "service": "file" + } + ] +} +``` + +### Parameter Usage: `roleAssignments` + +```json +"roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Reader", + "principalIds": [ + "12345678-1234-1234-1234-123456789012", // object 1 + "78945612-1234-1234-1234-123456789012" // object 2 + ] + }, + { + "roleDefinitionIdOrName": "/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11", + "principalIds": [ + "12345678-1234-1234-1234-123456789012" // object 1 + ] + } + ] +} +``` + +### Parameter Usage: `tags` + +Tag names and tag values can be provided as needed. A tag can be left without a value. + +```json +"tags": { + "value": { + "Environment": "Non-Prod", + "Contact": "test.user@testcompany.com", + "PurchaseOrder": "1234", + "CostCenter": "7890", + "ServiceName": "DeploymentValidation", + "Role": "DeploymentValidation" + } +} +``` + +### Parameter Usage: `userAssignedIdentities` + +You can specify multiple user assigned identities to a resource by providing additional resource IDs using the following format: + +```json +"userAssignedIdentities": { + "value": { + "/subscriptions/12345678-1234-1234-1234-123456789012/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-sxx-az-msi-x-001": {}, + "/subscriptions/12345678-1234-1234-1234-123456789012/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-sxx-az-msi-x-002": {} + } +}, +``` + +## Outputs + +| Output Name | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the static site. | +| `resourceGroupName` | string | The resource group the static site was deployed into. | +| `resourceId` | string | The resource ID of the static site. | +| `systemAssignedPrincipalId` | string | The principal ID of the system assigned identity. | + +## Template references + +- [Locks](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2017-04-01/locks) +- [Privateendpoints](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Network/2021-05-01/privateEndpoints) +- [Privateendpoints/Privatednszonegroups](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Network/2021-05-01/privateEndpoints/privateDnsZoneGroups) +- [Roleassignments](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/roleAssignments) +- [Staticsites](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Web/2021-03-01/staticSites) diff --git a/arm/Microsoft.Web/staticSites/version.json b/arm/Microsoft.Web/staticSites/version.json new file mode 100644 index 0000000000..41f66cc990 --- /dev/null +++ b/arm/Microsoft.Web/staticSites/version.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "version": "0.1" +}