From d37e2e30ce67ff4e0af39641c1563a676e14d8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= Date: Wed, 18 Aug 2021 07:58:01 +0800 Subject: [PATCH 1/9] repo init --- .azuredevops/PULL_REQUEST_TEMPLATE.md | 22 + .github/CODEOWNERS | 12 + .github/ISSUE_TEMPLATE/BUG_REPORT.md | 20 + .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md | 13 + .github/PULL_REQUEST_TEMPLATE.md | 25 + .github/workflows/linter.yml | 19 + .github/workflows/workflow.yml | 25 + .pipelines/linter.yml | 17 + .pipelines/pipeline.yml | 31 + KeyVault/deploy.bicep | 277 ++++++++ KeyVault/deploy.json | 611 ++++++++++++++++++ ...e_location_KeyVault_PrivateEndpoints.bicep | 52 ++ KeyVault/nested_rbac_name.bicep | 12 + KeyVault/parameters.json | 68 ++ KeyVault/readme.md | 241 +++++++ README.md | 158 ++++- SUPPORT.md | 35 +- docs/README.md | 70 ++ docs/markdown-syntax-guide.md | 103 +++ docs/media/MicrosoftAzure-32px.png | Bin 0 -> 1020 bytes docs/media/MicrosoftPowerShellCore-32px.png | Bin 0 -> 1596 bytes 21 files changed, 1785 insertions(+), 26 deletions(-) create mode 100644 .azuredevops/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/BUG_REPORT.md create mode 100644 .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/linter.yml create mode 100644 .github/workflows/workflow.yml create mode 100644 .pipelines/linter.yml create mode 100644 .pipelines/pipeline.yml create mode 100644 KeyVault/deploy.bicep create mode 100644 KeyVault/deploy.json create mode 100644 KeyVault/nested_name_location_KeyVault_PrivateEndpoints.bicep create mode 100644 KeyVault/nested_rbac_name.bicep create mode 100644 KeyVault/parameters.json create mode 100644 KeyVault/readme.md create mode 100644 docs/README.md create mode 100644 docs/markdown-syntax-guide.md create mode 100644 docs/media/MicrosoftAzure-32px.png create mode 100644 docs/media/MicrosoftPowerShellCore-32px.png diff --git a/.azuredevops/PULL_REQUEST_TEMPLATE.md b/.azuredevops/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..38e357ab42 --- /dev/null +++ b/.azuredevops/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ +# Change + +***Feel free to remove this sample text*** +>Thank you for your contribution! Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. + +## Type of Change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update (Wiki) + +## Checklist + +- [ ] I'm sure there are no other open Pull Requests for the same update/change +- [ ] My corresponding Pipelines / Checks run clean and green without any errors or warnings +- [ ] My code follows the style guidelines of this project +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation (readme) +- [ ] I did format my code diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..6015116137 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,12 @@ +# See for instructions on this file + +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# @global-owner1 and @global-owner2 will be requested for +# review when someone opens a pull request. + +* @segraef + +.azuredevops/** @segraef +.github/** @segraef +.pipelines/** @segraef diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md new file mode 100644 index 0000000000..6a143da629 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md @@ -0,0 +1,20 @@ +--- +name: "Bug report \U0001F41B" +about: Report errors or unexpected behaviour +title: 'Bug Report' +labels: bug +assignees: '' +--- + + + +## Description + +Please describe your bug as detailed as possible. + +### Steps to reproduce + +1. +2. + +### Screenshots diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md new file mode 100644 index 0000000000..6fb906f01f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md @@ -0,0 +1,13 @@ +--- +name: "Feature request \U0001F680" +about: Suggest an idea for this project +title: 'Feature Request' +labels: feature +assignees: '' +--- + + + +## Description + +Please describe your request. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..a96c157b7f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,25 @@ +# Change + +***Feel free to remove this sample text*** +>Thank you for your contribution ! +Please include a summary of the change and which issue is fixed. +Please also include relevant motivation and context. +List any dependencies that are required for this change. + +## Type of Change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update (Wiki) + +## Checklist + +- [ ] I'm sure there are no other open Pull Requests for the same update/change +- [ ] My corresponding pipelines / checks run clean and green without any errors or warnings +- [ ] My code follows the style guidelines of this project +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation (readme) +- [ ] I did format my code diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000000..51c193be4b --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,19 @@ +name: Linter + +on: [pull_request] + +jobs: + build: + name: Linter + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v2 + + - name: Lint Code Base + uses: github/super-linter@v4.2.2 + env: + VALIDATE_ALL_CODEBASE: false + VALIDATE_MARKDOWN: false + DEFAULT_BRANCH: main + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 0000000000..51145b0d93 --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,25 @@ +name: "Sample Workflow" +on: + workflow_dispatch: + inputs: + name: + description: 'Person to greet' + required: true + default: 'You' + home: + description: 'location' + required: false + default: 'The Universe' + +jobs: + job: + name: "Job" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Hello + shell: pwsh + run: | + echo "Hello ${{ github.event.inputs.name }}!" + echo "- in ${{ github.event.inputs.home }}!" diff --git a/.pipelines/linter.yml b/.pipelines/linter.yml new file mode 100644 index 0000000000..968b5d12b5 --- /dev/null +++ b/.pipelines/linter.yml @@ -0,0 +1,17 @@ +name: SuperLinter + +trigger: +- main + +pool: + vmImage: ubuntu-latest + +jobs: + + - job: lint + displayName: Linter + steps: + - script: | + docker pull github/super-linter:latest + docker run -e RUN_LOCAL=true -v $(System.DefaultWorkingDirectory):/tmp/lint github/super-linter + displayName: 'Lint Code Base' \ No newline at end of file diff --git a/.pipelines/pipeline.yml b/.pipelines/pipeline.yml new file mode 100644 index 0000000000..bf35cc07cb --- /dev/null +++ b/.pipelines/pipeline.yml @@ -0,0 +1,31 @@ +name: "Sample Pipeline" + +trigger: +- main + +pool: + vmImage: ubuntu-latest + +jobs: + + - job: Job + displayName: "Job" + steps: + + - checkout: self + fetchDepth: 0 + persistCredentials: true + + - task: Bash@3 + displayName: "Bash" + inputs: + targetType: "inline" + script: | + echo Bash + + - task: PowerShell@2 + displayName: "PowerShell" + inputs: + targetType: "inline" + script: | + echo PowerShell diff --git a/KeyVault/deploy.bicep b/KeyVault/deploy.bicep new file mode 100644 index 0000000000..ae45815ea6 --- /dev/null +++ b/KeyVault/deploy.bicep @@ -0,0 +1,277 @@ +@description('Optional. Name of the Key Vault. If no name is provided, then unique name will be created.') +@maxLength(24) +param keyVaultName string = '' + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Array of access policies object') +param accessPolicies array = [] + +@description('Optional. All secrets [{"secretName":"","secretValue":""} wrapped in a secure object]') +@secure() +param secretsObject object = { + secrets: [] +} + +@description('Optional. All keys [{"keyName":"","keyType":"","keyOps":"","keySize":"","curvename":""} wrapped in a secure object]') +@secure() +param keysObject object = { + keys: [] +} + +@description('Optional. Specifies if the vault is enabled for deployment by script or compute') +@allowed([ + true + false +]) +param enableVaultForDeployment bool = true + +@description('Optional. Specifies if the vault is enabled for a template deployment') +@allowed([ + true + false +]) +param enableVaultForTemplateDeployment bool = true + +@description('Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios.') +@allowed([ + true + false +]) +param enableVaultForDiskEncryption bool = true + +@description('Optional. Switch to enable/disable Key Vault\'s soft delete feature.') +param enableSoftDelete bool = true + +@description('Optional. softDelete data retention days. It accepts >=7 and <=90.') +param softDeleteRetentionInDays int = 90 + +@description('Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored (warning: this is a preview feature). When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. If null or not specified, the vault is created with the default value of false. Note that management actions are always authorized with RBAC.') +param enableRbacAuthorization bool = false + +@description('Optional. The vault\'s create mode to indicate whether the vault need to be recovered or not. - recover or default.') +param createMode string = 'default' + +@description('Optional. Provide \'true\' to enable Key Vault\'s purge protection feature.') +param enablePurgeProtection bool = false + +@description('Optional. Specifies the SKU for the vault') +@allowed([ + 'Premium' + 'Standard' +]) +param vaultSku string = 'Premium' + +@description('Optional. Service endpoint object information') +param networkAcls object = {} + +@description('Optional. Virtual Network resource identifier, if networkAcls is passed, this value must be passed as well') +param vNetId string = '' + +@description('Optional. The name of the Diagnostic setting.') +param diagnosticSettingName string = 'service' + +@description('Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely.') +@minValue(0) +@maxValue(365) +param diagnosticLogsRetentionInDays int = 365 + +@description('Optional. Resource identifier of the Diagnostic Storage Account.') +param diagnosticStorageAccountId string = '' + +@description('Optional. Resource identifier of Log Analytics.') +param workspaceId string = '' + +@description('Optional. Resource ID of the event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') +param eventHubAuthorizationRuleId string = '' + +@description('Optional. Name of the event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category.') +param eventHubName string = '' + +@description('Optional. Switch to lock Key Vault from deletion.') +param lockForDeletion bool = false + +@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 = [] + +@description('Optional. Configuration Details for private endpoints.') +param privateEndpoints array = [] + +@description('Optional. Resource tags.') +param tags object = {} + +@description('Optional. Customer Usage Attribution id (GUID). This GUID must be previously registered') +param cuaId string = '' + +@description('Generated. Do not provide a value! This date value is used to generate a SAS token to access the modules.') +param baseTime string = utcNow('u') + +var moduleName = 'Key Vault' +var maxNameLength = 24 +var uniqueKeyVaultNameUntrim = uniqueString(concat(moduleName, baseTime)) +var uniqueKeyVaultName = ((length(uniqueKeyVaultNameUntrim) > maxNameLength) ? substring(uniqueKeyVaultNameUntrim, 0, maxNameLength) : uniqueKeyVaultNameUntrim) +var keyVaultName_var = (empty(keyVaultName) ? uniqueKeyVaultName : keyVaultName) +var deployServiceEndpoint = (!empty(networkAcls)) +var virtualNetworkRules = { + virtualNetworkRules: [for j in range(0, ((!deployServiceEndpoint) ? 0 : length(networkAcls.virtualNetworkRules))): { + id: '${vNetId}/subnets/${networkAcls.virtualNetworkRules[j].subnet}' + }] +} +var networkAcls_var = { + bypass: ((!deployServiceEndpoint) ? json('null') : networkAcls.bypass) + defaultAction: ((!deployServiceEndpoint) ? json('null') : networkAcls.defaultAction) + virtualNetworkRules: ((!deployServiceEndpoint) ? json('null') : ((length(networkAcls.virtualNetworkRules) == 0) ? emptyArray : virtualNetworkRules.virtualNetworkRules)) + ipRules: ((!deployServiceEndpoint) ? json('null') : ((length(networkAcls.ipRules) == 0) ? emptyArray : networkAcls.ipRules)) +} +var emptyArray = [] +var diagnosticsMetrics = [ + { + category: 'AllMetrics' + timeGrain: null + enabled: true + retentionPolicy: { + enabled: true + days: diagnosticLogsRetentionInDays + } + } +] +var diagnosticsLogs = [ + { + category: 'AuditEvent' + enabled: true + retentionPolicy: { + enabled: true + days: diagnosticLogsRetentionInDays + } + } +] +var builtInRoleNames = { + Owner: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635' + Contributor: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + Reader: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7' + 'Key Vault Administrator (preview)': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/00482a5a-887f-4fb3-b363-3b7fe8e74483' + 'Key Vault Certificates Officer (preview)': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/a4417e6f-fecd-4de8-b567-7b0420556985' + 'Key Vault Contributor': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/f25e0fa2-a7c8-4377-a976-54943a77a395' + 'Key Vault Crypto Officer (preview)': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/14b46e9e-c2b7-41b4-b07b-48a6ebf60603' + 'Key Vault Crypto Service Encryption User (preview)': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/e147488a-f6f5-4113-8e2d-b22465e65bf6' + 'Key Vault Crypto User (preview)': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/12338af0-0e69-4776-bea7-57ae8d297424' + 'Key Vault Reader (preview)': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/21090545-7ca7-4776-b22c-e363652d74d2' + 'Key Vault Secrets Officer (preview)': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/b86a8fe4-44ce-4948-aee5-eccb2c155cd7' + 'Key Vault Secrets User (preview)': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6' + 'Log Analytics Contributor': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293' + 'Log Analytics Reader': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/73c42c96-874c-492b-b04d-ab87d138a893' + 'Managed Application Contributor Role': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/641177b8-a67a-45b9-a033-47bc880bb21e' + 'Managed Application Operator Role': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/c7393b34-138c-406f-901b-d8cf2b17e6ae' + 'Managed Applications Reader': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/b9331d33-8a36-4f8c-b097-4f54124fdb44' + 'Monitoring Contributor': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa' + 'Monitoring Metrics Publisher': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/3913510d-42f4-4e42-8a64-420c390055eb' + 'Monitoring Reader': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/43d0d8ad-25c7-4714-9337-8ba259a9fe05' + 'Resource Policy Contributor': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/36243c78-bf99-498c-9df9-86d9f8d28608' + 'User Access Administrator': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + 'Azure Service Deploy Release Management Contributor': '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/21d96096-b162-414a-8302-d8354f9d91b2' + masterreader: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/a48d7796-14b4-4889-afef-fbb65a93e5a2' +} + +resource keyVaultName_resource 'Microsoft.KeyVault/vaults@2019-09-01' = { + name: keyVaultName_var + location: location + tags: tags + properties: { + enabledForDeployment: enableVaultForDeployment + enabledForTemplateDeployment: enableVaultForTemplateDeployment + enabledForDiskEncryption: enableVaultForDiskEncryption + enableSoftDelete: enableSoftDelete + softDeleteRetentionInDays: softDeleteRetentionInDays + enableRbacAuthorization: enableRbacAuthorization + createMode: createMode + enablePurgeProtection: ((!enablePurgeProtection) ? json('null') : enablePurgeProtection) + tenantId: subscription().tenantId + accessPolicies: accessPolicies + sku: { + name: vaultSku + family: 'A' + } + networkAcls: ((!deployServiceEndpoint) ? json('null') : networkAcls_var) + } +} + +resource keyVaultName_Microsoft_Authorization_keyVaultDoNotDelete 'Microsoft.KeyVault/vaults/providers/locks@2016-09-01' = if (lockForDeletion) { + name: '${keyVaultName_var}/Microsoft.Authorization/keyVaultDoNotDelete' + properties: { + level: 'CannotDelete' + } + dependsOn: [ + keyVaultName_resource + ] +} + +resource keyVaultName_Microsoft_Insights_diagnosticSettingName 'Microsoft.KeyVault/vaults/providers/diagnosticsettings@2017-05-01-preview' = if ((!empty(diagnosticStorageAccountId)) || (!empty(workspaceId)) || (!empty(eventHubAuthorizationRuleId)) || (!empty(eventHubName))) { + name: '${keyVaultName_var}/Microsoft.Insights/${diagnosticSettingName}' + location: location + properties: { + storageAccountId: (empty(diagnosticStorageAccountId) ? json('null') : diagnosticStorageAccountId) + workspaceId: (empty(workspaceId) ? json('null') : workspaceId) + eventHubAuthorizationRuleId: (empty(eventHubAuthorizationRuleId) ? json('null') : eventHubAuthorizationRuleId) + eventHubName: (empty(eventHubName) ? json('null') : eventHubName) + metrics: ((empty(diagnosticStorageAccountId) && empty(workspaceId) && empty(eventHubAuthorizationRuleId) && empty(eventHubName)) ? json('null') : diagnosticsMetrics) + logs: ((empty(diagnosticStorageAccountId) && empty(workspaceId) && empty(eventHubAuthorizationRuleId) && empty(eventHubName)) ? json('null') : diagnosticsLogs) + } + dependsOn: [ + keyVaultName_resource + ] +} + +resource secretsObject_secrets_keyVaultName_secretEntity_keyVaultName_secretsObject_secrets_secretName 'Microsoft.KeyVault/vaults/secrets@2019-09-01' = [for i in range(0, length(secretsObject.secrets)): if (!empty(secretsObject.secrets)) { + name: (empty(secretsObject.secrets) ? '${keyVaultName_var}/secretEntity' : '${keyVaultName_var}/${secretsObject.secrets[i].secretName}') + properties: { + value: secretsObject.secrets[i].secretValue + } + dependsOn: [ + keyVaultName_resource + ] +}] + +resource keysObject_keys_keyVaultName_keyEntity_keyVaultName_keysObject_keys_keyName 'Microsoft.KeyVault/vaults/keys@2019-09-01' = [for i in range(0, length(keysObject.keys)): if (!empty(keysObject.keys)) { + name: (empty(keysObject.keys) ? '${keyVaultName_var}/keyEntity' : '${keyVaultName_var}/${keysObject.keys[i].keyName}') + location: location + properties: { + kty: keysObject.keys[i].keyType + keyOps: keysObject.keys[i].keyOps + keySize: keysObject.keys[i].keySize + curveName: keysObject.keys[i].curveName + } + dependsOn: [ + keyVaultName_resource + ] +}] + +module name_location_KeyVault_PrivateEndpoints './nested_name_location_KeyVault_PrivateEndpoints.bicep' = [for (item, i) in privateEndpoints: { + name: '${uniqueString(deployment().name, location)}-KeyVault-PrivateEndpoints-${i}' + params: { + privateEndpointResourceId: keyVaultName_resource.id + privateEndpointVnetLocation: (empty(privateEndpoints) ? 'dummy' : reference(split(item.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location) + privateEndpoint: item + tags: tags + } + dependsOn: [ + keyVaultName_resource + ] +}] + +module rbac_name './nested_rbac_name.bicep' = [for (item, i) in roleAssignments: { + name: 'rbac-${deployment().name}${i}' + params: { + roleAssignment: item + builtInRoleNames: builtInRoleNames + keyVaultName: keyVaultName_var + } + dependsOn: [ + keyVaultName_resource + ] +}] + +output keyVaultResourceId string = keyVaultName_resource.id +output keyVaultResourceGroup string = resourceGroup().name +output keyVaultName string = keyVaultName_var +output keyVaultUrl string = reference(keyVaultName_resource.id, '2016-10-01').vaultUri \ No newline at end of file diff --git a/KeyVault/deploy.json b/KeyVault/deploy.json new file mode 100644 index 0000000000..45f0436a65 --- /dev/null +++ b/KeyVault/deploy.json @@ -0,0 +1,611 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "keyVaultName": { + "type": "string", + "defaultValue": "", + "maxLength": 24, + "metadata": { + "description": "Optional. Name of the Key Vault. If no name is provided, then unique name will be created." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "accessPolicies": { + "type": "array", + "defaultValue": [ + ], + "metadata": { + "description": "Optional. Array of access policies object" + } + }, + "secretsObject": { + "type": "secureObject", + "defaultValue": { + "secrets": [ + ] + }, + "metadata": { + "description": "Optional. All secrets [{\"secretName\":\"\",\"secretValue\":\"\"} wrapped in a secure object]" + } + }, + "keysObject": { + "type": "secureObject", + "defaultValue": { + "keys": [ + ] + }, + "metadata": { + "description": "Optional. All keys [{\"keyName\":\"\",\"keyType\":\"\",\"keyOps\":\"\",\"keySize\":\"\",\"curvename\":\"\"} wrapped in a secure object]" + } + }, + "enableVaultForDeployment": { + "type": "bool", + "defaultValue": true, + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "Optional. Specifies if the vault is enabled for deployment by script or compute" + } + }, + "enableVaultForTemplateDeployment": { + "type": "bool", + "defaultValue": true, + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "Optional. Specifies if the vault is enabled for a template deployment" + } + }, + "enableVaultForDiskEncryption": { + "type": "bool", + "defaultValue": true, + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." + } + }, + "enableSoftDelete": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Switch to enable/disable Key Vault's soft delete feature." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 90, + "metadata": { + "description": "Optional. softDelete data retention days. It accepts >=7 and <=90." + } + }, + "enableRbacAuthorization": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored (warning: this is a preview feature). When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. If null or not specified, the vault is created with the default value of false. Note that management actions are always authorized with RBAC." + } + }, + "createMode": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." + } + }, + "vaultSku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Specifies the SKU for the vault" + } + }, + "networkAcls": { + "type": "object", + "defaultValue": { + }, + "metadata": { + "description": "Optional. Service endpoint object information" + } + }, + "vNetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Virtual Network resource identifier, if networkAcls is passed, this value must be passed as well" + } + }, + "diagnosticSettingName": { + "type": "string", + "defaultValue": "service", + "metadata": { + "description": "Optional. The name of the Diagnostic setting." + } + }, + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "diagnosticStorageAccountId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource identifier of the Diagnostic Storage Account." + } + }, + "workspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource identifier of Log Analytics." + } + }, + "eventHubAuthorizationRuleId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category." + } + }, + "lockForDeletion": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Switch to lock Key Vault from deletion." + } + }, + "roleAssignments": { + "defaultValue": [ + ], + "type": "array", + "metadata": { + "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'" + } + }, + "privateEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Configuration Details for private endpoints." + } + }, + "tags": { + "type": "object", + "defaultValue": { + }, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "cuaId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Customer Usage Attribution id (GUID). This GUID must be previously registered" + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a SAS token to access the modules." + } + } + }, + + "variables": { + "moduleName": "Key Vault", + "maxNameLength": 24, + "uniqueKeyVaultNameUntrim": "[uniqueString(concat(variables('moduleName'),parameters('baseTime')))]", + "uniqueKeyVaultName": "[if(greater(length(variables('uniqueKeyVaultNameUntrim')),variables('maxNameLength')),substring(variables('uniqueKeyVaultNameUntrim'),0,variables('maxNameLength')),variables('uniqueKeyVaultNameUntrim'))]", + "keyVaultName": "[if(empty(parameters('keyVaultName')),variables('uniqueKeyVaultName'),parameters('keyVaultName'))]", + "deployServiceEndpoint": "[not(empty(parameters('networkAcls')))]", + "virtualNetworkRules": { + "copy": [ + { + "name": "virtualNetworkRules", + "count": "[if(not(variables('deployServiceEndpoint')), 0, length(parameters('networkAcls').virtualNetworkRules))]", + "input": { + "id": "[concat(parameters('vNetId'), '/subnets/', parameters('networkAcls').virtualNetworkRules[copyIndex('virtualNetworkRules')].subnet)]" + } + } + ] + }, + "networkAcls": { + "bypass": "[if(not(variables('deployServiceEndpoint')), json('null'), parameters('networkAcls').bypass)]", + "defaultAction": "[if(not(variables('deployServiceEndpoint')), json('null'), parameters('networkAcls').defaultAction)]", + "virtualNetworkRules": "[if(not(variables('deployServiceEndpoint')), json('null'), if(equals(length(parameters('networkAcls').virtualNetworkRules), 0), variables('emptyArray'), variables('virtualNetworkRules').virtualNetworkRules))]", + "ipRules": "[if(not(variables('deployServiceEndpoint')), json('null'), if(equals(length(parameters('networkAcls').ipRules), 0), variables('emptyArray'), parameters('networkAcls').ipRules))]" + }, + "emptyArray": [ + ], + "diagnosticsMetrics": [ + { + "category": "AllMetrics", + "timeGrain": null, + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + ], + "diagnosticsLogs": [ + { + "category": "AuditEvent", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + ], + "builtInRoleNames": { + "Owner": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Contributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Reader": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Key Vault Administrator (preview)": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Certificates Officer (preview)": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'a4417e6f-fecd-4de8-b567-7b0420556985')]", + "Key Vault Contributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer (preview)": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User (preview)": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User (preview)": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader (preview)": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer (preview)": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User (preview)": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Log Analytics Contributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Managed Application Contributor Role": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '641177b8-a67a-45b9-a033-47bc880bb21e')]", + "Managed Application Operator Role": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'c7393b34-138c-406f-901b-d8cf2b17e6ae')]", + "Managed Applications Reader": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b9331d33-8a36-4f8c-b097-4f54124fdb44')]", + "Monitoring Contributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Metrics Publisher": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Monitoring Reader": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Resource Policy Contributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '36243c78-bf99-498c-9df9-86d9f8d28608')]", + "User Access Administrator": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Azure Service Deploy Release Management Contributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '21d96096-b162-414a-8302-d8354f9d91b2')]", + "masterreader": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'a48d7796-14b4-4889-afef-fbb65a93e5a2')]" + } + }, + "resources": [ + // Key Vault + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2019-09-01", + "name": "[variables('keyVaultName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "enabledForDeployment": "[parameters('enableVaultForDeployment')]", + "enabledForTemplateDeployment": "[parameters('enableVaultForTemplateDeployment')]", + "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", + "enableSoftDelete": "[parameters('enableSoftDelete')]", + "softDeleteRetentionInDays": "[parameters('softDeleteRetentionInDays')]", + "enableRbacAuthorization": "[parameters('enableRbacAuthorization')]", + "createMode": "[parameters('createMode')]", + "enablePurgeProtection": "[if(not(parameters('enablePurgeProtection')), json('null'), parameters('enablePurgeProtection'))]", + "tenantId": "[subscription().tenantId]", + "accessPolicies": "[parameters('accessPolicies')]", + "sku": { + "name": "[parameters('vaultSku')]", + "family": "A" + }, + "networkAcls": "[if(not(variables('deployServiceEndpoint')), json('null'), variables('networkAcls'))]" + }, + "resources": [ + { + "type": "providers/locks", + "apiVersion": "2016-09-01", + "condition": "[parameters('lockForDeletion')]", + "name": "Microsoft.Authorization/keyVaultDoNotDelete", + "dependsOn": [ + "[concat('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]" + ], + "comments": "Resource lock on Azure Key Vault", + "properties": { + "level": "CannotDelete" + } + }, + { + "type": "Microsoft.KeyVault/vaults/providers/diagnosticsettings", + "apiVersion": "2017-05-01-preview", + "name": "[concat(variables('keyVaultName'), '/Microsoft.Insights/', parameters('diagnosticSettingName'))]", + "location": "[parameters('location')]", + "condition": "[or(not(empty(parameters('diagnosticStorageAccountId'))),not(empty(parameters('workspaceId'))),not(empty(parameters('eventHubAuthorizationRuleId'))),not(empty(parameters('eventHubName'))))]", + "dependsOn": [ + "[concat('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]" + ], + "properties": { + "storageAccountId": "[if(empty(parameters('diagnosticStorageAccountId')), json('null'), parameters('diagnosticStorageAccountId'))]", + "workspaceId": "[if(empty(parameters('workspaceId')), json('null'), parameters('workspaceId'))]", + "eventHubAuthorizationRuleId": "[if(empty(parameters('eventHubAuthorizationRuleId')), json('null'), parameters('eventHubAuthorizationRuleId'))]", + "eventHubName": "[if(empty(parameters('eventHubName')), json('null'), parameters('eventHubName'))]", + "metrics": "[if(and(empty(parameters('diagnosticStorageAccountId')), empty(parameters('workspaceId')), empty(parameters('eventHubAuthorizationRuleId')), empty(parameters('eventHubName'))), json('null'), variables('diagnosticsMetrics'))]", + "logs": "[if(and(empty(parameters('diagnosticStorageAccountId')), empty(parameters('workspaceId')), empty(parameters('eventHubAuthorizationRuleId')), empty(parameters('eventHubName'))), json('null'), variables('diagnosticsLogs'))]" + } + } + ] + }, + // Key Vault Secrets + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2019-09-01", + "condition": "[not(empty(parameters('secretsObject').secrets))]", + "name": "[if(empty(parameters('secretsObject').secrets), concat(variables('keyVaultName'), '/', 'secretEntity'), concat(variables('keyVaultName'), '/', parameters('secretsObject').secrets[copyIndex()].secretName))]", + "properties": { + "value": "[parameters('secretsObject').secrets[copyIndex()].secretValue]" + }, + "dependsOn": [ + "[concat('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]" + ], + "copy": { + "name": "secretsCopy", + "count": "[length(parameters('secretsObject').secrets)]" + } + }, + // Key Vault Keys + { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2019-09-01", + "condition": "[not(empty(parameters('keysObject').keys))]", + "name": "[if(empty(parameters('keysObject').keys), concat(variables('keyVaultName'), '/', 'keyEntity'), concat(variables('keyVaultName'), '/', parameters('keysObject').keys[copyIndex()].keyName))]", + "location": "[parameters('location')]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]" + ], + "properties": { + "kty": "[parameters('keysObject').keys[copyIndex()].keyType]", + "keyOps": "[parameters('keysObject').keys[copyIndex()].keyOps]", + "keySize": "[parameters('keysObject').keys[copyIndex()].keySize]", + "curveName": "[parameters('keysObject').keys[copyIndex()].curveName]" + }, + "copy": { + "name": "keyCopy", + "count": "[length(parameters('keysObject').keys)]" + } + }, + // Private Endpoints + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2020-06-01", + "name": "[concat(uniqueString(deployment().name, parameters('location')), '-KeyVault-PrivateEndpoints','-',copyIndex())]", + "condition": "[not(empty(parameters('privateEndpoints')))]", + "dependsOn": [ + "[variables('keyVaultName')]" + ], + "copy": { + "name": "privateEndpointsCopy", + "count": "[length(parameters('privateEndpoints'))]" + }, + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "parameters": { + "privateEndpointResourceId": { + "value": "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]" + }, + "privateEndpointVnetLocation": { + "value": "[if(empty(parameters('privateEndpoints')),'dummy',reference(split(parameters('privateEndpoints')[copyIndex()].subnetResourceId,'/subnets/')[0],'2020-06-01', 'Full').location)]" + }, + "privateEndpoint": { + "value": "[parameters('privateEndpoints')[copyIndex()]]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "privateEndpointResourceId": { + "type": "string" + }, + "privateEndpointVnetLocation": { + "type": "string" + }, + "privateEndpoint": { + "type": "object" + }, + "tags": { + "type": "object" + } + }, + "variables": { + "privateEndpointResourceName": "[last(split(parameters('privateEndpointResourceId'),'/'))]", + "privateEndpoint": { + "name": "[if(contains(parameters('privateEndpoint'), 'name'),if(empty(parameters('privateEndpoint').name),concat(variables('privateEndpointResourceName'),'-',parameters('privateEndpoint').service),parameters('privateEndpoint').name),concat(variables('privateEndpointResourceName'),'-',parameters('privateEndpoint').service))]", + "subnetResourceId": "[parameters('privateEndpoint').subnetResourceId]", + "service": [ + "[parameters('privateEndpoint').service]" + ], + "privateDnsZoneResourceIds": "[if(contains(parameters('privateEndpoint'), 'privateDnsZoneResourceIds'),if(empty(parameters('privateEndpoint').privateDnsZoneResourceIds),createArray(),parameters('privateEndpoint').privateDnsZoneResourceIds),createArray())]", + "customDnsConfigs": "[if(contains(parameters('privateEndpoint'), 'customDnsConfigs'),if(empty(parameters('privateEndpoint').customDnsConfigs),json('null'),parameters('privateEndpoint').customDnsConfigs),json('null'))]" + } + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2020-05-01", + "name": "[variables('privateEndpoint').name]", + "location": "[parameters('privateEndpointVnetLocation')]", + "tags": "[parameters('tags')]", + "properties": { + "privateLinkServiceConnections": [ + { + "name": "[variables('privateEndpoint').name]", + "properties": { + "privateLinkServiceId": "[parameters('privateEndpointResourceId')]", + "groupIds": "[variables('privateEndpoint').service]" + } + } + ], + "manualPrivateLinkServiceConnections": [], + "subnet": { + "id": "[variables('privateEndpoint').subnetResourceId]" + }, + "customDnsConfigs": "[variables('privateEndpoint').customDnsConfigs]" + } + }, + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2020-05-01", + "condition": "[not(empty(variables('privateEndpoint').privateDnsZoneResourceIds))]", + "name": "[concat(variables('privateEndpoint').name, '/default')]", + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpoint').name)]" + ], + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(variables('privateEndpoint').privateDnsZoneResourceIds)]", + "input": { + "name": "[last(split(variables('privateEndpoint').privateDnsZoneResourceIds[copyIndex('privateDnsZoneConfigs')],'/'))]", + "properties": { + "privateDnsZoneId": "[variables('privateEndpoint').privateDnsZoneResourceIds[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + } + } + ] + } + } + }, + // RBAC + { + "name": "[concat('rbac-',deployment().name, copyIndex())]", + "apiVersion": "2020-06-01", + "type": "Microsoft.Resources/deployments", + "condition": "[not(empty(parameters('roleAssignments')))]", + "dependsOn": [ + "[variables('keyVaultName')]" + ], + "copy": { + "name": "rbacDeplCopy", + "count": "[length(parameters('roleAssignments'))]" + }, + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "parameters": { + "roleAssignment": { + "value": "[parameters('roleAssignments')[copyIndex()]]" + }, + "builtInRoleNames": { + "value": "[variables('builtInRoleNames')]" + }, + "keyVaultName": { + "value": "[variables('keyVaultName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "roleAssignment": { + "type": "object" + }, + "builtInRoleNames": { + "type": "object" + }, + "keyVaultName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/providers/roleAssignments", + "apiVersion": "2018-09-01-preview", + "name": "[concat(parameters('keyVaultName'), '/Microsoft.Authorization/', guid(uniqueString(concat(parameters('keyVaultName'), array(parameters('roleAssignment').principalIds)[copyIndex('innerRbacCopy')], parameters('roleAssignment').roleDefinitionIdOrName ) )))]", + "dependsOn": [ + ], + "copy": { + "name": "innerRbacCopy", + "count": "[length(parameters('roleAssignment').principalIds)]" + }, + "properties": { + "roleDefinitionId": "[if(contains(parameters('builtInRoleNames'), parameters('roleAssignment').roleDefinitionIdOrName ), parameters('builtInRoleNames')[parameters('roleAssignment').roleDefinitionIdOrName] , parameters('roleAssignment').roleDefinitionIdOrName )]", + "principalId": "[array(parameters('roleAssignment').principalIds)[copyIndex()]]" + } + } + ] + } + } + } + ], + "functions": [ + ], + "outputs": { + "keyVaultResourceId": { + "type": "string", + "value": "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", + "metadata": { + "description": "The Resource Id of the Key Vault." + } + }, + "keyVaultResourceGroup": { + "type": "string", + "value": "[resourceGroup().name]", + "metadata": { + "description": "The name of the Resource Group the Key Vault was created in." + } + }, + "keyVaultName": { + "type": "string", + "value": "[variables('keyVaultName')]", + "metadata": { + "description": "The Name of the Key Vault." + } + }, + "keyVaultUrl": { + "type": "string", + "value": "[reference(resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName')),'2016-10-01').vaultUri]", + "metadata": { + "description": "The URL of the Key Vault." + } + } + } +} diff --git a/KeyVault/nested_name_location_KeyVault_PrivateEndpoints.bicep b/KeyVault/nested_name_location_KeyVault_PrivateEndpoints.bicep new file mode 100644 index 0000000000..4a16ebcc28 --- /dev/null +++ b/KeyVault/nested_name_location_KeyVault_PrivateEndpoints.bicep @@ -0,0 +1,52 @@ +param privateEndpointResourceId string +param privateEndpointVnetLocation string +param privateEndpoint object +param tags object + +var privateEndpointResourceName = last(split(privateEndpointResourceId, '/')) +var privateEndpoint_var = { + name: (contains(privateEndpoint, 'name') ? (empty(privateEndpoint.name) ? '${privateEndpointResourceName}-${privateEndpoint.service}' : privateEndpoint.name) : '${privateEndpointResourceName}-${privateEndpoint.service}') + subnetResourceId: privateEndpoint.subnetResourceId + service: [ + privateEndpoint.service + ] + privateDnsZoneResourceIds: (contains(privateEndpoint, 'privateDnsZoneResourceIds') ? (empty(privateEndpoint.privateDnsZoneResourceIds) ? createArray() : privateEndpoint.privateDnsZoneResourceIds) : createArray()) + customDnsConfigs: (contains(privateEndpoint, 'customDnsConfigs') ? (empty(privateEndpoint.customDnsConfigs) ? json('null') : privateEndpoint.customDnsConfigs) : json('null')) +} + +resource privateEndpoint_name 'Microsoft.Network/privateEndpoints@2020-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 privateEndpoint_name_default 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2020-05-01' = if (!empty(privateEndpoint_var.privateDnsZoneResourceIds)) { + name: '${privateEndpoint_var.name}/default' + properties: { + privateDnsZoneConfigs: [for j in range(0, length(privateEndpoint_var.privateDnsZoneResourceIds)): { + name: last(split(privateEndpoint_var.privateDnsZoneResourceIds[j], '/')) + properties: { + privateDnsZoneId: privateEndpoint_var.privateDnsZoneResourceIds[j] + } + }] + } + dependsOn: [ + privateEndpoint_name + ] +} \ No newline at end of file diff --git a/KeyVault/nested_rbac_name.bicep b/KeyVault/nested_rbac_name.bicep new file mode 100644 index 0000000000..102fd302d2 --- /dev/null +++ b/KeyVault/nested_rbac_name.bicep @@ -0,0 +1,12 @@ +param roleAssignment object +param builtInRoleNames object +param keyVaultName string + +resource keyVaultName_Microsoft_Authorization_keyVaultName_roleAssignment_principalIds_innerRbacCopy_roleAssignment_roleDefinitionIdOrName 'Microsoft.KeyVault/vaults/providers/roleAssignments@2018-09-01-preview' = [for i in range(0, length(roleAssignment.principalIds)): { + name: '${keyVaultName}/Microsoft.Authorization/${guid(uniqueString(concat(keyVaultName, array(roleAssignment.principalIds)[i], roleAssignment.roleDefinitionIdOrName)))}' + properties: { + roleDefinitionId: (contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : roleAssignment.roleDefinitionIdOrName) + principalId: array(roleAssignment.principalIds)[i] + } + dependsOn: [] +}] \ No newline at end of file diff --git a/KeyVault/parameters.json b/KeyVault/parameters.json new file mode 100644 index 0000000000..fbcfd5abf6 --- /dev/null +++ b/KeyVault/parameters.json @@ -0,0 +1,68 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "keyVaultName": { + "value": "sxx-az-kv-weu-x-001" + }, + "keysObject": { + "value": { + "keys": [ + { + "keyName": "keyRSA", + "keyType": "RSA", + "keyOps": [ + "encrypt", + "decrypt", + "sign", + "verify", + "wrapKey", + "unwrapKey" + ], + "keySize": "2048", + "curveName": "" + } + ] + } + }, + "accessPolicies": { + "value": [ + { + "tenantId": "", + "objectId": "", + "permissions": { + "certificates": ["All"], + "keys": ["All"], + "secrets": ["All"] + } + }, + { + "tenantId": "", + "objectId": "", + "permissions": { + "certificates": ["All"], + "keys": ["All"], + "secrets": ["All"] + } + } + ] + }, + "enableSoftDelete": { + "value": true + }, + "softDeleteRetentionInDays": { + "value": 7 + }, +// "networkAcls": { +// "value": { +// "bypass": "AzureServices", +// "defaultAction": "Deny", +// "virtualNetworkRules": [], +// "ipRules": [] +// } +// }, + "enableRbacAuthorization": { + "value": false + } + } +} \ No newline at end of file diff --git a/KeyVault/readme.md b/KeyVault/readme.md new file mode 100644 index 0000000000..07585e3c87 --- /dev/null +++ b/KeyVault/readme.md @@ -0,0 +1,241 @@ +# KeyVault + +This module deploys Key Vault, with resource lock. + +## Resource types + +| Resource Type | Api Version | +| :-- | :-- | +| `Microsoft.KeyVault/vaults/keys` | 2019-09-01 | +| `Microsoft.KeyVault/vaults/providers/diagnosticsettings` | 2017-05-01-preview | +| `Microsoft.KeyVault/vaults/providers/roleAssignments` | 2018-09-01-preview | +| `Microsoft.KeyVault/vaults/secrets` | 2019-09-01 | +| `Microsoft.KeyVault/vaults` | 2019-09-01 | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | 2020-05-01 | +| `Microsoft.Network/privateEndpoints` | 2020-05-01 | +| `Microsoft.Resources/deployments` | 2020-06-01 | +| `providers/locks` | 2016-09-01 | + +## Parameters + +| Parameter Name | Type | Default Value | Possible values | Description | +| :- | :- | :- | :- | :- | +| `keyVaultName` | string | | | Optional. Name of the Key Vault Name. If no name is provided, then unique name will be created.| +| `location` | string | `[resourceGroup().location]` | | Optional. Location for all resources. +| `accessPolicies` | object | `{}` | Complex structure, see below. | Optional. Access policies object +| `secretsObject` | object | `{}` | Complex structure, see below. | Optional. All secrets {\"secretName\":\"\",\"secretValue\":\"\"} wrapped in a secure object +| `keysObject` | object | `{}` | Complex structure, see below. | Optional. All secrets {\"secretName\":\"\",\"secretValue\":\"\"} wrapped in a secure object +| `enableVaultForDeployment` | bool | `true` | | Optional. Specifies if the vault is enabled for deployment by script or compute +| `enableVaultForTemplateDeployment` | bool | `true` | | Optional. Specifies if the vault is enabled for a template deployment +| `enableVaultForDiskEncryption` | bool | `true` | | Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios. +| `enableSoftDelete` | bool | `true` | | Optional. Switch to enable Key Vault's soft delete feature. +| `softDeleteRetentionInDays` | int | 90 | | Optional. softDelete data retention days. It accepts >=7 and <=90. +| `enableRbacAuthorization` | bool | `false` | | Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored (warning: this is a preview feature). When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. If null or not specified, the vault is created with the default value of false. Note that management actions are always authorized with RBAC. +| `createMode` | bool | `true` | | Optional. The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default. +| `enablePurgeProtection` | bool | `false` | | Optional. Switch to enable Key Vault's purge protection feature. +| `vaultSku` | string | `Premium` | Premium, Standard |Optional. Specifies the SKU for the vault +| `vNetId` | string | "" | | Optional. Virtual Network Identifier used to create a service endpoint. +| `networkAcls` | object | {} | Complex structure, see below. | Optional. Network ACLs, this value contains IPs to whitelist and/or Subnet information. +| `diagnosticSettingName` | string | `service` | | Optional. The name of the Diagnostic setting. +| `diagnosticLogsRetentionInDays` | int | `365` | | Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely. +| `diagnosticStorageAccountId` | string | "" | | Optional. Resource identifier of the Diagnostic Storage Account. +| `workspaceId` | string | "" | | Optional. Resource identifier of Log Analytics. +| `eventHubAuthorizationRuleId` | string | "" | | Optional. Resource ID of the event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. +| `eventHubName` | string | "" | | Optional. Name of the event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. +| `lockForDeletion` | bool | `true` | | Optional. Switch to lock Azure Key Vault from deletion. +| `roleAssignments` | array | [] | Complex structure, see below. | 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 it's fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11' +| `privateEndpoints` | array | System.Object[] | | Optional. Configuration Details for private endpoints. | +| `tags` | object | {} | Complex structure, see below. | Optional. Tags of the Azure Key Vault resource. +| `cuaId` | string | "" | | Optional. Customer Usage Attribution id (GUID). This GUID must be previously registered. +| `baseTime` | string | utcNow('u') | | Generated. Do not provide a value! This date value is used to generate a SAS token toaccess the modules. + +### Parameter Usage: `roleAssignments` + +```json +"roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Desktop Virtualization User", + "principalIds": [ + "12345678-1234-1234-1234-123456789012", // object 1 + "78945612-1234-1234-1234-123456789012" // object 2 + ] + }, + { + "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: `networkAcls` + +```json +"networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "Deny", + "virtualNetworkRules": [ + { + "subnet": "sharedsvcs" + } + ], + "ipRules": [] + } +} +``` + +### Parameter Usage: `vNetId` + +```json +"vNetId": { + "value": "/subscriptions/00000000/resourceGroups/resourceGroup" +} +``` + +### Parameter Usage: `accessPolicies` + +```json +"accessPolicies": { + "value": [ + { + "tenantId": null, + "objectId": null, + "permissions": { + "certificates": [ + "All" + ], + "keys": [ + "All" + ], + "secrets": [ + "All" + ] + } + } + ] +} +``` + +### Parameter Usage: `secretsObject` + +```json +"secretsObject": { + "value": { + "secrets": [ + { + "secretName": "Secret--AzureAd--Domain", + "secretValue": "Some value" + } + ] + } +} +``` + +### Parameter Usage: `keysObject` + +```json +"keysObject": { + "value": { + "keys": [ + { + "keyName": "keyRSA", // The name of the key to be created + "keyType": "RSA", // The JsonWebKeyType of the key to be created + "keyOps": [ //The permitted JSON web key operations of the key to be created + "encrypt", + "decrypt", + "sign", + "verify", + "wrapKey", + "unwrapKey" + ], + "keySize": "2048", //The size in bits of the key to be created + "curveName": "" // The JsonWebKeyCurveName of the key to be created + } + ] + } +} +``` + +### 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 recommened 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-sa-cac-y-123-pe", // Optional: Name will be automatically generated if one is not provided here + "subnetResourceId": "/subscriptions/xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/sxx-az-vnet-weu-x-001/subnets/sxx-az-subnet-weu-x-001", + "service": "vault", + "privateDnsZoneResourceIds": [ // Optional: No DNS record will be created if a private DNS zone Resource ID is not specified + "/subscriptions/xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx/resourceGroups/validation-rg/providers/Microsoft.Network/privateDnsZones/privatelink.vaultcore.azure.net" + ], + "customDnsConfigs": [ // Optional + { + "fqdn": "customname.test.local", + "ipAddresses": [ + "10.10.10.10" + ] + } + ] + } + ] +} +``` + +## Outputs + +| Output Name | Type | Description | +| :-- | :-- | :-- | +| `keyVaultName` | string | The Name of the Key Vault. | +| `keyVaultResourceGroup` | string | The name of the Resource Group the Key Vault was created in. | +| `keyVaultResourceId` | string | The Resource Id of the Key Vault. | +| `keyVaultUrl` | string | The URL of the Key Vault. | + +## Considerations + +**N/A* + +## Additional resources + +- [What is Azure Key Vault?](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-whatis) +- [Microsoft.KeyVault vaults template reference](https://docs.microsoft.com/en-us/azure/templates/microsoft.keyvault/2018-02-14/vaults) +- [Use tags to organize your Azure resources](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-using-tags) +- [Deployments](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Resources/2020-06-01/deployments) +- [Vaults](https://docs.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2019-09-01/vaults) +- [Vaults](https://docs.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2019-09-01/vaults/secrets) +- [Vaults](https://docs.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2019-09-01/vaults/keys) +- [Deployments](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Resources/2020-06-01/deployments) \ No newline at end of file diff --git a/README.md b/README.md index 5cd7cecfc8..19d5976aeb 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,120 @@ -# Project +# ![AzureIcon] Modules -> This repo has been populated by an initial template to help get you started. Please -> make sure to update the content to build a great experience for community-building. +This repository consists of a collection of compliant [Azure Resource Manager (ARM)][AzureResourceManager] and [Bicep][Bicep] templates as well as [template specs](). -As the maintainer of this project, please make a few updates: +## Description -- Improving this README.MD file to provide a great experience -- Updating SUPPORT.MD with content about this project's support experience -- Understanding the security reporting process in SECURITY.MD -- Remove this section from the README +## Status + +[![Super Linter]()]() + +[![Sample Workflow]()]() + +## Getting Started + +This is an example of how you may give instructions on setting up your project locally. +To get a local copy up and running follow these simple example steps. + +### Prerequisites + +To be able to deploy [ARM][AzureResourceManager] templates you should have latest version [PowerShell 7][PowerShellDocs] + [Azure Az Module][InstallAzPs] or [Azure CLI]()as well as [Bicep][Bicep] installed. + +### Installation + +#### One-liner to install or update Azure CLI on Windows 10 + +```PowerShell +iwr https://aka.ms/installazurecliwindows -OutFile .\AzureCLI.msi; start msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet'; rm .\AzureCLI.msi +``` + +#### One-liner to install or update Azure CLI on Linux +```bash +curl -L https://aka.ms/InstallAzureCli | bash +``` + +# One-liner to install or update PowerShell 7 on Windows 10 + +```PowerShell +iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI" +Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force +``` + +Make sure to install Azure Az Module as well. + +```PowerShell +iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI" +Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force +``` + +### Usage + +#### Deploy local template (Azure CLI) + +```bash +az group create --name ExampleGroup --location "Central US" +az deployment group create \ + --name ExampleDeployment \ + --resource-group ExampleGroup \ + --template-file \ + --parameters storageAccountType=Standard_GRS +``` + +#### Deploy local template (PowerShell) + +```PowerShell +New-AzResourceGroup -Name ExampleGroup -Location "Central US" +New-AzResourceGroupDeployment ` + -Name ExampleDeployment ` + -ResourceGroupName ExampleGroup ` + -TemplateFile +``` + +#### Deploy remote template (Azure CLI) + +```bash +az group create --name ExampleGroup --location "Central US" +az deployment group create \ + --name ExampleDeployment \ + --resource-group ExampleGroup \ + --template-uri "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.storage/storage-account-create/azuredeploy.json" \ + --parameters storageAccountType=Standard_GRS +``` + +#### Deploy remote template (PowerShell) + +```PowerShell +New-AzResourceGroup -Name ExampleGroup -Location "Central US" +New-AzResourceGroupDeployment ` + -Name remoteTemplateDeployment ` + -ResourceGroupName ExampleGroup ` + -TemplateUri https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.storage/storage-account-create/azuredeploy.json +``` + +## FAQ and Known Issues + +Any advise for common problems or issues. + ```bash + command to run if program contains helper info + ``` + +## Reporting Issues and Feedback + +### Issues and Bugs + +If you find any bugs, please file an issue in the [GitHub Issues][GitHubIssues] page. Please search the existing issues before filing new issues to avoid duplicates. Please fill out the provided template with the appropriate information. + +If you are taking the time to mention a problem, even a seemingly minor one, it is greatly appreciated, and a totally valid contribution to this project. **Thank you!** + +### Feedback + +If there is a feature you would like to see in here, please file an issue or feature request in the [GitHub Issues][GitHubIssues] page to provide direct feedback. + +## Contributors + +Contributors names and contact info + +* You, Yourself and the Universe +* [@your_twitter]() ## Contributing @@ -26,8 +132,40 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio ## Trademarks -This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft -trademarks or logos is subject to and must follow +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft +trademarks or logos is subject to and must follow [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies. + +## Learn More + +* [PowerShell Documentation][PowerShellDocs] +* [Microsoft Azure Documentation][MicrosoftAzureDocs] +* [Azure Resource Manager][AzureResourceManager] +* [Bicep][Bicep] + + + + +[ProjectSetup]: +[CreateFromTemplate]: +[GitHubDocs]: +[AzureDevOpsDocs]: +[GitHubIssues]: +[Contributing]: CONTRIBUTING.md +[AzureIcon]: docs/media/MicrosoftAzure-32px.png +[PowershellIcon]: docs/media/MicrosoftPowerShellCore-32px.png +[BashIcon]: docs/media/Bash_Logo_black_and_white_icon_only-32px.svg.png + + +[Bicep]: +[Az]: +[AzGallery]: +[PowerShellCore]: +[InstallAzPs]: +[AzureResourceManager]: + + +[MicrosoftAzureDocs]: +[PowerShellDocs]: \ No newline at end of file diff --git a/SUPPORT.md b/SUPPORT.md index dc72f0e5a0..e714e2a415 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -1,25 +1,28 @@ -# TODO: The maintainer of this repo has not yet edited this file +# Support -**REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? +## Reporting Issues and Feedback -- **No CSS support:** Fill out this template with information about how to file issues and get help. -- **Yes CSS support:** Fill out an intake form at [aka.ms/spot](https://aka.ms/spot). CSS will work with/help you to determine next steps. More details also available at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). -- **Not sure?** Fill out a SPOT intake as though the answer were "Yes". CSS will help you decide. +### Issues and Bugs -*Then remove this first heading from this SUPPORT.MD file before publishing your repo.* +If you find any bugs, please file an issue in the [GitHub Issues][GitHubIssues] page. Please search the existing issues before filing new issues to avoid duplicates. Please fill out the provided template with the appropriate information. -# Support +If you are taking the time to mention a problem, even a seemingly minor one, it is greatly appreciated, and a totally valid contribution to this project. **Thank you!** -## How to file issues and get help +## Feedback -This project uses GitHub Issues to track bugs and feature requests. Please search the existing -issues before filing new issues to avoid duplicates. For new issues, file your bug or -feature request as a new Issue. +If there is a feature you would like to see in here, please file an issue or feature request in the [GitHub Issues][GitHubIssues] page to provide direct feedback. -For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE -FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER -CHANNEL. WHERE WILL YOU HELP PEOPLE?**. +## Microsoft Support Policy -## Microsoft Support Policy +Support for this **PROJECT** is limited to the resources listed above. + -Support for this **PROJECT or PRODUCT** is limited to the resources listed above. + +[ProjectSetup]: +[AzureDevOpsDocs]: +[GitHubIssues]: +[Contributing]: CONTRIBUTING.md +[AzureIcon]: docs/media/MicrosoftAzure-32px.png +[PowershellIcon]: docs/media/MicrosoftPowerShellCore-32px.png +[BashIcon]: docs/media/Bash_Logo_black_and_white_icon_only-32px.svg.png \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..2b599c0a49 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,70 @@ +# Project Title + +Simple overview of your project and its use or purpose. + +>Make use of the [Markdow Syntax Guide](markdown-syntax-guide.md). + +## Description + +Describe your project. + +## Getting Started + +This is an example of how you may give instructions on setting up your project locally. +To get a local copy up and running follow these simple example steps. + +### Prerequisites + +Describe any prerequisites or dependencies. + +### Installation + +* How/where to download your program +* Any modifications needed to be made to files/folders + + ```bash + iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI" + ``` + +## Usage + +Use this space to show useful examples of how a project can be used. Additional screenshots, code examples and demos work well in this space. You may also link to more resources. + +_For more examples, please refer to the [Documentation](https://example.com)_ + + +## FAQ and Known Issues + +Any advise for common problems or issues. + ```bash + command to run if program contains helper info + ``` + +## Contributors + +Contributors names and contact info + +* You, Yourself and the Universe +* [@your_twitter]() + +## Contribution + +If you would like to become an active contributor to this repository or project, please follow the instructions provided in [`CONTRIBUTING.md`](../CONTRIBUTING.md). + + +## Contact + +Your Name - [@your_twitter]() - email@example.com + +Project Link: [https://github.com/your_username/repo_name]() + + + +## License + +Distributed under the MIT License. See [`LICENSE`](`../../LICENSE`). + +## References + +* [Emoji Cheat Sheet]() +* [License Helper]() diff --git a/docs/markdown-syntax-guide.md b/docs/markdown-syntax-guide.md new file mode 100644 index 0000000000..1c1dbed1b2 --- /dev/null +++ b/docs/markdown-syntax-guide.md @@ -0,0 +1,103 @@ +# Markdown Syntax Guide + +This article offers a sample of basic Markdown syntax that can be used in content files, also it shows whether basic HTML elements are decorated with CSS. + + +## Headings + +The following HTML `

`—`

` elements represent six levels of section headings. `

` is the highest section level while `

` is the lowest. + +## H2 +### H3 +#### H4 +##### H5 +###### H6 + +## Paragraph + +Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. + +Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat. + +Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat. + +## Blockquotes + +The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a `footer` or `cite` element, and optionally with in-line changes such as annotations and abbreviations. + +### Blockquote without attribution + +> Tiam, ad mint andaepu dandae nostion secatur sequo quae. +> **Note** that you can use *Markdown syntax* within a blockquote. + +#### Blockquote with attribution + +> Simplicity is the ultimate sophistication. +> Leonardo da Vinci[^1] + +[^1]: The above quote is often attributed to Leonardo da Vinci but there is no concrete evidence to support this. + + +## Tables + + Name | Age +--------|------ + Bob | 27 + Alice | 23 + +### Inline Markdown within tables + +
+ +| Inline    | Markdown    | In    | Table | +| ---------- | --------- | ----------------- | ---------- | +| *italics* | **bold** | ~~strikethrough~~    | `code` | + +
+ +## Code Blocks + +### Code block indented with four spaces + + + + + + Example HTML5 Document + + +

Test

+ + + +## List Types + +### Ordered List + +1. First item +2. Second item +3. Third item + +### Unordered List + +* List item +* Another item +* And another item + +### Nested list + +* Item +1. First Sub-item +2. Second Sub-item + +## Other Elements — abbr, sub, sup, kbd, mark + +GIF is a bitmap image format. + +H2O + +Xn + Yn = Zn + +Press CTRL+ALT+Delete to end the session. + +Most salamanders are nocturnal, and hunt for insects, worms, and other small creatures. \ No newline at end of file diff --git a/docs/media/MicrosoftAzure-32px.png b/docs/media/MicrosoftAzure-32px.png new file mode 100644 index 0000000000000000000000000000000000000000..20479a035301c7d0e042e08bf90d6b5f424f3911 GIT binary patch literal 1020 zcmV003M>0c&c2$N&HU7<5HgbW?9;ba!ELWdLwtX>N2bZe?^J zG%hhNHDpIvQUCx0dPzhMI2znBeCV5$F+Pc(MMHJMYG}?;?w@al|!R4apo0*ryh+3qsxFIh1{N_24m`+lI z6%_h||KWY_o9{pKW_zj;M))tNIrB(U+KiVN1+ry~53iqpBs_(^`nznuAmtQzu_xOm zzESNK<(M)+dV%znw}t1h)Zu4Y*V8>+n?qG*530*|;*)Bt_(g3+ zpNf6Bnl%|-Om5Oe&CMQiz}X|KS@J(+gCAZpP=wOY6XQr?y7svGnB75yEFaqcpPPTP7FU1|z7R z3JOBUSlTa4-%l2)ZQ|QR(?r2K`8Z{7col2Lr^H7#(qyxjoTgubg_E-6SY&LL4Gkok zB@=wrH?uk)Ok~XmqjTb`Q1E@#iKvlR00TLwbCJUno1>Nz zzqB>ckSC*CYE_I1eNqPvz}9-6Cy+y9eMCq{8VAO)qFM(E_rS@ivEyhgmP~YUDjlF_ zL7|5vFPN&=N(W-l0S&Y`^eApYKE`hmygCy*puVm-s^Ki~MBECb&gSaDnj*6P544mzf_3`dS%0Qy~fMo$r1={W>$R0c<~Ni!{Jb#6ZH;xW77Ws*j`t71^z_v zgL7wQyHvnzQqyq0Uu$xaPFS&Dc*W8YZ1WFr+wQ9k4&<})zfWanv}m*&)u^oZ>eChM qi2715Ub*%-(y?+QjPS3ZQhf(^2-AtP^Crds0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y9E;VFFSW*B01+7U$K~z{r?bhi}R96@VaCT&yfnk+(W?Hu zgQliJQN;W7oI7WRxid`k58z4O4-?4z&b@Qq_Z*A4%*9;#?{K1XLtK3SFcNgtOY5ev z&e9qb)+t&8!a7OocWoX2jf+2h9%4qBrgsQ|D_i$pSLHWy%Ejvto!5Y9^%_Lw)**6X z4I*-?5uR0vu#5^Q7L*|*wG_e0C6FZ+LK>fspjb5mlndb(l?mVQH25fz;1wJP52+IF z0g;gShhtUqwm!z0W=H3@Z4}nxYiIC9PlM+nKxKf3CKEg!o>CRu10&()7YebD90gSy zt}xCt&u;su#~5$kybt}q{DH={T?ospKxjI_)0Po@DddSo1Yg4NMevWxf^Wov8C<5r z!w4P>kyj9ETlaM^PMGe?uv^u-e?%#G@>*QEb^|mI9zH_N`Zu+B3c-^Ioq9MG&*KpbS7Xbr55VzD0LK5D zMA^EH2KZtG#!x();OUqjmLk9<{uB=(xD?I=mqsK__FUjpj1;E*)TOo2>IOX?N$`m5 zD)QP_V&^-buq6QZ{vAhQRSUy&dE7735RZjNP&B{cc-&jcKe>~e4>AjDht8jeEhB|# z-P84<0M8+K)+&T%tbihIISwBFj4c5eyL%5gng;kQDV{;_RDvhMQ*MC!hCu8sBX|J8 z=fgqd0ZrY;&lzVFz_NDZfvZtGuG{epU$C6)cn#Tf#W>t`k}UzaH8O@|^$IPnNQ4)U zDAwmUX;pKBMvFTOa9T@iUNL_Fl|Q$Am<}2_88ouQ0@7yr(A2cx z?^`2`1t!TswDs+y@Cnc4dp#i|4@Ju=QK+fFl9Dpy7nLHfpae;&8L+XN2PmKL^4Q;pLs%A`0Jz_L)?dBNrS8w8HJjD|;7h`&Qn*G%@D=O;< zYN^L1p1u#de&&=sXq=9(1{#b9O=aUt{1=gZhR);tWEPZ?-<17{ z)7JJrX*_8+itBGQ!b^qWjmF%dv9z=@focDf*FX5_Ph0@`JbO-GhuHWUZG4s1)iGKZ ugw;)}fA%_Zj*I`epA#`^E^{%8g~k6vUCGv)RWSts0000 Date: Wed, 18 Aug 2021 08:52:49 +0800 Subject: [PATCH 2/9] typo --- README.md | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 19d5976aeb..cd7c3138fd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # ![AzureIcon] Modules -This repository consists of a collection of compliant [Azure Resource Manager (ARM)][AzureResourceManager] and [Bicep][Bicep] templates as well as [template specs](). +This repository consists of a collection of compliant [Azure Resource Manager (ARM)][AzureResourceManager] and [Bicep][Bicep] templates as well as supporting [template specs](). + +This library of **Modules** ensures organizations can deploy compliant Azure services aligned with the proactive and preventive policies provided by [Enterprise-Scale landing zones (ESLZ)](), aligned with [Azure Security Benchmark](). + +> This repository serves ***currently*** as a temporary extension and development site for [ESLZ Workload Templates library](). ## Description @@ -12,9 +16,6 @@ This repository consists of a collection of compliant [Azure Resource Manager (A ## Getting Started -This is an example of how you may give instructions on setting up your project locally. -To get a local copy up and running follow these simple example steps. - ### Prerequisites To be able to deploy [ARM][AzureResourceManager] templates you should have latest version [PowerShell 7][PowerShellDocs] + [Azure Az Module][InstallAzPs] or [Azure CLI]()as well as [Bicep][Bicep] installed. @@ -32,7 +33,7 @@ iwr https://aka.ms/installazurecliwindows -OutFile .\AzureCLI.msi; start msiexec curl -L https://aka.ms/InstallAzureCli | bash ``` -# One-liner to install or update PowerShell 7 on Windows 10 +#### One-liner to install or update PowerShell 7 on Windows 10 ```PowerShell iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI" @@ -93,15 +94,16 @@ New-AzResourceGroupDeployment ` ## FAQ and Known Issues Any advise for common problems or issues. - ```bash - command to run if program contains helper info - ``` +```bash +command to run if program contains helper info +``` ## Reporting Issues and Feedback ### Issues and Bugs -If you find any bugs, please file an issue in the [GitHub Issues][GitHubIssues] page. Please search the existing issues before filing new issues to avoid duplicates. Please fill out the provided template with the appropriate information. +If you find any bugs, please file an issue in the [GitHub Issues][GitHubIssues] page. Please fill out the provided template with the appropriate information. +> Please search the existing issues before filing new issues to avoid duplicates. If you are taking the time to mention a problem, even a seemingly minor one, it is greatly appreciated, and a totally valid contribution to this project. **Thank you!** @@ -113,27 +115,20 @@ If there is a feature you would like to see in here, please file an issue or fea Contributors names and contact info -* You, Yourself and the Universe -* [@your_twitter]() +* [@segraef]() ## Contributing -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. -When you submit a pull request, a CLA bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions -provided by the bot. You will only need to do this once across all repos using our CLA. +When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. ## Trademarks -This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft -trademarks or logos is subject to and must follow +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies. @@ -144,12 +139,12 @@ Any use of third-party trademarks or logos are subject to those third-party's po * [Microsoft Azure Documentation][MicrosoftAzureDocs] * [Azure Resource Manager][AzureResourceManager] * [Bicep][Bicep] +* [GitHubDocs][GitHubDocs] [ProjectSetup]: -[CreateFromTemplate]: [GitHubDocs]: [AzureDevOpsDocs]: [GitHubIssues]: From f1224459692c37fec5cd96054d65d3c8676f394e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= Date: Wed, 18 Aug 2021 09:19:12 +0800 Subject: [PATCH 3/9] typo --- README.md | 130 ++++++++++++------------------------------------------ 1 file changed, 28 insertions(+), 102 deletions(-) diff --git a/README.md b/README.md index cd7c3138fd..fcfa06dd79 100644 --- a/README.md +++ b/README.md @@ -1,122 +1,42 @@ # ![AzureIcon] Modules -This repository consists of a collection of compliant [Azure Resource Manager (ARM)][AzureResourceManager] and [Bicep][Bicep] templates as well as supporting [template specs](). - -This library of **Modules** ensures organizations can deploy compliant Azure services aligned with the proactive and preventive policies provided by [Enterprise-Scale landing zones (ESLZ)](), aligned with [Azure Security Benchmark](). - -> This repository serves ***currently*** as a temporary extension and development site for [ESLZ Workload Templates library](). +This repository consists of a collection of compliant [Azure Resource Manager (ARM)][AzureResourceManager] and [Bicep][Bicep] templates as well as supporting [template specs][TemplateSpecs]. ## Description +This library of **Modules** ensures organizations can deploy compliant Azure services aligned with the proactive and preventive policies provided by [Enterprise-Scale landing zones (ESLZ)][ESLZ], aligned with [Azure Security Benchmark][AzureSecurityBenchmark]. + +> This repository serves ***currently*** as a temporary extension and **active** development site for [ESLZ Workload Templates library][ESLZWorkloadTemplatesLibrary]. ## Status [![Super Linter]()]() -[![Sample Workflow]()]() - -## Getting Started - -### Prerequisites - -To be able to deploy [ARM][AzureResourceManager] templates you should have latest version [PowerShell 7][PowerShellDocs] + [Azure Az Module][InstallAzPs] or [Azure CLI]()as well as [Bicep][Bicep] installed. - -### Installation - -#### One-liner to install or update Azure CLI on Windows 10 - -```PowerShell -iwr https://aka.ms/installazurecliwindows -OutFile .\AzureCLI.msi; start msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet'; rm .\AzureCLI.msi -``` - -#### One-liner to install or update Azure CLI on Linux -```bash -curl -L https://aka.ms/InstallAzureCli | bash -``` - -#### One-liner to install or update PowerShell 7 on Windows 10 - -```PowerShell -iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI" -Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force -``` - -Make sure to install Azure Az Module as well. - -```PowerShell -iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI" -Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force -``` - -### Usage - -#### Deploy local template (Azure CLI) +[![Workflow]()]() -```bash -az group create --name ExampleGroup --location "Central US" -az deployment group create \ - --name ExampleDeployment \ - --resource-group ExampleGroup \ - --template-file \ - --parameters storageAccountType=Standard_GRS -``` +![GitHub issues by-label](https://img.shields.io/github/issues/Azure/Modules) -#### Deploy local template (PowerShell) + + Issues +
+ + Pull requests + -```PowerShell -New-AzResourceGroup -Name ExampleGroup -Location "Central US" -New-AzResourceGroupDeployment ` - -Name ExampleDeployment ` - -ResourceGroupName ExampleGroup ` - -TemplateFile -``` - -#### Deploy remote template (Azure CLI) - -```bash -az group create --name ExampleGroup --location "Central US" -az deployment group create \ - --name ExampleDeployment \ - --resource-group ExampleGroup \ - --template-uri "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.storage/storage-account-create/azuredeploy.json" \ - --parameters storageAccountType=Standard_GRS -``` - -#### Deploy remote template (PowerShell) - -```PowerShell -New-AzResourceGroup -Name ExampleGroup -Location "Central US" -New-AzResourceGroupDeployment ` - -Name remoteTemplateDeployment ` - -ResourceGroupName ExampleGroup ` - -TemplateUri https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.storage/storage-account-create/azuredeploy.json -``` - -## FAQ and Known Issues - -Any advise for common problems or issues. -```bash -command to run if program contains helper info -``` - -## Reporting Issues and Feedback - -### Issues and Bugs - -If you find any bugs, please file an issue in the [GitHub Issues][GitHubIssues] page. Please fill out the provided template with the appropriate information. -> Please search the existing issues before filing new issues to avoid duplicates. - -If you are taking the time to mention a problem, even a seemingly minor one, it is greatly appreciated, and a totally valid contribution to this project. **Thank you!** - -### Feedback +## Getting Started -If there is a feature you would like to see in here, please file an issue or feature request in the [GitHub Issues][GitHubIssues] page to provide direct feedback. +For introduction guidance visit the [Wiki](https://github.com/azure/Modules/wiki) +For reference documentation visit [Enterprise-Scale](https://github.com/azure/enterprise-scale) +For information on contributing, see [Contribution]() +File an issue via [GitHub Issues](https://github.com/azure/Modules/issues/new/choose) -## Contributors + + ## Contributing This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. @@ -137,13 +57,14 @@ Any use of third-party trademarks or logos are subject to those third-party's po * [PowerShell Documentation][PowerShellDocs] * [Microsoft Azure Documentation][MicrosoftAzureDocs] +* [GitHubDocs][GitHubDocs] * [Azure Resource Manager][AzureResourceManager] * [Bicep][Bicep] -* [GitHubDocs][GitHubDocs] +[Wiki]: [ProjectSetup]: [GitHubDocs]: [AzureDevOpsDocs]: @@ -159,7 +80,12 @@ Any use of third-party trademarks or logos are subject to those third-party's po [AzGallery]: [PowerShellCore]: [InstallAzPs]: -[AzureResourceManager]: +[AzureResourceManager]: +[TemplateSpecs]: azure-resource-manager/management/overview> + +[ESLZ]: +[AzureSecurityBenchmark]: +[ESLZWorkloadTemplatesLibrary]: [MicrosoftAzureDocs]: From 1d61d3a5c02c747803102dce120061fdba4f73cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= Date: Wed, 18 Aug 2021 09:22:31 +0800 Subject: [PATCH 4/9] typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fcfa06dd79..fa4fb45a0b 100644 --- a/README.md +++ b/README.md @@ -80,8 +80,8 @@ Any use of third-party trademarks or logos are subject to those third-party's po [AzGallery]: [PowerShellCore]: [InstallAzPs]: -[AzureResourceManager]: -[TemplateSpecs]: azure-resource-manager/management/overview> +[AzureResourceManager]: +[TemplateSpecs]: [ESLZ]: [AzureSecurityBenchmark]: From dad74fe853db195c6c83a354b5e1c046df64675a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= Date: Wed, 18 Aug 2021 09:28:36 +0800 Subject: [PATCH 5/9] . --- README.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index fa4fb45a0b..e5245b9c28 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,22 @@ This library of **Modules** ensures organizations can deploy compliant Azure ser > This repository serves ***currently*** as a temporary extension and **active** development site for [ESLZ Workload Templates library][ESLZWorkloadTemplatesLibrary]. ## Status - + + +

+ + Super Linter + + + Workflow + Issues
@@ -22,12 +31,14 @@ This library of **Modules** ensures organizations can deploy compliant Azure ser Pull requests -## Getting Started +

+ +## Get started -For introduction guidance visit the [Wiki](https://github.com/azure/Modules/wiki) -For reference documentation visit [Enterprise-Scale](https://github.com/azure/enterprise-scale) -For information on contributing, see [Contribution]() -File an issue via [GitHub Issues](https://github.com/azure/Modules/issues/new/choose) +* For introduction guidance visit the [Wiki](https://github.com/azure/Modules/wiki) +* For reference documentation visit [Enterprise-Scale](https://github.com/azure/enterprise-scale) +* For information on contributing, see [Contribution]() +* File an issue via [GitHub Issues](https://github.com/azure/Modules/issues/new/choose)