зеркало из
1
0
Форкнуть 0

Merge pull request #1 from Azure/feature/code_added

Added code and initial documentation
This commit is contained in:
Brian Blanchard 2020-11-05 13:28:06 -06:00 коммит произвёл GitHub
Родитель 892c5bcc0d ef268ddd10
Коммит 2a72b7b9e1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
156 изменённых файлов: 13523 добавлений и 1 удалений

31
.github/workflows/ARM-Custom-Tests.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,31 @@
name: ARM - Custom Tests Nunit
on:
push:
paths:
- src/platform-automation/artifacts/**
env:
testRunner: ./src/platform-automation/tests/Templates.tests.ps1
testResultsFile: TestResults.Pester.xml
tempFolder: ../_temp
defaults:
run:
shell: pwsh
jobs:
test_arm_templates:
runs-on: ubuntu-latest
name: Run Custom tests with Nunit
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run ARM Tests
run: |
$results = ./src/platform-automation/platform-scripts/Run-Tests.ps1 -testName 'ValidateTemplates' -testScriptToRun '${{env.testRunner}}' -testResultsFile '${{env.testResultsFile}}' -verbose
if($results.FailedCount -gt 0){
Write-Output 'There are failed tests - breaking build now'
$failedResults = $results.TestResult|? Result -eq Failed
$failedResults;
exit 1;
}

27
.github/workflows/ARM-TTK-Tests.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,27 @@
name: ARM Tests (arm-ttk)
on:
pull_request:
types: [assigned, opened, synchronize, reopened]
branches:
- master
push:
branches:
- master
paths:
- src/platform-automation/artifacts/**
jobs:
test_arm_templates:
runs-on: ubuntu-latest
name: Run ARM TTK tests
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run ARM Tests
uses: ./Actions/Arm-ttk
id: action
env:
TestsToInclude: ''
TestsToSkip: ''
TemplatesFolder: './src/platform-automation/artifacts/templates/'
OutputFilePath: testRuns/results.csv

34
.github/workflows/Deploy-All-Customer.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,34 @@
name: Deploy all customers
on:
pull_request:
types: [closed]
branches:
- master
paths:
- src/platform-automation/customers/**
defaults:
run:
shell: pwsh
env:
storageAccountName: ${{ secrets.AZURE_STORAGE_ACCOUNT_PROD }}
storageAccountKey: ${{ secrets. AZURE_DEPLOYMENT_STORAGE_SAS_PROD }}
lighthouseDeploymentCredential: ${{ secrets.AZURE_SUBSCRIPTION_CREDENTIAL }}
jobs:
deploy-customer:
name: Deploy all customers in one job - To be implemented
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- name: Run script for each customer
run: |
Write-host 'Running script..'
# - name: Run deployment
# run: |
# Get each customer subfolder
# Foreach customer folder -
# run: ./src/platform-automation/platform-scripts/Deploy-Customer.ps1 -

32
.github/workflows/Deploy-Contoso.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,32 @@
name: Customer deployment Contoso
on:
pull_request:
types: [closed]
branches:
- master
paths:
- src/platform-automation/cmdb/customers/contoso/*
env:
storageAccountName: ${{ secrets.AZURE_STORAGE_ACCOUNT_PROD }}
storageAccountKey: ${{ secrets. AZURE_DEPLOYMENT_STORAGE_SAS_PROD }}
customerDeploymentCredential: ${{ secrets.AZURE_CONTOSO_CREDENTIAL }}
defaults:
run:
shell: pwsh
jobs:
deploy-customer:
name: Deploy Contoso with all it's glory
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Login to Azure with Powershell
run: ./src/platform-automation/platform-scripts/Login-WithSecretString.ps1 -secretJson '${{ env.customerDeploymentCredential }}' -verbose
- name: Run deployment with verbose output
run: ./src/platform-automation/platform-scripts/Deploy-Customer.ps1 -customer "contoso" -storageAccountName '${{ env.storageAccountName }}' -storageAccountKey '${{ env.storageAccountKey }}' -verbose

32
.github/workflows/Depoly-Fabrikam.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,32 @@
name: Customer deployment Fabrikam
on:
pull_request:
types: [closed]
branches:
- master
paths:
- src/platform-automation/cmdb/customers/fabrikam/*
env:
storageAccountName: ${{ secrets.AZURE_STORAGE_ACCOUNT_PROD }}
storageAccountKey: ${{ secrets. AZURE_DEPLOYMENT_STORAGE_SAS_PROD }}
customerDeploymentCredential: ${{ secrets.AZURE_FABRIKAM_CREDENTIAL }}
defaults:
run:
shell: pwsh
jobs:
deploy-customer:
name: Deploy Fabrikam with all it's glory
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Login to Azure with Powershell
run: ./src/platform-automation/platform-scripts/Login-WithSecretString.ps1 -secretJson '${{ env.customerDeploymentCredential }}' -verbose
- name: Run deployment with verbose output
run: ./src/platform-automation/platform-scripts/Deploy-Customer.ps1 -customer "fabrikam" -storageAccountName '${{ env.storageAccountName }}' -storageAccountKey '${{ env.storageAccountKey }}' -verbose

71
.github/workflows/Governance-Contoso.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,71 @@
name: Governance visualizer for contoso
on:
pull_request:
types: [closed]
branches:
- master
paths:
- src/platform-automation/cmdb/customers/contoso/*
env:
ManagementGroupId: Contoso.com-Management
OutputPath: wiki/customers/contoso/governance-scan/
MermaidFile: wiki/customers/contoso/governance-scan/AzGovViz_Contoso.com-Management.md
CsvDelimiter: ;
Repository: wikiRepo
customerDeploymentCredential: ${{ secrets.AZURE_CONTOSO_CREDENTIAL }}
defaults:
run:
shell: pwsh
jobs:
build-customer:
name: Scan contoso for Governance changes
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- name: Checkout
uses: actions/checkout@v2
with:
path: main
- uses: actions/checkout@v2
with:
repository: ${{github.repository}}.wiki # specify the wiki repo name here.
path: wiki
- name: Login to Azure with Powershell
run: ./main/src/platform-automation/platform-scripts/Login-WithSecretString.ps1 -secretJson '${{ env.customerDeploymentCredential }}' -verbose
- name: Install Azure resource graph
run: |
Install-Module -Name Az.ResourceGraph -Force
if(!(Test-Path '${{ env.OutputPath }}')){
new-item -itemtype directory '${{ env.OutputPath }}' -Force
}
- name: Run AZGovViz with parameters for this customer
run: ./main/src/platform-automation/platform-scripts/AzGovViz.ps1 -ManagementGroupId ${{ env.ManagementGroupId }} -OutputPath '${{ env.OutputPath }}' -CsvDelimiter "${{ env.CsvDelimiter }}" -AzureDevOpsWikiAsCode -ErrorAction SilentlyContinue -Verbose
- name: Compile mermaid
uses: neenjaw/compile-mermaid-markdown-action@master
with:
files: ${{ env.MermaidFile }}
output: ${{ env.OutputPath }}
env:
HIDE_CODEBLOCKS: 1
ABSOLUTE_IMAGE_LINKS: 0
- name: show changes
run: |
cd wiki
git status
cd ..
- name: Commit files
run: |
cd wiki
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .
git commit -m "Updated governance wiki"
- name: Push changes to wiki repo
uses: ad-m/github-push-action@master
with:
directory: wiki
repository: ${{github.repository}}.wiki # specify the wiki repo and push the update.
github_token: ${{ secrets.GITHUB_TOKEN }}

71
.github/workflows/Governance-Fabrikam.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,71 @@
name: Governance visualizer for fabrikam
on:
pull_request:
types: [closed]
branches:
- master
paths:
- src/platform-automation/cmdb/customers/fabrikam/*
env:
ManagementGroupId: IT
OutputPath: wiki/customers/fabrikam/governance-scan/
MermaidFile: wiki/customers/fabrikam/governance-scan/AzGovViz_IT.md
CsvDelimiter: ;
Repository: wikiRepo
customerDeploymentCredential: ${{ secrets.AZURE_FABRIKAM_CREDENTIAL }}
defaults:
run:
shell: pwsh
jobs:
build-customer:
name: Scan Fabrikam for Governance changes
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- name: Checkout
uses: actions/checkout@v2
with:
path: main
- uses: actions/checkout@v2
with:
repository: ${{github.repository}}.wiki # specify the wiki repo name here.
path: wiki
- name: Login to Azure with Powershell
run: ./main/src/platform-automation/platform-scripts/Login-WithSecretString.ps1 -secretJson '${{ env.customerDeploymentCredential }}' -verbose
- name: Install Azure resource graph
run: |
Install-Module -Name Az.ResourceGraph -Force
if(!(Test-Path '${{ env.OutputPath }}')){
new-item -itemtype directory '${{ env.OutputPath }}' -Force
}
# - name: Run AZGovViz with parameters for this customer
# run: ./main/src/platform-automation/platform-scripts/AzGovViz.ps1 -ManagementGroupId ${{ env.ManagementGroupId }} -OutputPath '${{ env.OutputPath }}' -CsvDelimiter "${{ env.CsvDelimiter }}" -AzureDevOpsWikiAsCode -ErrorAction SilentlyContinue -Verbose
- name: Compile mermaid
uses: neenjaw/compile-mermaid-markdown-action@master
with:
files: ${{ env.MermaidFile }}
output: ${{ env.OutputPath }}
env:
HIDE_CODEBLOCKS: 1
ABSOLUTE_IMAGE_LINKS: 0
- name: show changes
run: |
cd wiki
git status
cd ..
- name: Commit files
run: |
cd wiki
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .
git commit -m "Updated governance wiki"
- name: Push changes to wiki repo
uses: ad-m/github-push-action@master
with:
directory: wiki
repository: ${{github.repository}}.wiki # specify the wiki repo and push the update.
github_token: ${{ secrets.GITHUB_TOKEN }}

53
.github/workflows/Manage-CustomerSubscriptions.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,53 @@
name: Manage CSP Customer subscriptions
on:
push:
branches:
- master
paths:
- src/platform-automation/cmdb/customers/**/new_subscription
- src/platform-automation/cmdb/customers/**/delete_subscription
env:
partnerCenterCredential: ${{ secrets.AZURE_CONTOSO_CREDENTIAL }}
defaults:
run:
shell: pwsh
jobs:
manage-subscriptions:
name: Manage subscriptions for customers
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Login to Azure with Powershell
run: ./src/platform-automation/platform-scripts/Login-WithSecretString.ps1 -secretJson '${{ env.partnerCenterCredential }}' -verbose
- name: Install Azure resource graph and partner center SDK
run: |
Install-Module -Name Az.ResourceGraph -Force
Install-Module -Name PartnerCenter -Force;
- name: get changed files
id: getfile
run: |
echo "::set-output name=files::$(git diff-tree --no-commit-id --name-only -r ${{ github.sha }} | grep -e '.*new_subscription$' -e '.*delete_subscription$' | xargs)"
- name: Run the correct management scripts for the change
run: |
# $files = ${{ steps.getfile.outputs.files }}
$new_files = Get-ChildItem -Path ./src/platform-automation/cmdb/customers -recurse -filter new_subscription
$deleted_files = Get-ChildItem -Path ./src/platform-automation/cmdb/customers -recurse -filter deleted_subscription;
$new_files|Foreach-object {
./src/platform-automation/platform-scripts/New-CustomerSubscription.ps1 -subscriptionFile $_.Fullname -Verbose
}
# Could output subscriptions to customer file and auto-commit that
- name: Commit changes
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .
git commit -m "Updated subscription files"
- name: Push changes to wiki repo
uses: ad-m/github-push-action@master
with:
repository: ${{github.repository}}
github_token: ${{ secrets.GITHUB_TOKEN }}

41
.github/workflows/Publish-Artifacts-To-AzureStorage.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,41 @@
name: Production - Verify and publish artifacts to Azure Storage
on:
pull_request:
types: [closed]
branches:
- master
paths:
- src/platform-automation/artifacts/**
defaults:
run:
shell: pwsh
env:
storageAccountName: ${{ secrets.AZURE_STORAGE_ACCOUNT_PROD }}
storageAccountKey: ${{ secrets. AZURE_DEPLOYMENT_STORAGE_SAS_PROD }}
artifactsVersion: "1.0"
artifactsSrcFolder: ./src/platform-automation/artifacts
deploymentAutomationCredential: ${{ secrets.AZURE_SUBSCRIPTION_CREDENTIAL }}
jobs:
build-and-deploy:
runs-on: ubuntu-latest
# strategy:
# matrix:
# artifacts: ['blueprints','dsc','scripts','workbooks','templates']
# fail-fast: true
if: github.event.pull_request.merged == true
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Login to Azure with Powershell
run: ./src/platform-automation/platform-scripts/Login-WithSecretString.ps1 -secretJson '${{ env.deploymentAutomationCredential }}' -verbose
- name: Prepare for artifact upload
run: |
Write-Output 'StorageAccount : ${{ env.storageAccountName }} Preparing artifacts and uploading artifacts from ${{ env.artifactsSrcPath }}'
- name: Run upload artifacts script
run: ./src/platform-automation/platform-scripts/Upload-Artifacts.ps1 -storageAccountName '${{ env.storageAccountName }}' -storageAccountKey '${{ env.storageAccountKey }}' -version '${{ env.artifactsVersion }}' -artifactsPath '${{ env.artifactsSrcFolder }}' -verbose

40
.github/workflows/Publish-Artifacts.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,40 @@
name: Publish artifacts to workflow
on:
push:
paths:
- src/platform-automation/artifacts
# paths-ignore:
# - 'docs/**'
jobs:
create-artifacts:
name: Create artifacts for re-use
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Create blueprints artifacts
uses: actions/upload-artifact@v1
with:
name: Blueprints
path: ./src/platform-automation/artifacts/blueprints
- name: Create Desired state configuration artifacts
uses: actions/upload-artifact@v1
with:
name: dsc
path: ./src/platform-automation/artifacts/dsc
- name: Create pipelines artifact
uses: actions/upload-artifact@v1
with:
name: pipelines
path: ./src/platform-automation/artifacts/pipelines
- name: Create scripts
uses: actions/upload-artifact@v1
with:
name: scripts
path: ./src/platform-automation/artifacts/scripts
- name: Create all templates in one artifact
uses: actions/upload-artifact@v1
with:
name: templates
path: ./src/platform-automation/artifacts/templates

17
.github/workflows/Readme.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,17 @@
# Workflows needs to be on (ROOT)\.github\workflows
# Getting started
The workflows needs some secrets to be set under github and some 'prework'.
Create a storage account that are to be used for sharing artifacts (or configure the name in the pipelines)
See:
- [Publish-Artifacts-To-AzureStorage.yml](./Publish-Artifacts-To-AzureStorage.yml).
- [Deploy-Contoso.yml](./Deploy-Contoso.yml).
Create minimum two secrets in github to allow the 'operations/platform' pipelines to work:
- AZURE_DEPLOYMENT_STORAGE_SAS => SAS from the previous storage account
- AZURE_SUBSCRIPTION_CREDENTIAL => Credential for deployment automation
In addition - per pipeline (customer)
- AZURE_CUSTOMER_SUBSCRIPTION_CREDENTIAL => Diff

51
.github/workflows/Test-And-Upload-Dev-Artifacts.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,51 @@
name: Dev - Verify and publish artifacts to Azure Storage
on:
push:
branches-ignore:
- master
paths:
- src/platform-automation/artifacts/**
defaults:
run:
shell: pwsh
env:
storageAccountName: ${{ secrets.AZURE_STORAGE_ACCOUNT_DEV }}
storageAccountKey: ${{ secrets. AZURE_DEPLOYMENT_STORAGE_SAS_DEV }}
artifactsVersion: "1.0"
artifactsSrcFolder: ./src/platform-automation/artifacts
deploymentAutomationCredential: ${{ secrets.AZURE_SUBSCRIPTION_CREDENTIAL }}
jobs:
test_arm_templates:
runs-on: ubuntu-latest
name: Run artifacts tests for all customers
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run artifacts test
run: |
Find-Module Pester|Install-Module -Scope CurrentUser -Force
Import-module Pester
./src/platform-automation/tests/Artifacts.tests.ps1
build-and-deploy:
needs: test_arm_templates
runs-on: ubuntu-latest
# strategy:
# matrix:
# artifacts: ['blueprints','dsc','scripts','workbooks','templates']
# fail-fast: true
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Login to Azure with Powershell
run: ./src/platform-automation/platform-scripts/Login-WithSecretString.ps1 -secretJson '${{ env.deploymentAutomationCredential }}' -verbose
- name: Prepare for artifact upload
run: |
Write-Output 'StorageAccount : ${{ env.storageAccountName }} Preparing artifacts and uploading artifacts from ${{ env.artifactsSrcPath }}'
- name: Run upload artifacts script
run: ./src/platform-automation/platform-scripts/Upload-Artifacts.ps1 -storageAccountName '${{ env.storageAccountName }}' -storageAccountKey '${{ env.storageAccountKey }}' -version '${{ env.artifactsVersion }}' -artifactsPath '${{ env.artifactsSrcFolder }}' -verbose

66
.github/workflows/Update-Wiki.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,66 @@
name: Update wiki
on:
push:
branches:
- master
paths:
- src/platform-automation/cmdb/customers/**
defaults:
run:
shell: pwsh
env:
artifactsSrcFolder: ./src/platform-automation/artifacts
lighthouseDeploymentCredential: ${{ secrets.AZURE_LIGHTHOUSE_CREDENTIAL }}
jobs:
test_arm_templates:
runs-on: ubuntu-latest
name: Generate wiki pages for all customers managed by code
steps:
- uses: actions/checkout@v2
with:
path: main
- uses: actions/checkout@v2
with:
repository: ${{github.repository}}.wiki # specify the wiki repo name here.
path: wiki
- name: Login to Azure with Powershell
run: ./main/src/platform-automation/platform-scripts/Login-WithSecretString.ps1 -secretJson '${{ env.lighthouseDeploymentCredential }}' -verbose
- name: check wiki repo content
run: |
cd wiki
ls -al
- name: Update customers wiki
run: ./main/src/platform-automation/platform-scripts/Build-Wiki.ps1 -customersPath 'main/src/platform-automation/cmdb/customers' -wikiPath 'wiki/'
- name: Commit changes files
run: |
cd wiki
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .
git commit -m "Updated wiki"
- name: Push changes to wiki repo
uses: ad-m/github-push-action@master
with:
directory: wiki
repository: ${{github.repository}}.wiki # specify the wiki repo and push the update.
github_token: ${{ secrets.GITHUB_TOKEN }}
# - name: Updated Governance documentation for customers
# id: cpr
# uses: peter-evans/create-pull-request@v2
# with:
# path: wiki
# token: ${{ secrets.GITHUB_TOKEN }}
# commit-message: Updated customer list
# title: '[Customers] Updated list of customers'
# body: |
# - Auto-generated by [create-pull-request][1]
# labels: report, automated pr
# assignees: haraldfianbakken
# reviewers: haraldfianbakken
# branch-suffix: timestamp
# - name: Check outputs
# run: |
# echo "Pull Request Number - ${{ env.PULL_REQUEST_NUMBER }}"
# echo "Pull Request Number - ${{ steps.cpr.outputs.pr_number }}"

23
.github/workflows/Validate-Customers-Tests.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,23 @@
name: Customer Platform Validation Tests
on:
push:
branches:
- master
paths:
- src/platform-automation/cmdb/customers/*/manifest.json
defaults:
run:
shell: pwsh
jobs:
test_arm_templates:
runs-on: ubuntu-latest
name: Run artifacts tests for all customers
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run artifacts test
run: |
Find-Module Pester|Install-Module -Scope CurrentUser -Force
Import-module Pester
./src/platform-automation/tests/Artifacts.tests.ps1

3
.gitignore поставляемый
Просмотреть файл

@ -59,7 +59,7 @@ BenchmarkDotNet.Artifacts/
# .NET Core # .NET Core
project.lock.json project.lock.json
project.fragment.lock.json project.fragment.lock.json
artifacts/
# StyleCop # StyleCop
StyleCopReport.xml StyleCopReport.xml
@ -322,6 +322,7 @@ __pycache__/
*.odx.cs *.odx.cs
*.xsd.cs *.xsd.cs
.vscode/
# OpenCover UI analysis results # OpenCover UI analysis results
OpenCover/ OpenCover/

Просмотреть файл

@ -0,0 +1,27 @@
FROM mcr.microsoft.com/powershell:latest
LABEL "com.github.actions.name"="arm-ttk"
LABEL "com.github.actions.description"="Checks template with the arm-ttk toolkit"
LABEL version="1.0.0"
LABEL maintainer="Harald S. Fianbakken"
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y git
RUN git clone https://github.com/Azure/arm-ttk.git
COPY entrypoint.ps1 /entrypoint.ps1
# When used from Github - mounts workspace into :
# /github/workspace
# Build and run locally using
#
# docker image build -t armttk:1.0 .
# Run with mount
# docker run --rm -it armttk:1.0 --mount source=../../,target=/github/workspace -e TemplatesFolder=./src/platform-automation/artifacts/templates
# Start using the Entrypoint file.
ENTRYPOINT [ "pwsh", "/entrypoint.ps1" ]

Просмотреть файл

@ -0,0 +1,64 @@
Import-Module '/arm-ttk/arm-ttk/arm-ttk.psd1'
$params = @{};
if($env:TestsToInclude){
$params.Add("Test", $env:TestsToInclude);
}
if($env:TestsToSkip){
$params.add("Skip", $env:TestsToSkip)
}
if($env:TemplatePath -and -not $env:TemplatesFolder){
$params.Add("TemplatePath", $env:TemplatePath);
}
$testRuns = @();
if($env:TemplatesFolder){
$files = Get-ChildItem -Recurse -filter *.json -path $env:TemplatesFolder -exclude *.parameters.json;
$files | Foreach-object {
$TestResults = Test-AzTemplate @params -TemplatePath $_.FullName;
$testRuns += $TestResults;
}
} else {
$TestResults = Test-AzTemplate @params;
$testRuns += $TestResults;
}
$runs = $testRuns|foreach-object {
@{
"Passed"=$_.Passed;
"Name"=$_.Name;
"Group"=$_.Group;
"FileName"=$_.File.FullPath;
"FileshortName"=$_.File.Name;
"Output" = $_.AllOutput;
}
}
$TestFailures = $runs | Where-Object { -not $_.Passed }
# Write test results to csv file (output path)
if($env:OutputFilePath){
$outputPath = $env:OutputFilePath;
if(!(Test-Path $outputPath)){
[void](New-Item -ItemType File $outputPath -force);
}
$runs|ConvertTo-Csv -Delimiter ';'|Set-Content $outputPath;
}
$runs|Select-Object FileName, Group, Passed, Name, Output;
# Fail github
if ($TestFailures) {
Write-Error "There were $($TestFailures.Count) tests failing - please fix before continuing!"
$TestFailures|Select-Object FileName, Group, Passed, Name, Output;
Write-Error "There were $($TestFailures.Count) tests failing - please fix before continuing!"
exit 1
}
else {
Write-Output "All tests are passing"
exit 0
}

Просмотреть файл

@ -0,0 +1,142 @@
trigger:
- master
stages:
- stage: buildArtifacts
displayName: create artifacts
variables:
artifactsDirectory : "$(Build.ArtifactStagingDirectory)"
bluePrintsFolder : "$(Build.ArtifactStagingDirectory)/Blueprints"
dscFolder : "$(Build.ArtifactStagingDirectory)/Dsc"
pipelinesFolder : "$(Build.ArtifactStagingDirectory)/Pipelines"
scriptsFolder : "$(Build.ArtifactStagingDirectory)/Scripts"
mgTemplatesFolder: "$(Build.ArtifactStagingDirectory)/MgTemplates"
rgTemplatesFolder: "$(Build.ArtifactStagingDirectory)/RgTemplates"
subscriptionTemplatesFolder: "$(Build.ArtifactStagingDirectory)/subscriptionTemplates"
tenantTemplatesFolder: "$(Build.ArtifactStagingDirectory)/tenantTemplates"
templateFolder : "$(Build.ArtifactStagingDirectory)/Templates"
blueprintArtifactName : "Blueprints"
dscArtifactName : "Dsc"
pipelinesArtifactName : "Pipelines"
scriptsArtifactName : "Scripts"
mgTemplatesArtifactName : "ManagementGroup"
rgTemplatesArtifactName : "ResourceGroup"
subscriptionTemplatesArtifactName : "Subscription"
tenantTemplatesArtifactName : "Tenant"
templatesArtifactName : "Templates"
jobs:
- job: buildAndAssembleArtifacts
steps:
- pwsh: |
new-item -itemType Directory $(bluePrintsFolder) -force
new-item -itemType Directory $(dscFolder) -force
new-item -itemType Directory $(pipelinesFolder) -force
new-item -itemType Directory $(scriptsFolder) -force
new-item -itemType Directory $(mgTemplatesFolder) -force
new-item -itemType Directory $(rgTemplatesFolder) -force
new-item -itemType Directory $(subscriptionTemplatesFolder) -force
new-item -itemType Directory $(tenantTemplatesFolder) -force
new-item -itemType Directory $(templateFolder) -force
displayName: Create folders and prep artifacts
enabled: true
- task: CopyFiles@2
displayName: "Copy blueprints"
inputs:
sourceFolder: "$(Build.SourcesDirectory)/src/platform-automation/artifacts/blueprints"
contents: "**"
targetFolder: "$(blueprintsFolder)"
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(blueprintsFolder)
artifactName: $(blueprintArtifactName)
- task: CopyFiles@2
displayName: "Copy DSC"
inputs:
sourceFolder: "$(Build.SourcesDirectory)/src/platform-automation/artifacts/dsc"
contents: "**"
targetFolder: "$(dscFolder)"
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(dscFolder)
artifactName: $(dscArtifactName)
- task: CopyFiles@2
displayName: "Copy pipelines"
inputs:
sourceFolder: "$(Build.SourcesDirectory)/src/platform-automation/artifacts/pipelines"
contents: "**"
targetFolder: "$(pipelinesFolder)"
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(pipelinesFolder)
artifactName: $(pipelinesArtifactName)
- task: CopyFiles@2
displayName: Copy Scripts
inputs:
sourceFolder: "$(Build.SourcesDirectory)/src/platform-automation/artifacts/scripts"
contents: "**"
targetFolder: "$(scriptsFolder)"
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(scriptsFolder)
artifactName: $(scriptsArtifactName)
- task: CopyFiles@2
displayName: Copy MG templates
inputs:
sourceFolder: "$(Build.SourcesDirectory)/src/platform-automation/artifacts/templates/managementgroup"
contents: "**"
targetFolder: "$(mgTemplatesFolder)"
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(mgTemplatesFolder)
artifactName: $(mgTemplatesArtifactName)
- task: CopyFiles@2
displayName: Copy RG templates
inputs:
sourceFolder: "$(Build.SourcesDirectory)/src/platform-automation/artifacts/templates/resourcegroup"
contents: "**"
targetFolder: "$(rgTemplatesFolder)"
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(rgTemplatesFolder)
artifactName: $(rgTemplatesArtifactName)
- task: CopyFiles@2
displayName: Copy subscription templates
inputs:
sourceFolder: "$(Build.SourcesDirectory)/src/platform-automation/artifacts/templates/subscription"
contents: "**"
targetFolder: "$(subscriptionTemplatesFolder)"
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(subscriptionTemplatesFolder)
artifactName: $(subscriptionTemplatesArtifactName)
- task: CopyFiles@2
displayName: Copy tenant templates
inputs:
sourceFolder: "$(Build.SourcesDirectory)/src/platform-automation/artifacts/templates/tenant"
contents: "**"
targetFolder: "$(tenantTemplatesFolder)"
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(tenantTemplatesFolder)
artifactName: $(tenantTemplatesArtifactName)
- task: CopyFiles@2
displayName: Copy all templates
inputs:
sourceFolder: "$(Build.SourcesDirectory)/src/platform-automation/artifacts/templates/tenant"
contents: "**"
targetFolder: "$(templatesFolder)"
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(templatesFolder)
artifactName: $(templatesArtifactName)

Просмотреть файл

@ -3,6 +3,92 @@ This repo will house an indevelopment solution for multi-tenant Azure landing zo
Upon completion of the development and engineering review, this solution will likely be featured in the Cloud Adoption Framework as an Azure landing zone implementation option. Upon completion of the development and engineering review, this solution will likely be featured in the Cloud Adoption Framework as an Azure landing zone implementation option.
In the meantime, please feel free to share feedback on the work-in-progress development or leverage the existing Azure Landing Zone implementation options: https://docs.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/implementation-options In the meantime, please feel free to share feedback on the work-in-progress development or leverage the existing Azure Landing Zone implementation options: https://docs.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/implementation-options
# Narrative
Some companies have the need for multiple landing zones; support different lisencing models (EA, PAYG, CSP) and build, support and operate these landing zones across multiple tenants. This is especially important for partners where different delivery models account for a big deal of their business or enterprises that run seperated businesses within their enterprise and still require control and standardization.
This solution is not opinionated on the architecture you choose to deliver or how to. If we look at Enterprise Scale - this would be one out of many landing zones a company would support and be able to deliver at scale.
# Design principles
- DevOps first approach and 'DevOps' tooling netural (Any toolchain)
- Native tooling and support cross platform
- Test and deploy from anywhere (pipelines, workflows, locally or on-site)
- Secure development and automated testing for best practices development
- Ability to approve landing zones (or solutions) for company wide use
- Bootstrap any tenant and apply an operational model
- Discover new subscriptions and tenants that are onboarded to operational models
- Tenants as code (customers as code)
- Subscriptions democratization through automation (supporting multi-licensing models)
# Building blocks
These are the central building blocks used to create the delivery mechanism used to scale:
- Git (including branching, reviews ++)
- PowerShell Core (including AZ Modules)
- Azure Resource Manager (ARM)
- Azure Storage (Delivery mechanism, idempotent and for staging)
- Arm TTK
- Azure Lighthouse
# Multi-tenant landing zones and cross tenant deployments
# Getting started
- Read instructions
# Solution
- Build, test and verify artifacts
- Approve and publish artifacts for re-use
- Create and validate manifests
- Deploy manifest
- Manage customers at scale (Lighthouse, customers as code ++)
- Discover customers
- Tenants as code (self documenting, governance scanning)
## How it works
## Extras
These are 'demos' or features not fully implemented or standalone items, to showcase various features of Azure DevOps / GitHub or how to scale from management, operations and deployment.
- Build-DelegationList.ps1 : This script outputs an array of objects with customer whom are onboarded or offboarded onto your lighthouse offer. This requires you to be logged in to your management tenant and have read access to the monitoring logs. Typically this would be used in a automation process (azure function or azure automation) on automate the customer process.
- Export-Blueprints.ps1 - As a part of your company process you might have someone working with Azure Blueprints in staging tenant that you want to automate into your Git Repository to re-use across your customers/tenants. This script can be used as such an export - and run periodcally as part of a git workflow / pipeline.
- Tests\Scripts\Deploy-Customers.tests.ps1 - This test file runs the PSScriptAnalyzer tests and checks for best practices in Powershell script file Deploy-Customer.ps1. Can be used as a best practices testing when creating deployment scripts and files. Should be embedded as a safe-guard when doing pull-requests and doing work on the actual deployment scripts themselves.
- Tests\Templates.SVT.tests.ps1 - This set of tests runs the AzSK_ARMTemplateChecker (Azure Secure DevOpsKit) to verify that security best practices have been implemented in our artifacts. Can be used as a gate for secure development practices.
[![Security scanning](images/Templates.SVT.tests.png)](#)
### Workflows
#### Publish artifacts to workflow
This workflow shows how to create zip files (artifacts) that can be re-used throughout a Github Workflow.
***Note:*** This should be used in correlation with a full workflow. Simlar concept would apply for Azure DevOps pipelines - where you would published artifacts within the pipeline and consume them at a later stage.
## Security on workflows and pipeline
As Github does not currently offer a way to seperate secrets from repositories - this means anyone with contributor access to your repository can potentially create a workflow that uses your secret. Github enterprise can do secrets on organization level or on repository level only. Be aware of this when you design and think around how you will manage multiple tenants as code.
Azure DevOps provides pipeline security which currently are more granular.
## Building "artifacts" (details)
## Approve and publish artifacts
The solution now triggers when a new pull request have been approved and merged onto master. The publish artifacts workflow will upload the templates (and other artifacts) to an Azure Storage account - where they can be consumed later in a deployment or provisioning.
***Design choices:*** Instead of triggering directly on master - we could have a workflow, create release on a tag push (e.g. v.) - and have this fully automated as part of our gitflow. Any Git event (commit, tag, wiki update ++) can trigger any other workflow.
## Current known limitations
AzGovViz and Mermaid diagrams - The AzGovViz scanner together with the action compile mermaid diagram sometimes hangs and stops responding in pipelines. This will cause the workflow to execute for a very long time before terminating.
- New subscription workflow is currently only mocked as a demo on how to enable subscription democratization as code - regardsless of licensing model (EA, CSP, PAYG).
- Uploading and approving artifacts of type scripts/DSC/Dashboards: As these would normally require additionally testing or it's own validation process - we have left the upload part out from Upload-Artifacts.ps1. If your workflow will upload these to storage dirctly, you could choose to implement it directly here.
## Provisonining
# Contributing # Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a This project welcomes contributions and suggestions. Most contributions require you to agree to a

41
docs/Artifacts.md Normal file
Просмотреть файл

@ -0,0 +1,41 @@
## Navigation Menu
* [Getting started](../src/platform-automation#platform-automation---getting-started)
* [Landing zones](./Landing-zones.md)
- **Artifacts**
- [Customers](../src/platform-automation/cmdb#customers)
- [Multi tenant deployments](./Multi-tenant-deployments.md)
* [Platform automation at scale](./Platform-automation-at-scale.md)
* [Design Guidelines](./Design-Guidelines.md)
- [CSP and Azure AD Tenants](./CSP-and-Azure-AD-Tenants.md)
- [Identity, Access Management and Lighthouse](./Identity-Access-Management-and-Lighthouse.md)
- [Management Group and Subscription Organisation](./Management-Group-and-Subscription-Organisation.md)
- [Management and Monitoring](./Management-and-Monitoring.md)
- [Security, Governance and Compliance](./Security-Governance-and-Compliance.md)
- [Platform Automation and DevOps](./Platform-Automation-and-DevOps.md)
---
# Artifacts
Artifacts repository contains all the components a partner will want to deploy. Each artifact type has its own directory. Ex: All the policies will go in the policy-definition folder. For templates, there are 4 deployments scopes: rg, subscription, MG and tenant.
For instance, if an ARM template needs to be deployed at tenant level, it will be added in templates/ tenant folder.
|-- artifacts
|-- dashboards
|-- dsc
|-- pipelines
|-- policy-definitions
|-- role-definitions
|-- scripts
|-- templates
|-- resourcegroup
|-- subscription
|-- managementgroup
|-- tenant
|-- workbooks
An action will be triggered on any commit in artifacts master repo and all artifacts will be added to the storage account used. Once the resources will be stored in the storage account, any combination of those resources can be deployed to any customer.

Просмотреть файл

@ -0,0 +1,101 @@
## Navigation Menu
* [Getting started](../src/platform-automation#platform-automation---getting-started)
* [Landing zones](./Landing-zones.md)
- [Artifacts](./Artifacts.md)
- [Customers](../src/platform-automation/cmdb#customers)
- [Multi tenant deployments](./Multi-tenant-deployments.md)
* [Platform automation at scale](./Platform-automation-at-scale.md)
* [Design Guidelines](./Design-Guidelines.md)
- **CSP and Azure AD Tenants**
- [Identity, Access Management and Lighthouse](./Identity-Access-Management-and-Lighthouse.md)
- [Management Group and Subscription Organisation](./Management-Group-and-Subscription-Organisation.md)
- [Management and Monitoring](./Management-and-Monitoring.md)
- [Security, Governance and Compliance](./Security-Governance-and-Compliance.md)
- [Platform Automation and DevOps](./Platform-Automation-and-DevOps.md)
---
# Buying Azure - Enrollments and Azure AD Tenants
There are multiple ways of purchasing Azure. As a customer you can buy Azure subscriptions through a direct agreement with Microsoft (MCA/Enterprise agrement), on a credit card or buy directly from partners. When purchasing from a partner - there are two different ways you should be aware of - which will have some implications in billing and support.
[![CSP Models](./media/direct-indirect.JPG)](#)
Figure 1 – CSP Models
CSP Direct model (1-tier)
- Partner works with Microsoft directly
- Fixed discount for Azure
- Partner needs to provide billing tools and build support practice
- Credit check during the onboarding process
CSP Indirect model (2-tier)
- CSP Indirect Provider (aka Distributor) – transacts to Microsoft, provides billing tools and technical support.
- CSP Indirect Reseller – sells Azure to customers through CSP Indirect Provider.
## 1. Planning for Enrollment
A customer have multiple ways of purchasing Azure. If they chose to transact directly from Microsoft - this is often done through an MCA agremeents. Customers can buy Azure and managed services from multiple partners and CSP is a common way for partners to provide support and managed solutions into the customers environment.
A CSP (Cloud Solution Provider) contract represents the commercial relationship between Microsoft, the partner and the customer regarding their use of Azure. It provides the basis for billing across all customer subscriptions and therefore has an impact on administration of the customer estate. A partner will create a tenant with Microsoft or will create subscriptions on an existing tenant. Each subscription will be billed seperately to the partner who will then be able to bill the customer. For more information on CSP please go here: http://aka.ms/csp
***Design Considerations***
- The tenant provides a hierarchical organizational structure to govern the management of customer subscriptions.
- Different customer environments can be separated by using multiple subscriptions on a single tenant to support holistic isolation.
- There can be multiple administrators appointed to a single tenant and or subscription
- Each Subscription must have an associated Account owner.
- Each tenant owner will be made a subscription owner for any subscriptions provisioned under that account. (???)
- A Subscription can only belong to one tenant at any given time.
- A Subscription can be suspended based on a specified set of criteria.
***Design Recommendations***
- Setup the notification account email address to ensure notifications are sent to an appropriate group mailbox.
- Assign a budget for each subscription and establish an alert associated with the budget.
- Leverage the Department organisational element to map customer business divisions. (EA Only?)
- Create a new Department if business domains have independent IT capabilities. (EA Only?)
- Restrict and minimise the number of owners within the tenant to avoid the proliferation of admin access to subscriptions and associated Azure resources.
- Separate Dev/Test/Prod environments at an subscription level to support holistic isolation.
<!-- -->
- Do not ignore notification emails sent to the notification account email address. Microsoft sends important communications to this account.
- Do not move or rename an owner account in Azure AD.
## 2. Define Azure AD Tenants
An Azure AD tenant is an instance of Azure Active Directory which contains accounts and groups, and acts as an authentication source for subscriptions, which must be rooted to a single AAD tenant.
***Design Considerations***
- A single tenant can have multiple CSP Azure subscriptions.
***Design Recommendations***
- Leverage AAD SSO based on the selected [planning topology](https://docs.microsoft.com/en-us/azure/active-directory/hybrid/plan-connect-topologies).
- Enforce MFA and conditional access policies for all privileged accounts.
- Plan for Emergency access or break-glass accounts to prevent tenant-wide account lockout.
- Use AAD PIM for Identity and Access management.
- If Dev/Test/Prod are going to be completely isolated environments from an identity perspective, separate them at a subscription level.
<!-- -->
- Avoid creating a new AAD tenant unless there is a strong IAM justification and processes are already in-place.

18
docs/Design-Guidelines.md Normal file
Просмотреть файл

@ -0,0 +1,18 @@
## Navigation Menu
* [Getting started](../src/platform-automation#platform-automation---getting-started)
* [Landing zones](./Landing-zones.md)
- [Artifacts](./Artifacts.md)
- [Customers](../src/platform-automation/cmdb#customers)
- [Multi tenant deployments](./Multi-tenant-deployments.md)
* [Platform automation at scale](./Platform-automation-at-scale.md)
* **Design Guidelines**
- [CSP and Azure AD Tenants](./CSP-and-Azure-AD-Tenants.md)
- [Identity, Access Management and Lighthouse](./Identity-Access-Management-and-Lighthouse.md)
- [Management Group and Subscription Organisation](./Management-Group-and-Subscription-Organisation.md)
- [Management and Monitoring](./Management-and-Monitoring.md)
- [Security, Governance and Compliance](./Security-Governance-and-Compliance.md)
- [Platform Automation and DevOps](./Platform-Automation-and-DevOps.md)
---
# Design Guidelines

Просмотреть файл

@ -0,0 +1,160 @@
## Navigation Menu
* [Getting started](../src/platform-automation#platform-automation---getting-started)
* [Landing zones](./Landing-zones.md)
- [Artifacts](./Artifacts.md)
- [Customers](../src/platform-automation/cmdb#customers)
- [Multi tenant deployments](./Multi-tenant-deployments.md)
* [Platform automation at scale](./Platform-automation-at-scale.md)
* [Design Guidelines](./Design-Guidelines.md)
- [CSP and Azure AD Tenants](./CSP-and-Azure-AD-Tenants.md)
- **Identity, Access Management and Lighthouse**
- [Management Group and Subscription Organisation](./Management-Group-and-Subscription-Organisation.md)
- [Management and Monitoring](./Management-and-Monitoring.md)
- [Security, Governance and Compliance](./Security-Governance-and-Compliance.md)
- [Platform Automation and DevOps](./Platform-Automation-and-DevOps.md)
---
# Identity, Access Management and Lighthouse
[![Identity and Access Management](./media/iam.png "Identity and Access Management")](#)
Figure 4 – Identity and Access Management
**Identity Baseline** is one of the Five Disciplines of Cloud Governance within the Cloud Adoption Framework governance model. Identity is increasingly considered the primary security perimeter in the cloud, which is a shift from the traditional focus on network security. Identity services provide the core mechanisms supporting access control and organization within IT environments, and the Identity Baseline discipline complements the Security Baseline discipline by consistently applying authentication and authorization requirements across cloud adoption efforts.
This section will examine design considerations and recommendations surrounding identity and access management for Microsoft partners.
## 1. Planning for Authentication Management
A key factor in for a cloud CSP in structuring the cloud-based identity services is the level of integration required with your existing on-premises identity infrastructure. Requirements for authentication inside the "Landing Zone" should therefore be thoroughly assessed and incorporated into plans to deploy AD, AAD-DS or both.
***Design Considerations***
- Centralized and delegated responsibilities to manage resources deployed inside the "Landing Zone".
- Capability and performance differences between AD, AAD, and AAD Domain Services.
- There are some Azure services that rely on AAD-DS, such as HDInsight, Azure File Service, WVD.
- Handling of privileged operations, such as creating a Service Principal within the AAD tenant, Registering Graph applications inside AAD, and procuring a wildcard certificate.
- AAD Proxy frontend authentication for applications relying on Integrated Windows Authentication (IWA), Forms/Header based authentication as well as rich client apps integrated with ADAL.
***Design Recommendations***
- Cloud-based identity management is an iterative process. You should choose the model that is matching your cloud maturity level. One can always start small with a small set of users in a cloud native solution.
- Come up with relevant cloud policy statements to address specific risks identified in the risk assessment cycle. For each statement, identify the following information: **technical risk**, **policy statement**, and **design options**. Some example risks: weak authentication mechanisms, lack of shared management accounts between on premises and the cloud, isolated identity providers, etc.
Expanding one topic as example:
###### Weak authentication mechanisms
**- Technical risk:** Identity management systems with insufficiently secure user authentication methods, such as basic user/password combinations, can lead to compromised or hacked passwords, providing a major risk of unauthorized access to secure cloud systems.
**- Policy statement:** All accounts are required to sign in to secured resources using a multi-factor authentication method.
**- Potential design options:** For Azure Active Directory, implement Azure MFA as part of your user authorization process.
- Evaluate the toolchain options and implement your toolchain by first rolling out in a pre-deployment phase, and then migrate.
- Develop a (draft) Architecture Guideline document. First review for that purpose the use of patterns discussed throughout the architectural decision guides.
- Customize the toolchain based on changes in your organizations requirements and needs. Update the Architecture Guideline document accordingly.
- Evaluate the compatibility of workloads for AD and AAD-DS.
- Deploy AAD-DS within the primary region as this service can be projected into only one subscription.
- Use Virtual Network Peering to support its usage as an authentication service.
- Use Managed Identities instead of Service Principles for authentication to Azure services.
- Use Just-In-Time access for both VM access and Azure control plane administration.
- Do not assume existing workloads are agnostic of AD and AAD-DS authentication, as there are differences between both approaches.
## 2. Planning for Access Management
CSPs will typically follow a least-privileged approach to operational access and this model should be expanded to consider Azure through AAD RBAC and custom role definitions. It is therefore critical to appropriately plan how to govern control plane and data plane access to resources in Azure, while also fully aligning with Joiner/Mover/Leaver (JML) processes.
***Design Considerations***
- There is a limit of 2000 custom RBAC role assignments per subscription.
- There is a limit of 500 custom RBAC role assignments per management group.
- Centralized versus federated resource ownership.
- Shared resources such as the network will need managed centrally.
- The management of application resources can be delegated to application teams.
- Custom role definitions can be used to map responsibility boundaries between central and application teams.
- Azure AD resides in an Azure subscription. Global Admin can self-designate permission to manage Azure. Service & Account Admins are assigned on each subscription.
- Challenges of AOBO (admin on behalf of):
- No granularity between customers. Users in Admin Agents Group get Owner permissions in all Azure subscriptions of all .customers
- No granularity on Azure. Users in Admin Agents Group are owners and role cannot be changed.
- Challenges for MSPs in Azure include such as inconsistent identity management (B2B invites, CSP admin agents, foreign principle), no cross-tenant visibility as well as complexity in managing customers at scale. The recommended solution is to use Azure lighthouse (elaborated more in the recommendations).
***Design Recommendations***
- Use AAD RBAC to manage data plane access to resources where possible (e.g. Key Vault, Storage Account, Azure SQL DB).
- Use AAD PIM to establish zero standing access.
- Use "AAD only" groups for Azure control plane resources in PIM when creating entitlements.
- Add on-premise groups to the "AAD only" group if there is an existing group management system already in place.
- Integrate Azure AD logs with Azure Log Analytics.
- To simplify permissions, evaluate and choose from the built in roles designed to cover most normal scenarios and avoid creating complicated custom roles.
- Avoid Granular and custom permissions specifically referencing resources or users.
- Use *management group* and *resource group* rather than resource specific permissions.
- To *assign access to groups in Azure AD* rather than using user specific permissions.
- Use Identity Score in Azure Active Directory to identify key recommendations and monitor progress.
- Govern all the employees, vendors, and contractors that take on administrative rights need by leveraging the “Just-In-Time” and “Just-Enough” admin capabilities of AAD PIM.
- Set up a process to manage access beyond what was initially provisioned for a user when that users identity was created. Consider automating the process through technologies such as dynamic groups and entitlements.
- Set up recurring review pattern and regularly review privileges with a business-critical impact.
- Use terms of use to get formal consent from users in form of accepting your terms of use (ToU)
- Use Custom RBAC role definitions within the AAD tenant, considering the following key roles
| Role | Usage | Actions: | No Actions: |
| -------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| Azure Platform Owner | Management Group and Subscription lifecycle management | * | |
| Network Management (NetOps) | Platform wide Global Connectivity management; VNets, UDRs, NSGs, NVAs, VPN, ER etc. | \*/read, Microsoft.Authorization/\*/write, Microsoft.Network/vpnGateways/\*, Microsoft.Network/expressRouteCircuits/\*, Microsoft.Network/routeTables/write, Microsoft.Network/vpnsites/\* | |
| Security Operations (SecOps) | Security Administrator role with a horizontal view across the entire Azure estate and the KV Purge Policy | \*/read, \*/register/action, Microsoft.KeyVault/locations/deletedVaults/purge/action, <br> Microsoft.Insights/alertRules/\*, Microsoft.Authorization/policyDefinitions/\*, Microsoft.Authorization/policyassignments/\*, Microsoft.Authorization/policysetdefinitions/\*, Microsoft.PolicyInsights/\*,Microsoft.Security/\* | |
| Subscription Owner | Delegated Role for Subscription Owner derived from subscription Owner role | * | Microsoft.Authorization/\*/write, Microsoft.Network/vpnGateways/\*, Microsoft.Network/expressRouteCircuits/\*, Microsoft.Network/routeTables/write, Microsoft.Network/vpnsites/\* |
| Application Owners DevOps/AppOps | Contributor role granted for application/operations team at resource group level | | Microsoft.Network/publicIPAddresses/write, Microsoft.Network/virtualNetworks/write, Microsoft.KeyVault/locations/deletedVaults/purge/action |
- Use JIT for all IaaS Resources to enable network level protection.
- Use AAD Managed Service Identities (MSI) for Azure resources, avoiding username and password-based authentication.
- Use privileged identities for automation runbooks that require elevated access permissions.
<!-- -->
- Do not add users directly to Azure resource scopes.
- Adopt **Azure Lighthouse** , which offers service providers a single control plane to view and manage Azure across all their customers with higher automation, scale, and enhanced governance:
- it allows finer control on what permission each user/group gets
- shall reduce the number of users with the Admin Agents role
- Enable all advanced security features for those users (MFA, IP, PIM)
- Some best security practices:
- Enable MFA on MSP tenant
- Apply principle of least privilege
- Use AAD PIM to control access to delegated groups (in private preview)
- Additional segmentation can be achieved creating groups per customer or industry segment
- Example:
1. Tier 1 support group assigned to every customer as Reader
2. Tier 2 and 3 support are assigned on a customer by customer basis
--> This would mean creating one marketplace offer plan or template per industry or per customer

18
docs/Landing-zones.md Normal file
Просмотреть файл

@ -0,0 +1,18 @@
## Navigation Menu
* [Getting started](../src/platform-automation#platform-automation---getting-started)
* **Landing zones**
- [Artifacts](./Artifacts.md)
- [Customers](../src/platform-automation/cmdb#customers)
- [Multi tenant deployments](./Multi-tenant-deployments.md)
* [Platform automation at scale](./Platform-automation-at-scale.md)
* [Design Guidelines](./Design-Guidelines.md)
- [CSP and Azure AD Tenants](./CSP-and-Azure-AD-Tenants.md)
- [Identity, Access Management and Lighthouse](./Identity-Access-Management-and-Lighthouse.md)
- [Management Group and Subscription Organisation](./Management-Group-and-Subscription-Organisation.md)
- [Management and Monitoring](./Management-and-Monitoring.md)
- [Security, Governance and Compliance](./Security-Governance-and-Compliance.md)
- [Platform Automation and DevOps](./Platform-Automation-and-DevOps.md)
---
# Landing zones

Просмотреть файл

@ -0,0 +1,81 @@
## Navigation Menu
* [Getting started](../src/platform-automation#platform-automation---getting-started)
* [Landing zones](./Landing-zones.md)
- [Artifacts](./Artifacts.md)
- [Customers](../src/platform-automation/cmdb#customers)
- [Multi tenant deployments](./Multi-tenant-deployments.md)
* [Platform automation at scale](./Platform-automation-at-scale.md)
* [Design Guidelines](./Design-Guidelines.md)
- [CSP and Azure AD Tenants](./CSP-and-Azure-AD-Tenants.md)
- [Identity, Access Management and Lighthouse](./Identity-Access-Management-and-Lighthouse.md)
- **Management Group and Subscription Organisation**
- [Management and Monitoring](./Management-and-Monitoring.md)
- [Security, Governance and Compliance](./Security-Governance-and-Compliance.md)
- [Platform Automation and DevOps](./Platform-Automation-and-DevOps.md)
---
# Management Group and Subscription Organisation
[![Management Group Hierarchy](./media/mg.png "Management Group Hierarchy")](#)
Figure 1 – Management Group Hierarchy
Within an AAD tenant, Management Group structures help to support organisational mapping and must therefore be appropriately considered when planning Azure adoption at-scale.
***Design Considerations***
- Subscriptions serve as a scale unit so that component workloads can scale within platform [subscription limits](https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits).
- Management groups can be used to aggregate Policy and Initiative assignments.
- There is a limit of 7 levels in any nested Management Group structure.
- Management groups and subscriptions can only support one parent
- Management groups can have many children
- Same subscription can't be part of multiple MGs. You can move subscriptions between MGs.
- Certain role will be needed to create MGs. Check [Management Group Access](https://docs.microsoft.com/en-us/azure/governance/management-groups/overview#management-group-access)
***Design Recommendations***
- Treat subscriptions as a democratised unit of management aligned with business needs and priorities
- Decide which resource types are available in a subscription by default.
- Decide what all standard subscriptions should look like. Considerations include RBAC access, policies, tags, and infrastructure resources.
- Define structures for naming and tagging
- Segregate duties within your team and grant only the amount of access to users that they need to perform their jobs. Instead of giving everybody unrestricted permissions in your Azure subscription or resources, allow only certain actions at a particular scope.
- Prefered to programmatically create new subscriptions via a service principal. You must grant permission to the service principal to create subscriptions.
- Use management groups to model your organization or mirror your billing hierarchy
- Group Subscriptions in MG based on a need for common roles assigned along with Azure Policies and initiatives
- Do not create Subscriptions under the "root" Management Group.
- Do not transpose the organisational structure into a deeply nested management group hierarchy.
- Limit the number of Azure Policy assignments made at the root Management Group scope to avoid managing through exclusions at inherited scopes.
***Example***
[![Production and nonproduction subscriptions](./media/dev-prod.png "Production and nonproduction subscriptions")](#)
Figure 2 – Production and nonproduction subscriptions
- Using separate subscriptions for your production and nonproduction environments creates a boundary that makes management of your resources simpler and safer.
- Azure has specific Dev/Test subscription offerings for nonproduction workloads. These offerings provide discounted rates on Azure services and software licensing.
- Your production and nonproduction environments will likely have different sets of Azure policies. - Using separate subscriptions makes it simple to apply each distinct policy at the subscription level.
- You can allow certain types of Azure resources in your nonproduction subscription for testing purposes. You can enable those resource providers in your nonproduction subscription without making them available in your production environment.
- You can use dev/test subscriptions as isolated sandbox environments. These sandboxes allow administrators and developers to rapidly build up and tear down entire sets of Azure resources. This isolation can also help with data protection and security concerns.
- The acceptable cost thresholds that you define will likely vary between production and dev/test subscriptions.

Просмотреть файл

@ -0,0 +1,93 @@
## Navigation Menu
* [Getting started](../src/platform-automation#platform-automation---getting-started)
* [Landing zones](./Landing-zones.md)
- [Artifacts](./Artifacts.md)
- [Customers](../src/platform-automation/cmdb#customers)
- [Multi tenant deployments](./Multi-tenant-deployments.md)
* [Platform automation at scale](./Platform-automation-at-scale.md)
* [Design Guidelines](./Design-Guidelines.md)
- [CSP and Azure AD Tenants](./CSP-and-Azure-AD-Tenants.md)
- [Identity, Access Management and Lighthouse](./Identity-Access-Management-and-Lighthouse.md)
- [Management Group and Subscription Organisation](./Management-Group-and-Subscription-Organisation.md)
- **Management and Monitoring**
- [Security, Governance and Compliance](./Security-Governance-and-Compliance.md)
- [Platform Automation and DevOps](./Platform-Automation-and-DevOps.md)
---
# Management and Monitoring
[![Monitoring on Azure](./media/monitor.png "Monitoring on Azure")](#)
Figure 1 – Monitoring on Azure
***Design Considerations***
- Understand what should be monitored & who needs to be notified
- Understand out-of-the-box & on-by-default data collection already available for Azure Resources
- Ensure appropriate levels of data access using RBAC. Monitoring Reader or Monitoring Contributor roles can grant access to monitoring data while restricting broader access. Central teams can access all logs with Workspace Access, while individual teams might just be given Resource Access
- Decide whether to use separate or single Application Insights Resource for your scenarior
- Separate resources can help save costs, prevent data mix-up and allow more relaxed access
- Single resource can help keep all relevant telemetry in the same place to use with Application Insights features
- Different independent applications -> Use separate iKeys for each app
- Multiple microservices or roles of one business application -> Use a single iKey; Filter/Segment telemetry by cloud_RoleName property
- Dev, Test & Production -> Use separate iKeys for each stage/environment of release
- A | B Testing -> Use a single iKey; Add custom property to identify variants
- Prefer Metric Alerts for better performance/latency; Use Log Alerts for powerful query-based triggers or lack of metrics
- Consider collecting and integrating additional AKS workload metrics from Prometheus
- Consider custom telemetry to gain valuable logs, distributed tracing & usage insights
- Setup actionable alerts with notifications and/or remediation
- Properly define severity/descriptions and avoid sending blanket notifications to people who cannot take any actions
- Optimize Cost - Collect & Retain only as much data as you need
- Review configuration settings to reduce frequency of data collection and only collect required logs (e.g. avoid Info)
- Setup appropriate data caps to avoid anomalous spikes / bill shocks and configure data cap alerts to avoid losing data
- Use sampling to reduce number of telemetry items that are actually sent from your apps
- Setting lower retention on selected data types can be used to reduce your data costs
- Leverage reserved capacity pricing when appropriate for lower costs
- Evaluate recommendations from Azure Advisor to help optimize Availability, Security, Performance & Cost
- Ways to reduce Logs Data Collection
- Select [common or minimal security events](https://docs.microsoft.com/azure/security-center/security-center-enable-data-collection#data-collection-tier). Change the security audit policy to collect only needed events. Review the need to collect events for: audit filtering platform, audit registry, audit file system, audit kernel object, audit handle manipulation, audit removable storage
- Change [performance counter configuration](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/data-sources-performance-counters) to reduce the frequency of collection and the number of performance counters
- Change [event log configuration](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/data-sources-windows-events) to reduce the number of event logs collected. Collect only required event levels. E.g. do not collect Information level events
- Change [syslog configuration](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/data-sources-syslog) to reduce the number of facilities collected. Collect only required event levels. E.g. do not collect Info and Debug level events
- Change resource log collection to reduce the number of resources send logs to Log Analytics. Collect only required logs
***Design Recommendations***
- Configure Agents & Diagnostic Settings for additional logs/perf counters as needed
- Install Log Analytics Agent to collect data from Guest OS & VM Workloads in LA workspaces. Required for writing Log Analytics Queries or using VM Insights, Azure Security Center or Azure Sentinel.
- Configure Diagnostics Settings in resource-specific mode, which makes it easy to discover schemas and write queries
- Use Dependency Agent to collect discovered data about running processes & external process dependencies on VMs. Required for VM Insights Maps feature and has dependency on Log Analytics Agent.
- Log Analytics workspace setup: use as few as possible, unless there are specific organizational requirements or geographical data sovereignty constraints
- Automate agent deployment, insights enablement & diagnostics settings configuration across resources via:
- Azure Automation DSC (Desired State Configuration)
- Azure CLI / PowerShell
- Azure Resource Manager (ARM) Templates
- Azure Policy
- Integrate with Release Management via Azure DevOps Pipelines/Github actions
- Connect Alerts with ITSM or Ticketing Systems (like Service Now or Pager Duty) for efficient management
- Setup Automation Runbooks and/or Custom Workflows (Logic Apps) for Auto-Healing & Remediations
- Use Action Rules to manage Alert Suppression & Actions at scale
- Create Scheduled Queries via Logic Apps to run custom alerts on schedule
- Auto-Scaling can be performed on a schedule, or based on a runtime metric, such as CPU or memory usage
- Enable Smart Detection Alerts
- Application Insights Smart Detection: Out-of-the-box Alert Rules which help detect anomalies like slow page load time, slow server response time, degradation in server response time, degradation in dependency duration, abnormal rise in exception volume, potential memory leak, potential security issue, etc.
- Dynamic Threshold Metric Alerts: Detect patterns in the data such as seasonality (Hourly/Daily/Weekly). Sensitivity can be set to control amount of deviation from behavior required to trigger an alert (Medium/Low helps reduce Alert Noise).

Просмотреть файл

@ -0,0 +1,17 @@
## Navigation Menu
* [Getting started](../src/platform-automation#platform-automation---getting-started)
* [Landing zones](./Landing-zones.md)
- [Artifacts](./Artifacts.md)
- [Customers](../src/platform-automation/cmdb#customers)
- **Multi tenant deployments**
* [Design Guidelines](./Design-Guidelines.md)
- [CSP and Azure AD Tenants](./CSP-and-Azure-AD-Tenants.md)
- [Identity, Access Management and Lighthouse](./Identity-Access-Management-and-Lighthouse.md)
- [Management Group and Subscription Organisation](./Management-Group-and-Subscription-Organisation.md)
- [Management and Monitoring](./Management-and-Monitoring.md)
- [Security, Governance and Compliance](./Security-Governance-and-Compliance.md)
- [Platform Automation and DevOps](./Platform-Automation-and-DevOps.md)
---
# Multi tenant deployments

Просмотреть файл

@ -0,0 +1,19 @@
## Navigation Menu
* [Getting started](../src/platform-automation#platform-automation---getting-started)
* [Landing zones](./Landing-zones.md)
- [Artifacts](./Artifacts.md)
- [Customers](../src/platform-automation/cmdb#customers)
- [Multi tenant deployments](./Multi-tenant-deployments.md)
* [Platform automation at scale](./Platform-automation-at-scale.md)
* [Design Guidelines](./Design-Guidelines.md)
- [CSP and Azure AD Tenants](./CSP-and-Azure-AD-Tenants.md)
- [Identity, Access Management and Lighthouse](./Identity-Access-Management-and-Lighthouse.md)
- [Management Group and Subscription Organisation](./Management-Group-and-Subscription-Organisation.md)
- [Management and Monitoring](./Management-and-Monitoring.md)
- [Security, Governance and Compliance](./Security-Governance-and-Compliance.md)
- **Platform Automation and DevOps**
---
# Working document
[Open working document](https://microsofteur-my.sharepoint.com/:w:/g/personal/hafianba_microsoft_com/EdSBgTlOEk5LnhXsIfwAmTEB4itZU3wvpXhpSF1BVy7I3w?e=IgOu8P)

Просмотреть файл

@ -0,0 +1,56 @@
## Navigation Menu
* [Getting started](../src/platform-automation#platform-automation---getting-started)
* [Landing zones](./Landing-zones.md)
- [Artifacts](./Artifacts.md)
- [Customers](../src/platform-automation/cmdb#customers)
- [Multi tenant deployments](./Multi-tenant-deployments.md)
* [Platform automation at scale](./Platform-automation-at-scale.md)
* [Design Guidelines](./Design-Guidelines.md)
- [CSP and Azure AD Tenants](./CSP-and-Azure-AD-Tenants.md)
- [Identity, Access Management and Lighthouse](./Identity-Access-Management-and-Lighthouse.md)
- [Management Group and Subscription Organisation](./Management-Group-and-Subscription-Organisation.md)
- [Management and Monitoring](./Management-and-Monitoring.md)
- **Security, Governance and Compliance**
- [Platform Automation and DevOps](./Platform-Automation-and-DevOps.md)
---
# Security, Governance and Compliance
## 1. Data Protection
- Create policies that enforce the use of encryption at rest on VMs and App Services when available.
- When possible, use Microsoft managed encryption keys. This saves time and resources on key management activities.
- If customer requires to manage its own keys, use Azure KeyVault when possible. Use one KeyVault per security boundary.
- See more details about encryption design choices [here](https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/decision-guides/encryption/) and [here](https://docs.microsoft.com/en-us/azure/security/fundamentals/data-encryption-best-practices).
- See Azure Encryption options in the image below
[![Azure Encryotion Options](./media/azure-encryption-options.PNG)](#)
## 2. Security Management
- Enable Azure Security Center (ASC) for all customer subscriptions.
- Create your own customized policies for Azure Security Center that match your own recommendations. You might have several custom policies to adjust to different customer segments (ie. financial vs public sector) or to different managed services you offer (ie. full security posture management service vs managed detection and response).
- Keep every custom policy that you create as code in your repository, to enhance traceability and automation.
- Monitor Secure Score and act upon recommendations. Create your own workflows to automate the response to recommendations (ie. enable Just In Time access for VMs). More details [here](https://docs.microsoft.com/en-us/azure/security-center/workflow-automation).
- Stream ASC recommendations to your log analytics workspace so you can build dashboards and workbooks based on this data. More details [here](https://docs.microsoft.com/en-us/azure/security-center/continuous-export).
## 3. Threat Protection
- When possible enable ASC Standard Tier to add Threat protection capabilities for VMs and PaaS services. Remember that Standard Tier includes Microsoft Defender ATP for Windows Servers.
- Create your own automated response to attacks coming from ASC. More details [here](https://docs.microsoft.com/en-us/azure/security-center/workflow-automation).
- If using Azure Sentinel, connect ASC to it to receive all relevant alerts. If using a different SIEM, configure Continuous Export to send relevant data to Event Hub and then to external SIEM. More details [here](https://docs.microsoft.com/en-us/azure/security-center/continuous-export).
- If using Azure Sentinel as your customer's SIEM, watch [this webinar](https://youtu.be/hwahlwgJPnE) focused on MSSP best practices with all the considerations to take into account.

Двоичные данные
docs/media/HS.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 30 KiB

Двоичные данные
docs/media/MvnetHS.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 52 KiB

Двоичные данные
docs/media/MvnetHSPP.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 76 KiB

Двоичные данные
docs/media/azure-encryption-options.PNG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 84 KiB

Двоичные данные
docs/media/cmanged-nt.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 151 KiB

Двоичные данные
docs/media/create-secret.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 147 KiB

Двоичные данные
docs/media/dev-prod.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 9.8 KiB

Двоичные данные
docs/media/direct-indirect.JPG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 86 KiB

Двоичные данные
docs/media/eg-net-top.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 145 KiB

Двоичные данные
docs/media/global-transit.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 113 KiB

Двоичные данные
docs/media/iam.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичные данные
docs/media/mg.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 167 KiB

Двоичные данные
docs/media/monitor.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 180 KiB

Двоичные данные
docs/media/net-con2.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 232 KiB

Двоичные данные
docs/media/same_aad.JPG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 332 KiB

Двоичные данные
docs/media/separate_aad.JPG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 349 KiB

Двоичные данные
images/Contoso-details.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 113 KiB

Двоичные данные
images/Customers-Overview.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 103 KiB

Двоичные данные
images/Management-groups.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 46 KiB

Двоичные данные
images/Templates.SVT.tests.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 93 KiB

Двоичные данные
images/Wiki-main.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 64 KiB

Двоичные данные
images/secret.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 147 KiB

Просмотреть файл

@ -0,0 +1,110 @@
## Navigation Menu
* **Getting started**
* [Landing zones](../../docs/Landing-zones.md)
- [Artifacts](../../docs/Artifacts.md)
- [Customers](./cmdb#customers)
- [Multi tenant deployments](../../docs/Multi-tenant-deployments.md)
* [Platform automation at scale](../../docs/Platform-automation-at-scale.md)
* [Design Guidelines](../../docs/Design-Guidelines.md)
- [CSP and Azure AD Tenants](../../docs/CSP-and-Azure-AD-Tenants.md)
- [Identity, Access Management and Lighthouse](../../docs/Identity-Access-Management-and-Lighthouse.md)
- [Management Group and Subscription Organisation](../../docs/Management-Group-and-Subscription-Organisation.md)
- [Management and Monitoring](../../docs/Management-and-Monitoring.md)
- [Security, Governance and Compliance](../../docs/Security-Governance-and-Compliance.md)
- [Platform Automation and DevOps](../../docs/Platform-Automation-and-DevOps.md)
---
# Platform automation - getting started
This section is used to setup the exact environment. Once you fork this repository from GitHub or use this template, the following are required:
- An Azure Storage account (for storing artifacts)
- An SPN for your Azure Lighthouse automation (e.g. scanning for subscriptions, deploying at scale etc)
- An SPN for with User Access administrator access (or global admin) for customer platform provisioning and automation
- Update variables
## Create storage account used for artifacts
All the artifacts defined in the artifacts repo will be published in a storage account. All the customer deployments will use that storage account to access the templates/definitions that need to be deployed.
cd .\src\platform-automation
Add-Azaccount
$rg = new-AzResourceGroup -resourcegroupname 'rg-prod-automation' -location 'west europe'
$deploy = new-azresourcegroupdeployment -resourcegroup $rg.ResourceGroupName -templateFile .\artifacts\templates\resourcegroup\Storage-Account.json -storageAccountNamePrefix 'devops' -verbose
# Output names & key
$deploy.outputs.storageAccountName.value
$deploy.outputs.masterKey.value
***Copy these value for storageAccount and masterKey*** as these will be stored as ***secrets*** in Github and used by the pipelines to publish the artifacts & do the deployments.
## Update variables (Github)
- Update the workflows
- Replace the value for storageAccountName and paste your value
- Add a github secret
- Secretname: AZURE_DEPLOYMENT_STORAGE_SAS with masterKey value
## Create SPN and add as secret to Github (actions)
### Create SPN (User Access Administrator)
Instructions for how to create an SPN for deployments in customer tenant.
From Azure CLI:
az ad sp create-for-rbac --name "DevOpsGlobalAdmin" --role 'Owner' --sdk-auth
As a recommendation, include the SPN in the Lighthouse offer for your customers. In this way, the SPN will have access to all the delegated resources and can be used to do the deployments across multiple customers at once, with one identity access.
You might want to give this SPN User Access Administrator as well to elevate privileges for certain deployments. You can achieve this by elevating the User Access Administrator and Owner to root level:
New-AzRoleAssignment -ApplicationId '<appId>' -RoleDefinitionName 'User Access Administrator' -Scope /
New-AzRoleAssignment -ApplicationId '<appID' -RoleDefinitionName 'Owner' -Scope /
Your output will be something like this - copy and paste the entire string
{
"clientId": "<<Retracted>>,
"clientSecret": "<<Retracted>>",
"subscriptionId": "<<Retracted>>",
"tenantId": "<<Retracted>>",
"activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
"resourceManagerEndpointUrl": "https://management.azure.com/",
"activeDirectoryGraphResourceId": "https://graph.windows.net/",
"sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
"galleryEndpointUrl": "https://gallery.azure.com/",
"managementEndpointUrl": "https://management.core.windows.net/"
}
Copy the entire json string as this will be stored as a secret in Github.
### Create Github secrets
1. On GitHub, navigate to the main page of the repository.
2. Under your repository name, click on the "Settings" tab.
3. In the left sidebar, click Secrets.
4. On the right bar, click on "Add a new secret"
[![Create Github secret](../../docs/media/create-secret.png)](#)
5. Add the secret name: AZURE_STORAGE_ACCOUNT with the masterKey value copied when the storage account was created
6. Add the secret name: AZURE_DEPLOYMENT_STORAGE_SAS with the storageAccountName value copied when the storage account was created
7. Add the secret name: AZURE_SUBSCRIPTION_CREDENTIAL with the json string value copied when the SPN was created
*** Note *** When managing multiple customers - replace _SUBSCRIPTION_ with Customername instead. E.g AZURE_CONTOSO_CREDENTIAL - and make sure to refer the right credential in the customer pipeline.
[Read more about Github secrets](https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md)
### Create SPN for Lighthouse management & automation
Create the Lighthouse SPN that you will use for automation for managing customers through Lighthouse. Make sure that the SPN is added in the Lighthouse offer for your customers and has the premissions needed. Check this for more info on Lighthouse scenarios and permissions needed.
Call the secret AZURE_LIGHTHOUSE_CREDENTIAL in Github actions and paste the value.
## Resources
#### Creating workflows / Pipelines
[GitHub actions - Docs](https://help.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow)
### ARM deployments
- [Management group deployment](https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/deploy-to-tenant#create-management-group)
### Image packing
https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-automatic-upgrade#automatic-os-image-upgrade-for-custom-images-preview
Packer

Просмотреть файл

@ -0,0 +1,76 @@
{
"kind": "template",
"properties": {
"displayName": "NSG for new VNET",
"dependsOn": [
"vnet-and-subnet-template"
],
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"localPrefix": {
"type": "string",
"metadata": {
"displayName": "Prefix for the resource names deployed in this template"
}
}
},
"variables": {
"subnetId": "[resourceId(resourceGroup().name, 'Microsoft.Network/virtualNetworks/subnets', concat(parameters('localPrefix'),'vnet-blueprint'), concat(parameters('localPrefix'),'subnet-blueprint'))]",
"location": "[resourceGroup().location]",
"existingVirtualNetworkResourceGroupName": "[resourceGroup().name]",
"existingVirtualNetworkName": "[concat(parameters('localPrefix'), 'vnet-blueprint')]",
"existingSubnetName": "[concat(parameters('localPrefix'), 'subnet-blueprint')]",
"newNsgName": "[concat(parameters('localPrefix'), 'nsg-blueprint')]"
},
"resources": [
{
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2018-04-01",
"name": "[variables('newNsgName')]",
"location": "[variables('location')]",
"properties": {
"securityRules": []
}
},
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Resources/deployments",
"name": "associateNsg",
"resourceGroup": "[resourceGroup().name]",
"dependsOn": [
"[variables('newNsgName')]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"resources": [
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Network/virtualNetworks/subnets",
"name": "[concat(variables('existingVirtualNetworkName'), '/', variables('existingSubnetName'))]",
"location": "[variables('location')]",
"properties": {
"addressPrefix": "[reference(variables('subnetId'), '2018-04-01').addressPrefix]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('newNsgName'))]"
}
}
}
]
}
}
}
]
},
"resourceGroup": "SingleRG",
"parameters": {
"localPrefix": {
"value": "[parameters('resourceNamePrefix')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,62 @@
{
"kind": "template",
"properties": {
"displayName": "VNET and one subnet",
"dependsOn": [],
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"localPrefix": {
"type": "string",
"metadata": {
"displayName": "Prefix for the resource names deployed in this template"
}
},
"addressSpaceVnet": {
"type": "string",
"defaultValue": "10.0.0.0/16"
},
"addressSpaceSubnet": {
"type": "string",
"defaultValue": "10.0.0.0/24"
}
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/virtualNetworks",
"name": "[concat(parameters('localPrefix'), 'vnet-blueprint')]",
"location": "[resourceGroup().location]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('addressSpaceVnet')]"
]
},
"subnets": [
{
"name": "[concat(parameters('localPrefix'), 'subnet-blueprint')]",
"properties": {
"addressPrefix": "[parameters('addressSpaceSubnet')]"
}
}
]
}
}
]
},
"resourceGroup": "SingleRG",
"parameters": {
"localPrefix": {
"value": "[parameters('resourceNamePrefix')]"
},
"addressSpaceVnet": {
"value": "[parameters('addressSpaceForVnet')]"
},
"addressSpaceSubnet": {
"value": "[parameters('addressSpaceForSubnet')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,39 @@
{
"properties": {
"displayName": "Basic Networking (VNET)",
"description": "Configures a virtual network with a subnet and an NSG.",
"targetScope": "subscription",
"parameters": {
"resourceNamePrefix": {
"type": "string",
"metadata": {
"displayName": "Resource name prefix",
"description": "Resource group and resource name prefix"
}
},
"addressSpaceForVnet": {
"type": "string",
"metadata": {
"displayName": "Addess space for vnet"
},
"defaultValue": "10.0.0.0/16"
},
"addressSpaceForSubnet": {
"type": "string",
"metadata": {
"displayName": "Addess space for subnet"
},
"defaultValue": "10.0.0.0/24"
}
},
"resourceGroups": {
"SingleRG": {
"name": "[concat(parameters('resourceNamePrefix'),'-RG')]",
"metadata": {
"displayName": "VNET Resource Group"
},
"dependsOn": []
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Append CostCenter TAG & its value from the Resource Group",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/9ea02ca2-71db-412d-8b00-7c7ca9fcd32d",
"parameters": {
"tagName": {
"value": "CostCenter"
}
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Append CostCenter TAG to Resource Groups",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/49c88fc8-6fd1-46fd-a676-f12d1d3a4c71",
"parameters": {
"tagName": {
"value": "CostCenter"
},
"tagValue": {
"value": "[parameters('Policy_CostCenter_Tag')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,325 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Enable Monitoring in Azure Security Center",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8",
"parameters": {
"vmssSystemUpdatesMonitoringEffect": {
"value": "AuditIfNotExists"
},
"vmssEndpointProtectionMonitoringEffect": {
"value": "AuditIfNotExists"
},
"vmssOsVulnerabilitiesMonitoringEffect": {
"value": "AuditIfNotExists"
},
"systemUpdatesMonitoringEffect": {
"value": "AuditIfNotExists"
},
"systemConfigurationsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"endpointProtectionMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diskEncryptionMonitoringEffect": {
"value": "AuditIfNotExists"
},
"networkSecurityGroupsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"webApplicationFirewallMonitoringEffect": {
"value": "AuditIfNotExists"
},
"nextGenerationFirewallMonitoringEffect": {
"value": "AuditIfNotExists"
},
"vulnerabilityAssesmentMonitoringEffect": {
"value": "AuditIfNotExists"
},
"storageEncryptionMonitoringEffect": {
"value": "Audit"
},
"jitNetworkAccessMonitoringEffect": {
"value": "AuditIfNotExists"
},
"adaptiveApplicationControlsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"sqlAuditingMonitoringEffect": {
"value": "AuditIfNotExists"
},
"sqlEncryptionMonitoringEffect": {
"value": "AuditIfNotExists"
},
"sqlDbEncryptionMonitoringEffect": {
"value": "AuditIfNotExists"
},
"sqlServerAuditingMonitoringEffect": {
"value": "AuditIfNotExists"
},
"sqlServerAuditingActionsAndGroupsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInAppServiceMonitoringEffect": {
"value": "Disabled"
},
"diagnosticsLogsInSelectiveAppServicesMonitoringEffect": {
"value": "AuditIfNotExists"
},
"encryptionOfAutomationAccountMonitoringEffect": {
"value": "Audit"
},
"diagnosticsLogsInBatchAccountMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInBatchAccountRetentionDays": {
"value": "365"
},
"metricAlertsInBatchAccountMonitoringEffect": {
"value": "AuditIfNotExists"
},
"classicComputeVMsMonitoringEffect": {
"value": "Audit"
},
"classicStorageAccountsMonitoringEffect": {
"value": "Audit"
},
"diagnosticsLogsInDataLakeAnalyticsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInDataLakeAnalyticsRetentionDays": {
"value": "365"
},
"diagnosticsLogsInDataLakeStoreMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInDataLakeStoreRetentionDays": {
"value": "365"
},
"diagnosticsLogsInEventHubMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInEventHubRetentionDays": {
"value": "365"
},
"diagnosticsLogsInKeyVaultMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInKeyVaultRetentionDays": {
"value": "365"
},
"diagnosticsLogsInLogicAppsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInLogicAppsRetentionDays": {
"value": "365"
},
"diagnosticsLogsInRedisCacheMonitoringEffect": {
"value": "Audit"
},
"diagnosticsLogsInSearchServiceMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInSearchServiceRetentionDays": {
"value": "365"
},
"aadAuthenticationInServiceFabricMonitoringEffect": {
"value": "Audit"
},
"clusterProtectionLevelInServiceFabricMonitoringEffect": {
"value": "Audit"
},
"diagnosticsLogsInServiceBusMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInServiceBusRetentionDays": {
"value": "365"
},
"namespaceAuthorizationRulesInServiceBusMonitoringEffect": {
"value": "Disabled"
},
"aadAuthenticationInSqlServerMonitoringEffect": {
"value": "AuditIfNotExists"
},
"secureTransferToStorageAccountMonitoringEffect": {
"value": "Audit"
},
"diagnosticsLogsInStreamAnalyticsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInStreamAnalyticsRetentionDays": {
"value": "365"
},
"useRbacRulesMonitoringEffect": {
"value": "Audit"
},
"disableUnrestrictedNetworkToStorageAccountMonitoringEffect": {
"value": "Audit"
},
"diagnosticsLogsInServiceFabricMonitoringEffect": {
"value": "AuditIfNotExists"
},
"accessRulesInEventHubNamespaceMonitoringEffect": {
"value": "Disabled"
},
"accessRulesInEventHubMonitoringEffect": {
"value": "Disabled"
},
"sqlDbVulnerabilityAssesmentMonitoringEffect": {
"value": "AuditIfNotExists"
},
"sqlDbDataClassificationMonitoringEffect": {
"value": "AuditIfNotExists"
},
"identityDesignateLessThanOwnersMonitoringEffect": {
"value": "AuditIfNotExists"
},
"identityDesignateMoreThanOneOwnerMonitoringEffect": {
"value": "AuditIfNotExists"
},
"identityEnableMFAForOwnerPermissionsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"identityEnableMFAForWritePermissionsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"identityEnableMFAForReadPermissionsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"identityRemoveDeprecatedAccountWithOwnerPermissionsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"identityRemoveDeprecatedAccountMonitoringEffect": {
"value": "AuditIfNotExists"
},
"identityRemoveExternalAccountWithOwnerPermissionsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"identityRemoveExternalAccountWithWritePermissionsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"identityRemoveExternalAccountWithReadPermissionsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"apiAppConfigureIPRestrictionsMonitoringEffect": {
"value": "Disabled"
},
"functionAppConfigureIPRestrictionsMonitoringEffect": {
"value": "Disabled"
},
"webAppConfigureIPRestrictionsMonitoringEffect": {
"value": "Disabled"
},
"apiAppDisableRemoteDebuggingMonitoringEffect": {
"value": "AuditIfNotExists"
},
"functionAppDisableRemoteDebuggingMonitoringEffect": {
"value": "AuditIfNotExists"
},
"webAppDisableRemoteDebuggingMonitoringEffect": {
"value": "AuditIfNotExists"
},
"apiAppDisableWebSocketsMonitoringEffect": {
"value": "Disabled"
},
"functionAppDisableWebSocketsMonitoringEffect": {
"value": "Disabled"
},
"webAppDisableWebSocketsMonitoringEffect": {
"value": "Disabled"
},
"apiAppEnforceHttpsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"functionAppEnforceHttpsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"webAppEnforceHttpsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"apiAppRestrictCORSAccessMonitoringEffect": {
"value": "AuditIfNotExists"
},
"functionAppRestrictCORSAccessMonitoringEffect": {
"value": "AuditIfNotExists"
},
"webAppRestrictCORSAccessMonitoringEffect": {
"value": "AuditIfNotExists"
},
"apiAppUsedCustomDomainsMonitoringEffect": {
"value": "Disabled"
},
"functionAppUsedCustomDomainsMonitoringEffect": {
"value": "Disabled"
},
"webAppUsedCustomDomainsMonitoringEffect": {
"value": "Disabled"
},
"apiAppUsedLatestDotNetMonitoringEffect": {
"value": "Disabled"
},
"webAppUsedLatestDotNetMonitoringEffect": {
"value": "Disabled"
},
"apiAppUsedLatestJavaMonitoringEffect": {
"value": "Disabled"
},
"webAppUsedLatestJavaMonitoringEffect": {
"value": "Disabled"
},
"webAppUsedLatestNodeJsMonitoringEffect": {
"value": "Disabled"
},
"apiAppUsedLatestPHPMonitoringEffect": {
"value": "Disabled"
},
"webAppUsedLatestPHPMonitoringEffect": {
"value": "Disabled"
},
"apiAppUsedLatestPythonMonitoringEffect": {
"value": "Disabled"
},
"webAppUsedLatestPythonMonitoringEffect": {
"value": "Disabled"
},
"vnetEnableDDoSProtectionMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInIoTHubMonitoringEffect": {
"value": "AuditIfNotExists"
},
"diagnosticsLogsInIoTHubRetentionDays": {
"value": "365"
},
"sqlServerAdvancedDataSecurityMonitoringEffect": {
"value": "AuditIfNotExists"
},
"sqlManagedInstanceAdvancedDataSecurityMonitoringEffect": {
"value": "AuditIfNotExists"
},
"kubernetesServiceRbacEnabledMonitoringEffect": {
"value": "Audit"
},
"vulnerabilityAssessmentOnManagedInstanceMonitoringEffect": {
"value": "AuditIfNotExists"
},
"vulnerabilityAssessmentOnServerMonitoringEffect": {
"value": "AuditIfNotExists"
},
"adaptiveNetworkHardeningsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"restrictAccessToManagementPortsMonitoringEffect": {
"value": "AuditIfNotExists"
},
"restrictAccessToAppServicesMonitoringEffect": {
"value": "AuditIfNotExists"
},
"disableIPForwardingMonitoringEffect": {
"value": "AuditIfNotExists"
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Allowed locations",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c",
"parameters": {
"listOfAllowedLocations": {
"value": "[parameters('Policy_Allowed-Locations')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Allowed locations for resource groups",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/e765b5de-1225-4ba3-bd56-1ac6695af988",
"parameters": {
"listOfAllowedLocations": {
"value": "[parameters('Policy_Allowed-Locations')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,9 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Deploy network watcher when virtual networks are created",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/a9b99dd8-06c5-4317-8629-9d86a3c6e7d9",
"parameters": {}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Resource Types that you do not want to allow in your environment",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/6c112d4e-5bc7-47ae-a041-ea2d9dccd749",
"parameters": {
"listOfResourceTypesNotAllowed": {
"value": "[parameters('Policy_Resource-Types-DENY')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,9 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Secure transfer to storage accounts should be enabled",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/404c3081-a854-4457-ae30-26a93ef643f9",
"parameters": {}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Allowed storage account SKUs",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/7433c107-6db4-4ad1-b57a-a76dce0154a1",
"parameters": {
"listOfAllowedSKUs": {
"value": "[parameters('Policy_Allowed-StorageAccount-SKUs')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Allowed virtual machine SKUs",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/cccc23c7-8427-4f53-ad12-b6a63eb452b3",
"parameters": {
"listOfAllowedSKUs": {
"value": "[parameters('Policy_Allowed-VM-SKUs')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,118 @@
{
"kind": "template",
"properties": {
"displayName": "Deploy Key Vault",
"description": "Deploy Key Vault for Secrets, Certs & Keys",
"dependsOn": [],
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"Organization_Name": {
"type": "string"
},
"KV-AccessPolicy": {
"type": "string"
}
},
"variables": {
"deployment-prefix": "[concat(parameters('Organization_Name'), '-sharedsvcs')]",
"key-vault-name": "[concat(variables('deployment-prefix'), '-kv')]"
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"name": "[variables('key-vault-name')]",
"apiVersion": "2016-10-01",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "KeyVault"
},
"properties": {
"createMode": "default",
"enabledForDeployment": true,
"enabledForDiskEncryption": true,
"enabledForTemplateDeployment": true,
"tenantId": "[subscription().tenantId]",
"sku": {
"name": "premium",
"family": "A"
},
"networkAcls": {
"defaultAction": "Allow",
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": []
},
"accessPolicies": [
{
"objectId": "[parameters('KV-AccessPolicy')]",
"tenantId": "[subscription().tenantId]",
"permissions": {
"keys": [
"get",
"list",
"update",
"create",
"import",
"delete",
"recover",
"backup",
"restore"
],
"secrets": [
"get",
"list",
"set",
"delete",
"recover",
"backup",
"restore"
],
"certificates": [
"get",
"list",
"update",
"create",
"import",
"delete",
"recover",
"deleteissuers",
"recover",
"managecontacts",
"manageissuers",
"getissuers",
"listissuers",
"setissuers"
]
}
}
]
}
},
{
"type": "Microsoft.KeyVault/vaults/providers/locks",
"apiVersion": "2016-09-01",
"name": "[concat(variables('key-vault-name'), '/Microsoft.Authorization/keyVaultDoNotDelete')]",
"dependsOn": [
"[concat('Microsoft.KeyVault/vaults/', variables('key-vault-name'))]"
],
"comments": "Resource lock on key vault",
"properties": {
"level": "CannotDelete"
}
}
],
"outputs": {}
},
"resourceGroup": "SharedServices-RG",
"parameters": {
"Organization_Name": {
"value": "[parameters('Organization_Name')]"
},
"KV-AccessPolicy": {
"value": "[parameters('KV-AccessPolicy')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,148 @@
{
"kind": "template",
"properties": {
"displayName": "Deploy Log Analytics",
"description": "Deploy Log Analytics for Diagnostics",
"dependsOn": [],
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"Organization_Name": {
"type": "string"
},
"data-retention": {
"type": "int",
"defaultValue": 365,
"minValue": 0,
"maxValue": 365,
"metadata": {
"displayName": "Log retention in days",
"description": "Number of days data will be retained for"
}
},
"location": {
"type": "string",
"metadata": {
"displayName": "Location",
"description": "Region used when establishing the workspace"
},
"allowedValues": [
"Australia Central",
"Australia East",
"Australia Southeast",
"Brazil South",
"Canada Central",
"Central India",
"Central US",
"East Asia",
"East US",
"East US 2",
"France Central",
"Japan East",
"Korea Central",
"North Central US",
"North Europe",
"South Africa North",
"South Central US",
"Southeast Asia",
"UK South",
"UK West",
"West Europe",
"West US",
"West US 2"
]
}
},
"variables": {
"deployment-prefix": "[concat(parameters('Organization_Name'), '-sharedsvcs')]",
"uniqueString": "[uniqueString(subscription().id, concat(variables('deployment-prefix'), '-log'))]",
"diagnostic-storageAccount-prefix": "[concat(replace(variables('deployment-prefix'), '-', ''), 'diag')]",
"diagnostic-storageAccount-name": "[toLower(substring(replace(concat(variables('diagnostic-storageAccount-prefix'), variables('uniqueString'), variables('uniqueString')), '-', ''), 0, 23) )]",
"oms-workspace-name": "[concat(variables('deployment-prefix'), '-log')]"
},
"resources": [
{
"comments": "----DIAGNOSTICS STORAGE ACCOUNT-----",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('diagnostic-storageAccount-name')]",
"apiVersion": "2018-07-01",
"location": "[resourceGroup().location]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS"
},
"tags": {
"displayName": "Storage Account"
},
"properties": {
"encryption": {
"keySource": "Microsoft.Storage",
"services": {
"blob": {
"enabled": true
},
"file": {
"enabled": true
}
}
},
"supportsHttpsTrafficOnly": true
}
},
{
"type": "Microsoft.Storage/storageAccounts/providers/locks",
"apiVersion": "2016-09-01",
"name": "[concat(variables('diagnostic-storageAccount-name'), '/Microsoft.Authorization/storageDoNotDelete')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', variables('diagnostic-storageAccount-name'))]"
],
"comments": "Resource lock on diagnostic storage account",
"properties": {
"level": "CannotDelete"
}
},
{
"type": "Microsoft.OperationalInsights/workspaces",
"name": "[variables('oms-workspace-name')]",
"apiVersion": "2017-03-15-preview",
"location": "[parameters('location')]",
"tags": {
"displayName": "Log Analytics"
},
"properties": {
"sku": {
"Name": "pergb2018"
},
"retention": "[parameters('data-retention')]"
}
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/locks",
"apiVersion": "2016-09-01",
"name": "[concat(variables('oms-workspace-name'), '/Microsoft.Authorization/logAnalyticsDoNotDelete')]",
"dependsOn": [
"[variables('oms-workspace-name')]"
],
"comments": "Resource lock on Log Analytics",
"properties": {
"level": "CannotDelete"
}
}
],
"outputs": {}
},
"resourceGroup": "SharedServices-RG",
"parameters": {
"Organization_Name": {
"value": "[parameters('Organization_Name')]"
},
"data-retention": {
"value": "[parameters('LogAnalytics_DataRetention')]"
},
"location": {
"value": "[parameters('LogAnalytics_Location')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,26 @@
{
"kind": "template",
"properties": {
"displayName": "Azure Security Center template",
"description": "Set Security Center Standard",
"dependsOn": [],
"template": {
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.1",
"parameters": {},
"variables": {},
"resources": [
{
"type": "Microsoft.Security/pricings",
"apiVersion": "2017-08-01-preview",
"name": "default",
"properties": {
"pricingTier": "Standard"
}
}
],
"outputs": {}
},
"parameters": {}
}
}

Просмотреть файл

@ -0,0 +1,336 @@
{
"properties": {
"displayName": "CAF Foundation",
"description": "Microsoft Cloud Adoption Framework for Azure – Configure Foundational best practices",
"targetScope": "subscription",
"parameters": {
"Policy_CostCenter_Tag": {
"type": "string",
"metadata": {
"displayName": "Append CostCenter TAG & its value from the Resource Group",
"description": "AzureRegion"
},
"allowedValues": []
},
"Policy_Allowed-Locations": {
"type": "array",
"metadata": {
"displayName": "Which Azure Regions will you allow resources to be built in?",
"description": "Policy_Allowed-Locations",
"strongType": "location"
},
"defaultValue": []
},
"Policy_Resource-Types-DENY": {
"type": "array",
"metadata": {
"displayName": "Select the Azure Resource Types that you will DENY",
"description": "Policy_Resource-Types-DENY",
"strongType": "resourceTypes"
}
},
"Policy_Allowed-StorageAccount-SKUs": {
"type": "array",
"metadata": {
"displayName": "Storage Account SKUs you want to ALLOW",
"description": "Policy_Allowed-StorageAccount-SKUs",
"strongType": "storageSKUs"
},
"defaultValue": [
"Standard_LRS"
],
"allowedValues": [
"Premium_LRS",
"Standard_GRS",
"Standard_LRS",
"Standard_RAGRS",
"Standard_ZRS"
]
},
"Policy_Allowed-VM-SKUs": {
"type": "array",
"metadata": {
"displayName": "Virtual Machine SKUs you want to ALLOW",
"description": "Policy_Allowed-VM-SKUs"
},
"defaultValue": [
"Standard_B2ms",
"Standard_DS1_v2",
"Standard_F2s_v2"
],
"allowedValues": [
"Standard_A1_v2",
"Standard_A2m_v2",
"Standard_A2_v2",
"Standard_A4m_v2",
"Standard_A4_v2",
"Standard_A8m_v2",
"Standard_A8_v2",
"Standard_B1ls",
"Standard_B1ms",
"Standard_B1s",
"Standard_B2ms",
"Standard_B2s",
"Standard_B4ms",
"Standard_B8ms",
"Standard_D1_v2",
"Standard_D2s_v3",
"Standard_D2_v2",
"Standard_D2_v3",
"Standard_D3_v2",
"Standard_D4s_v3",
"Standard_D4_v2",
"Standard_D4_v3",
"Standard_D5_v2",
"Standard_D8s_v3",
"Standard_D8_v3",
"Standard_D11_v2",
"Standard_D12_v2",
"Standard_D13_v2",
"Standard_D14_v2",
"Standard_D15_v2",
"Standard_D16s_v3",
"Standard_D16_v3",
"Standard_D32s_v3",
"Standard_D32_v3",
"Standard_D64s_v3",
"Standard_D64_v3",
"Standard_DC2s",
"Standard_DC4s",
"Standard_DS1_v2",
"Standard_DS2_v2",
"Standard_DS3_v2",
"Standard_DS4_v2",
"Standard_DS5_v2",
"Standard_DS11-1_v2",
"Standard_DS11_v2",
"Standard_DS12-1_v2",
"Standard_DS12-2_v2",
"Standard_DS12_v2",
"Standard_DS13-2_v2",
"Standard_DS13-4_v2",
"Standard_DS13_v2",
"Standard_DS14-4_v2",
"Standard_DS14-8_v2",
"Standard_DS14_v2",
"Standard_DS15_v2",
"Standard_E2s_v3",
"Standard_E2_v3",
"Standard_E4-2s_v3",
"Standard_E4s_v3",
"Standard_E4_v3",
"Standard_E8-2s_v3",
"Standard_E8-4s_v3",
"Standard_E8s_v3",
"Standard_E8_v3",
"Standard_E16-4s_v3",
"Standard_E16-8s_v3",
"Standard_E16s_v3",
"Standard_E16_v3",
"Standard_E20s_v3",
"Standard_E20_v3",
"Standard_E32-8s_v3",
"Standard_E32-16s_v3",
"Standard_E32s_v3",
"Standard_E32_v3",
"Standard_E64-16s_v3",
"Standard_E64-32s_v3",
"Standard_E64is_v3",
"Standard_E64i_v3",
"Standard_E64s_v3",
"Standard_E64_v3",
"Standard_F1s",
"Standard_F2s",
"Standard_F2s_v2",
"Standard_F4s",
"Standard_F4s_v2",
"Standard_F8s",
"Standard_F8s_v2",
"Standard_F16s",
"Standard_F16s_v2",
"Standard_F32s_v2",
"Standard_F64s_v2",
"Standard_F72s_v2",
"Standard_GS1",
"Standard_GS2",
"Standard_GS3",
"Standard_GS4",
"Standard_GS4-4",
"Standard_GS4-8",
"Standard_GS5",
"Standard_GS5-8",
"Standard_GS5-16",
"Standard_H8",
"Standard_H8m",
"Standard_H16",
"Standard_H16m",
"Standard_H16mr",
"Standard_H16r",
"Standard_HB60rs",
"Standard_HC44rs",
"Standard_L4s",
"Standard_L8s",
"Standard_L8s_v2",
"Standard_L16s",
"Standard_L16s_v2",
"Standard_L32s",
"Standard_L32s_v2",
"Standard_L64s_v2",
"Standard_L80s_v2",
"Standard_M8-2ms",
"Standard_M8-4ms",
"Standard_M8ms",
"Standard_M16-4ms",
"Standard_M16-8ms",
"Standard_M16ms",
"Standard_M32-8ms",
"Standard_M32-16ms",
"Standard_M32ls",
"Standard_M32ms",
"Standard_M32ts",
"Standard_M64",
"Standard_M64-16ms",
"Standard_M64-32ms",
"Standard_M64ls",
"Standard_M64m",
"Standard_M64ms",
"Standard_M64s",
"Standard_M128",
"Standard_M128-32ms",
"Standard_M128-64ms",
"Standard_M128m",
"Standard_M128ms",
"Standard_M128s",
"Standard_NC6",
"Standard_NC6s_v2",
"Standard_NC6s_v3",
"Standard_NC12",
"Standard_NC12s_v2",
"Standard_NC12s_v3",
"Standard_NC24",
"Standard_NC24r",
"Standard_NC24rs_v2",
"Standard_NC24rs_v3",
"Standard_NC24s_v2",
"Standard_NC24s_v3",
"Standard_ND6s",
"Standard_ND12s",
"Standard_ND24rs",
"Standard_ND24s",
"Standard_NV6",
"Standard_NV6s_v2",
"Standard_NV12",
"Standard_NV12s_v2",
"Standard_NV24",
"Standard_NV24s_v2"
]
},
"Organization_Name": {
"type": "string",
"metadata": {
"displayName": "Enter your organization name (e.g. Contoso), must be unique",
"description": "Organization_Name"
},
"defaultValue": ""
},
"KV-AccessPolicy": {
"type": "string",
"metadata": {
"displayName": "Azure AD Group or User 'ObjectID' to grant permissions in Key Vault.(abc123de-f456-ghi7-89jk-l0mno123pqr4)",
"description": "KV-AccessPolicy"
}
},
"LogAnalytics_DataRetention": {
"type": "int",
"metadata": {
"displayName": "Number of days data will be retained in Log Analytics",
"description": "LogAnalytics_DataRetention"
},
"defaultValue": 365,
"allowedValues": [
30,
60,
90,
120,
180,
365
]
},
"LogAnalytics_Location": {
"type": "string",
"metadata": {
"displayName": "Azure Region used when establishing the Log Analytics workspace",
"description": "LogAnalytics_Location"
},
"allowedValues": [
"Australia Central",
"Australia East",
"Australia Southeast",
"Brazil South",
"Canada Central",
"Central India",
"Central US",
"East Asia",
"East US",
"East US 2",
"France Central",
"Japan East",
"Korea Central",
"North Central US",
"North Europe",
"South Africa North",
"South Central US",
"Southeast Asia",
"UK South",
"UK West",
"West Europe",
"West US",
"West US 2"
]
},
"AzureRegion": {
"type": "string",
"metadata": {
"displayName": "Select the Azure Region to deploy the Resources",
"description": "AzureRegion",
"strongType": "location"
},
"defaultValue": "eastus"
}
},
"resourceGroups": {
"SharedServices-RG": {
"name": "[concat(parameters('Organization_Name'),'-SharedSvcs-rg')]",
"location": "[parameters('AzureRegion')]",
"metadata": {
"displayName": "Resource Group for Shared Services"
},
"dependsOn": []
},
"Network-RG": {
"name": "[concat(parameters('Organization_Name'),'-VNet-rg')]",
"location": "[parameters('AzureRegion')]",
"metadata": {
"displayName": "Resource Group for Networks"
},
"dependsOn": []
},
"Identity-RG": {
"name": "[concat(parameters('Organization_Name'),'-Identity-rg')]",
"location": "[parameters('AzureRegion')]",
"metadata": {
"displayName": "Resource Group for Identity Services"
},
"dependsOn": []
},
"Application-RG": {
"name": "[concat(parameters('Organization_Name'),'-Application-rg')]",
"location": "[parameters('AzureRegion')]",
"metadata": {
"displayName": "Resource Group for First Application"
},
"dependsOn": []
}
}
}
}

Просмотреть файл

@ -0,0 +1 @@

Просмотреть файл

@ -0,0 +1,14 @@
{
"kind": "policyAssignment",
"properties": {
"displayName": "Allowed locations",
"dependsOn": [],
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c",
"parameters": {
"listOfAllowedLocations": {
"value": "[parameters('allowedlocations_listOfAllowedLocations')]"
}
},
"resourceGroup": "ResourceGroup"
}
}

Просмотреть файл

@ -0,0 +1,65 @@
{
"kind": "template",
"properties": {
"displayName": "arm",
"description": "",
"dependsOn": [],
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_ZRS",
"Premium_LRS"
],
"metadata": {
"description": "Storage Account type"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
},
"variables": {
"storageAccountName": "[concat('store', uniquestring(resourceGroup().id))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "StorageV2",
"properties": {}
}
],
"outputs": {
"storageAccountName": {
"type": "string",
"value": "[variables('storageAccountName')]"
}
}
},
"resourceGroup": "ResourceGroup",
"parameters": {
"storageAccountType": {
"value": "[parameters('arm_storageAccountType')]"
},
"location": {
"value": "[parameters('arm_location')]"
}
}
}
}

Просмотреть файл

@ -0,0 +1,54 @@
{
"properties": {
"targetScope": "subscription",
"parameters": {
"arm_storageAccountType": {
"type": "string",
"metadata": {
"displayName": "storageAccountType (arm)",
"description": "Storage Account type"
},
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_ZRS",
"Premium_LRS"
]
},
"rg_name": {
"type": "string",
"metadata": {
"displayName": "location resource group"
},
"allowedValues": []
},
"arm_location": {
"type": "string",
"metadata": {
"displayName": "location (arm)",
"description": "Location for all resources."
},
"allowedValues": []
},
"allowedlocations_listOfAllowedLocations": {
"type": "array",
"metadata": {
"displayName": "Allowed locations (Policy: Allowed locations)",
"strongType": "location"
},
"allowedValues": []
}
},
"resourceGroups": {
"ResourceGroup": {
"location": "westeurope",
"name": "[parameters('rg_name')]",
"metadata": {
"displayName": "rg"
},
"dependsOn": []
}
}
}
}

Просмотреть файл

@ -0,0 +1,901 @@
{
"properties": {
"lenses": {
"0": {
"order": 0,
"parts": {
"0": {
"position": {
"x": 0,
"y": 0,
"colSpan": 18,
"rowSpan": 1
},
"metadata": {
"inputs": [],
"type": "Extension/HubsExtension/PartType/MarkdownPart",
"settings": {
"content": {
"settings": {
"content": "<div style='line-height:50px;'>\n<span style='font-size:16px;font-weight:bold'>AZURE RESOURCE INVENTORY - </span>\n<span>This section gives you an overview of all your Azure resources across all subscriptions that you can access.</span>\n</div>",
"title": "",
"subtitle": ""
}
}
}
}
},
"1": {
"position": {
"x": 0,
"y": 1,
"colSpan": 3,
"rowSpan": 4
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Count of all my Azure resources"
},
{
"name": "query",
"value": "summarize Resources=count()"
},
{
"name": "chartType",
"isOptional": true
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile",
"settings": {}
}
},
"2": {
"position": {
"x": 3,
"y": 1,
"colSpan": 15,
"rowSpan": 4
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Top 10 resource counts by type"
},
{
"name": "query",
"value": "summarize ResourceCount=count() by type\r\n| order by ResourceCount\r\n| extend ['Resource count']=ResourceCount, ['Resource type']=type\r\n| project ['Resource type'], ['Resource count']\r\n| take 10"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"3": {
"position": {
"x": 0,
"y": 5,
"colSpan": 18,
"rowSpan": 1
},
"metadata": {
"inputs": [],
"type": "Extension/HubsExtension/PartType/MarkdownPart",
"settings": {
"content": {
"settings": {
"content": "<div style='line-height:50px'>\r\n<span style='font-size:16px;font-weight:bold'>AZURE COMPUTE INVENTORY - </span>\r\n<span>This section gives you an overview of your Azure Compute usage.</span>\r\n</div>",
"title": "",
"subtitle": ""
}
}
}
}
},
"4": {
"position": {
"x": 0,
"y": 6,
"colSpan": 4,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Virtual machines count (includes classic)"
},
{
"name": "query",
"value": "where type == \"microsoft.compute/virtualmachines\" or type==\"microsoft.classiccompute/virtualmachines\"\r\n| summarize VMCount=count()\r\n| extend ['Count (Virtual Machines)']=VMCount\r\n| project ['Count (Virtual Machines)']"
},
{
"name": "chartType",
"isOptional": true
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile",
"settings": {}
}
},
"5": {
"position": {
"x": 4,
"y": 6,
"colSpan": 4,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Virtual machines by operating system"
},
{
"name": "query",
"value": "where type == \"microsoft.compute/virtualmachines\" or type == \"microsoft.classiccompute/virtualmachines\"\r\n| extend OSType = iff(type == \"microsoft.compute/virtualmachines\", tostring(properties.storageProfile.osDisk.osType),tostring(properties.storageProfile.operatingSystemDisk.operatingSystem)) \r\n| summarize VMCount=count() by OSType\r\n| order by VMCount desc\r\n|extend ['Count (Virtual Machines)']=VMCount\r\n| project OSType, ['Count (Virtual Machines)']"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"6": {
"position": {
"x": 8,
"y": 6,
"colSpan": 6,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Virtual machines by family"
},
{
"name": "query",
"value": "where type == \"microsoft.compute/virtualmachines\" or type == \"microsoft.classiccompute/virtualmachines\"\r\n| extend Size = iff(type == \"microsoft.compute/virtualmachines\", tostring(properties.hardwareProfile.vmSize), tostring(properties.hardwareProfile.size))\r\n| extend Family = extract('([^_]+)_', 1, Size, typeof(string))\r\n| extend Family = iff(strlen(Family) == 0, Size, Family)\r\n| summarize VMCount=count() by Family\r\n| order by VMCount desc\r\n|extend ['Count (Virtual Machines)']=VMCount\r\n| project Family, ['Count (Virtual Machines)']"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"7": {
"position": {
"x": 14,
"y": 6,
"colSpan": 4,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Count of virtual machines by type"
},
{
"name": "query",
"value": "where type == \"microsoft.compute/virtualmachines\" or type==\"microsoft.classiccompute/virtualmachines\"\r\n| summarize VMCount=count() by type\r\n| extend ['Count (Virtual Machines)']=VMCount\r\n| extend Type = iff(type == \"microsoft.compute/virtualmachines\", \"Resource Manager\", \"Classic\")\r\n| project Type,['Count (Virtual Machines)']"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"8": {
"position": {
"x": 0,
"y": 9,
"colSpan": 18,
"rowSpan": 1
},
"metadata": {
"inputs": [],
"type": "Extension/HubsExtension/PartType/MarkdownPart",
"settings": {
"content": {
"settings": {
"content": "<div style='line-height:50px'>\n<span style='font-size:16px;font-weight:bold'>AZURE STORAGE INVENTORY - </span>\n<span>This section gives you an overview of your Azure Storage usage.</span>\n</div>",
"title": "",
"subtitle": ""
}
}
}
}
},
"9": {
"position": {
"x": 0,
"y": 10,
"colSpan": 6,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Count of storage accounts by status"
},
{
"name": "query",
"value": " where type == \"microsoft.storage/storageaccounts\"\r\n | summarize StorageCount=count() by PrimaryStatus=tostring(properties.statusOfPrimary), SecondaryStatus=tostring(properties.statusOfSecondary)\r\n | extend SecondaryStatus= iff(strlen(SecondaryStatus) == 0, \"No secondary\", SecondaryStatus)\r\n | extend ['Count (Storage accounts)']=StorageCount\r\n | project-away StorageCount"
},
{
"name": "chartType",
"isOptional": true
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryGridTile",
"settings": {}
}
},
"10": {
"position": {
"x": 6,
"y": 10,
"colSpan": 3,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Sum of all disk sizes (GB)"
},
{
"name": "query",
"value": "where type == \"microsoft.compute/disks\"\r\n| extend SizeGB = tolong(properties.diskSizeGB)\r\n| summarize ['Total Disk Size (GB)']=sum(SizeGB)"
},
{
"name": "chartType",
"isOptional": true
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile",
"settings": {}
}
},
"11": {
"position": {
"x": 9,
"y": 10,
"colSpan": 5,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Disks (count) by disk state"
},
{
"name": "query",
"value": "where type == \"microsoft.compute/disks\"\r\n| summarize DiskCount=count() by State=tostring(properties.diskState)\r\n| order by DiskCount desc\r\n| extend [\"Count (Disks)\"]=DiskCount\r\n| project State, [\"Count (Disks)\"]"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"12": {
"position": {
"x": 14,
"y": 10,
"colSpan": 4,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Count of storage accounts by type"
},
{
"name": "query",
"value": "where type == \"microsoft.storage/storageaccounts\" or type==\"microsoft.classicstorage/storageaccounts\"\r\n| summarize StorageCount=count() by type\r\n| extend ['Count (Storage Accounts)']=StorageCount\r\n| extend Type = iff(type == \"microsoft.storage/storageaccounts\", \"Resource Manager\", \"Classic\")\r\n| project Type,['Count (Storage Accounts)']"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"13": {
"position": {
"x": 0,
"y": 13,
"colSpan": 18,
"rowSpan": 1
},
"metadata": {
"inputs": [],
"type": "Extension/HubsExtension/PartType/MarkdownPart",
"settings": {
"content": {
"settings": {
"content": "<div style='line-height:50px'>\r\n<span style='font-size:16px;font-weight:bold'>AZURE NETWORKING INVENTORY - </span>\r\n<span>This section gives you an overview of your Azure networking usage.</span>\r\n</div>",
"title": "",
"subtitle": ""
}
}
}
}
},
"14": {
"position": {
"x": 0,
"y": 14,
"colSpan": 4,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Count of virtual networks (includes classic)"
},
{
"name": "query",
"value": "where type == \"microsoft.network/virtualnetworks\"or type == \"microsoft.classicnetwork/virtualnetworks\"\r\n| summarize ['Virtual networks']=count()"
},
{
"name": "chartType",
"isOptional": true
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile",
"settings": {}
}
},
"15": {
"position": {
"x": 4,
"y": 14,
"colSpan": 3,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Count of network interfaces"
},
{
"name": "query",
"value": "where type == \"microsoft.network/networkinterfaces\"\r\n| summarize ['Network interfaces']=count()"
},
{
"name": "chartType",
"isOptional": true
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile",
"settings": {}
}
},
"16": {
"position": {
"x": 7,
"y": 14,
"colSpan": 3,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Total public IPs"
},
{
"name": "query",
"value": "where type == \"microsoft.network/publicipaddresses\"\r\n| summarize ['Number of public IP addresses']=count()"
},
{
"name": "chartType",
"isOptional": true
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile",
"settings": {}
}
},
"17": {
"position": {
"x": 10,
"y": 14,
"colSpan": 8,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Virtual networks by type"
},
{
"name": "query",
"value": "where type == \"microsoft.network/virtualnetworks\" or type==\"microsoft.classicnetwork/virtualnetworks\"\r\n| summarize VNetCount=count() by type\r\n| extend ['Count (Virtual Networks)']=VNetCount\r\n| extend Type = iff(type == \"microsoft.network/virtualnetworks\", \"Resource Manager\", \"Classic\")\r\n| project Type,['Count (Virtual Networks)']"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"18": {
"position": {
"x": 0,
"y": 17,
"colSpan": 18,
"rowSpan": 1
},
"metadata": {
"inputs": [],
"type": "Extension/HubsExtension/PartType/MarkdownPart",
"settings": {
"content": {
"settings": {
"content": "<div style='line-height:50px'>\r\n<span style='font-size:16px;font-weight:bold'>AZURE SQL DATABASES INVENTORY - </span>\r\n<span>This section gives you an overview of your Azure SQL database usage.</span>\r\n</div>",
"title": "",
"subtitle": ""
}
}
}
}
},
"19": {
"position": {
"x": 0,
"y": 18,
"colSpan": 3,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Count of SQL databases"
},
{
"name": "query",
"value": "where type == \"microsoft.sql/servers/databases\"\r\n| summarize DBCount=count()"
},
{
"name": "chartType",
"isOptional": true
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile",
"settings": {}
}
},
"20": {
"position": {
"x": 3,
"y": 18,
"colSpan": 6,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "SQL databases (count) by tier"
},
{
"name": "query",
"value": "where type == \"microsoft.sql/servers/databases\"\r\n| summarize DBCount=count() by Tier=tostring(properties.currentSku.tier)\r\n| order by DBCount desc\r\n|extend ['Count (SQL Databases)']=DBCount\r\n| project Tier, ['Count (SQL Databases)']"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"21": {
"position": {
"x": 9,
"y": 18,
"colSpan": 9,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "SQL databases (count) by max size (GB)"
},
{
"name": "query",
"value": "where type == \"microsoft.sql/servers/databases\"\r\n| extend GB = todouble(properties.maxSizeBytes) / (1024 * 1024 * 1024)\r\n| summarize DBCount=count() by GB\r\n| order by GB desc\r\n|extend ['Count (SQL Databases)']=DBCount\r\n| project GB=strcat(tostring(GB), \" GB\"), ['Count (SQL Databases)']"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"22": {
"position": {
"x": 0,
"y": 21,
"colSpan": 18,
"rowSpan": 1
},
"metadata": {
"inputs": [],
"type": "Extension/HubsExtension/PartType/MarkdownPart",
"settings": {
"content": {
"settings": {
"content": "<div style='line-height:50px'>\r\n<span style='font-size:16px;font-weight:bold'>APP SERVICE INVENTORY - </span>\r\n<span>This section gives you an overview of your Azure App Service usage.</span>\r\n</div>",
"title": "",
"subtitle": ""
}
}
}
}
},
"23": {
"position": {
"x": 0,
"y": 22,
"colSpan": 3,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Count of AppService apps"
},
{
"name": "query",
"value": "where type == \"microsoft.web/sites\"\r\n| summarize SiteCount=count() \r\n|extend ['Count (AppService Apps)']=SiteCount\r\n| project ['Count (AppService Apps)']"
},
{
"name": "chartType",
"isOptional": true
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile",
"settings": {}
}
},
"24": {
"position": {
"x": 3,
"y": 22,
"colSpan": 3,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "Count of AppService plans"
},
{
"name": "query",
"value": "where type == \"microsoft.web/serverfarms\"\r\n| summarize serverFarmCount=count() \r\n|extend ['Count (AppService plans)']=serverFarmCount\r\n| project ['Count (AppService plans)']"
},
{
"name": "chartType",
"isOptional": true
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile",
"settings": {}
}
},
"25": {
"position": {
"x": 6,
"y": 22,
"colSpan": 4,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "AppService Apps by status"
},
{
"name": "query",
"value": "where type == \"microsoft.web/sites\"\r\n| summarize SiteCount=count() by Status=tostring(properties.state) \r\n| order by SiteCount desc\r\n|extend ['Count (AppService Apps)']=SiteCount\r\n| project Status, ['Count (AppService Apps)']"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"26": {
"position": {
"x": 10,
"y": 22,
"colSpan": 8,
"rowSpan": 3
},
"metadata": {
"inputs": [
{
"name": "partTitle",
"value": "AppService apps by kind"
},
{
"name": "query",
"value": "where type == \"microsoft.web/sites\"\r\n| summarize SiteCount=count() by kind \r\n| order by SiteCount desc\r\n|extend ['Count (AppService Apps)']=SiteCount\r\n| project Kind=kind, ['Count (AppService Apps)']"
},
{
"name": "chartType",
"value": 1
},
{
"name": "isShared",
"isOptional": true
},
{
"name": "queryId",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/ArgQueryChartTile",
"settings": {}
}
},
"27": {
"position": {
"x": 0,
"y": 25,
"colSpan": 6,
"rowSpan": 4
},
"metadata": {
"inputs": [
{
"name": "resourceType",
"value": "Microsoft.resourcegraph/queries",
"isOptional": true
},
{
"name": "filter",
"isOptional": true
},
{
"name": "scope",
"isOptional": true
},
{
"name": "kind",
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/BrowseResourcePinnedPart"
}
}
}
}
},
"metadata": {
"model": {
"timeRange": {
"value": {
"relative": {
"duration": 24,
"timeUnit": 1
}
},
"type": "MsPortalFx.Composition.Configuration.ValueTypes.TimeRange"
}
}
}
},
"name": "Azure Inventory Dashboard",
"type": "Microsoft.Portal/dashboards",
"location": "INSERT LOCATION",
"tags": {
"hidden-title": "Azure Inventory Dashboard"
},
"apiVersion": "2015-08-01-preview"
}

Просмотреть файл

@ -0,0 +1,15 @@
Configuration BaseWindowsServer
{
Import-DscResource -ModuleName PSDesiredStateConfiguration
Node localhost
{
File TempFolderIsPresent
{
Ensure = "Present"
Type = "Directory"
Recurse = $true
DestinationPath = "c:\tmp"
}
}
}

Просмотреть файл

@ -0,0 +1 @@

Просмотреть файл

@ -0,0 +1 @@

Просмотреть файл

@ -0,0 +1,29 @@
{
"mode": "all",
"parameters": {
"allowedLocations": {
"type": "array",
"metadata": {
"description": "The list of locations that can be specified when deploying resources",
"strongType": "location",
"displayName": "Allowed locations"
},
"defaultValue": [
"westus2"
]
}
},
"displayName": "Allowed locations",
"description": "This policy enables you to restrict the locations your organization can specify when deploying resources.",
"policyRule": {
"if": {
"not": {
"field": "location",
"in": "[parameters('allowedLocations')]"
}
},
"then": {
"effect": "deny"
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
{
"displayName": "Allowed locations for resource groups",
"policyType": "BuiltIn",
"mode": "All",
"description": "This policy enables you to restrict the locations your organization can create resource groups in. Use to enforce your geo-compliance requirements.",
"parameters": {
"listOfAllowedLocations": {
"type": "Array",
"metadata": {
"description": "The list of locations that resource groups can be created in.",
"strongType": "location",
"displayName": "Allowed locations"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
},
{
"field": "location",
"notIn": "[parameters('listOfAllowedLocations')]"
}
]
},
"then": {
"effect": "deny"
}
}
}

Просмотреть файл

@ -0,0 +1,39 @@
{
"displayName": "Allowed storage account SKUs",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "This policy enables you to specify a set of storage account SKUs that your organization can deploy.",
"metadata": {
"version": "1.0.0",
"category": "Storage"
},
"parameters": {
"listOfAllowedSKUs": {
"type": "Array",
"metadata": {
"description": "The list of SKUs that can be specified for storage accounts.",
"displayName": "Allowed SKUs",
"strongType": "StorageSKUs"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"not": {
"field": "Microsoft.Storage/storageAccounts/sku.name",
"in": "[parameters('listOfAllowedSKUs')]"
}
}
]
},
"then": {
"effect": "Deny"
}
}
}

Просмотреть файл

@ -0,0 +1,39 @@
{
"displayName": "Allowed virtual machine SKUs",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "This policy enables you to specify a set of virtual machine SKUs that your organization can deploy.",
"metadata": {
"version": "1.0.0",
"category": "Compute"
},
"parameters": {
"listOfAllowedSKUs": {
"type": "Array",
"metadata": {
"description": "The list of SKUs that can be specified for virtual machines.",
"displayName": "Allowed SKUs",
"strongType": "VMSKUs"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"not": {
"field": "Microsoft.Compute/virtualMachines/sku.name",
"in": "[parameters('listOfAllowedSKUs')]"
}
}
]
},
"then": {
"effect": "Deny"
}
}
}

Просмотреть файл

@ -0,0 +1,49 @@
{
"displayName": "Append a tag and its value to resource groups",
"policyType": "BuiltIn",
"mode": "All",
"description": "Appends the specified tag and value when any resource group which is missing this tag is created or updated. Does not modify the tags of resource groups created before this policy was applied until those resource groups are changed. New 'modify' effect policies are available that support remediation of tags on existing resources (see https://aka.ms/modifydoc).",
"metadata": {
"version": "1.0.0",
"category": "Tags"
},
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag, such as 'environment'"
}
},
"tagValue": {
"type": "String",
"metadata": {
"displayName": "Tag Value",
"description": "Value of the tag, such as 'production'"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
},
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"exists": "false"
}
]
},
"then": {
"effect": "append",
"details": [
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"value": "[parameters('tagValue')]"
}
]
}
}
}

Просмотреть файл

@ -0,0 +1,41 @@
{
"displayName": "Audit usage of custom RBAC rules",
"policyType": "BuiltIn",
"mode": "All",
"description": "Audit built-in roles such as 'Owner, Contributer, Reader' instead of custom RBAC roles, which are error prone. Using custom roles is treated as an exception and requires a rigorous review and threat modeling",
"metadata": {
"version": "1.0.0",
"category": "General"
},
"parameters": {
"effect": {
"type": "string",
"defaultValue": "Audit",
"allowedValues": [
"Audit",
"Disabled"
],
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Authorization/roleDefinitions"
},
{
"field": "Microsoft.Authorization/roleDefinitions/type",
"equals": "CustomRole"
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}

Просмотреть файл

@ -0,0 +1,103 @@
{
"displayName": "Enable Azure Monitor for VMs",
"policyType": "BuiltIn",
"description": "Enable Azure Monitor for the Virtual Machines (VMs) in the specified scope (Management group, Subscription or resource group). Takes Log Analytics workspace as parameter.",
"metadata": {
"version": "1.0.1",
"category": "Monitoring"
},
"parameters": {
"logAnalytics_1": {
"type": "String",
"metadata": {
"displayName": "Log Analytics workspace",
"description": "Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.",
"strongType": "omsWorkspace"
}
},
"listOfImageIdToInclude_windows": {
"type": "Array",
"defaultValue": [],
"metadata": {
"displayName": "Optional: List of VM images that have supported Windows OS to add to scope",
"description": "Example value: '/subscriptions/<subscriptionId>/resourceGroups/YourResourceGroup/providers/Microsoft.Compute/images/ContosoStdImage'"
}
},
"listOfImageIdToInclude_linux": {
"type": "Array",
"defaultValue": [],
"metadata": {
"displayName": "Optional: List of VM images that have supported Linux OS to add to scope",
"description": "Example value: '/subscriptions/<subscriptionId>/resourceGroups/YourResourceGroup/providers/Microsoft.Compute/images/ContosoStdImage'"
}
}
},
"policyDefinitions": [
{
"policyDefinitionReferenceId": "LogAnalyticsExtension_Windows_VM_Deploy",
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/0868462e-646c-4fe3-9ced-a733534b6a2c",
"parameters": {
"logAnalytics": {
"value": "[parameters('logAnalytics_1')]"
},
"listOfImageIdToInclude": {
"value": "[parameters('listOfImageIdToInclude_windows')]"
}
}
},
{
"policyDefinitionReferenceId": "LogAnalyticsExtension_Linux_VM_Deploy",
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/053d3325-282c-4e5c-b944-24faffd30d77",
"parameters": {
"logAnalytics": {
"value": "[parameters('logAnalytics_1')]"
},
"listOfImageIdToInclude": {
"value": "[parameters('listOfImageIdToInclude_linux')]"
}
}
},
{
"policyDefinitionReferenceId": "DependencyAgentExtension_Windows_VM_Deploy",
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/1c210e94-a481-4beb-95fa-1571b434fb04",
"parameters": {
"listOfImageIdToInclude": {
"value": "[parameters('listOfImageIdToInclude_windows')]"
}
}
},
{
"policyDefinitionReferenceId": "DependencyAgentExtension_Linux_VM_Deploy",
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/4da21710-ce6f-4e06-8cdb-5cc4c93ffbee",
"parameters": {
"listOfImageIdToInclude": {
"value": "[parameters('listOfImageIdToInclude_linux')]"
}
}
},
{
"policyDefinitionReferenceId": "LogAnalytics_OSImage_Audit",
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/32133ab0-ee4b-4b44-98d6-042180979d50",
"parameters": {
"listOfImageIdToInclude_windows": {
"value": "[parameters('listOfImageIdToInclude_windows')]"
},
"listOfImageIdToInclude_linux": {
"value": "[parameters('listOfImageIdToInclude_linux')]"
}
}
},
{
"policyDefinitionReferenceId": "DependencyAgent_OSImage_Audit",
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/11ac78e3-31bc-4f0c-8434-37ab963cea07",
"parameters": {
"listOfImageIdToInclude_windows": {
"value": "[parameters('listOfImageIdToInclude_windows')]"
},
"listOfImageIdToInclude_linux": {
"value": "[parameters('listOfImageIdToInclude_linux')]"
}
}
}
]
}

Просмотреть файл

@ -0,0 +1,58 @@
{
"displayName": "Deploy network watcher when virtual networks are created",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "This policy creates a network watcher resource in regions with virtual networks. You need to ensure existence of a resource group named networkWatcherRG, which will be used to deploy network watcher instances.",
"metadata": {
"version": "1.0.0",
"category": "Network"
},
"parameters": {},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Network/virtualNetworks"
},
"then": {
"effect": "DeployIfNotExists",
"details": {
"type": "Microsoft.Network/networkWatchers",
"resourceGroupName": "networkWatcherRG",
"existenceCondition": {
"field": "location",
"equals": "[field('location')]"
},
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7"
],
"deployment": {
"properties": {
"mode": "incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2016-09-01",
"type": "Microsoft.Network/networkWatchers",
"name": "[concat('networkWatcher_', parameters('location'))]",
"location": "[parameters('location')]"
}
]
},
"parameters": {
"location": {
"value": "[field('location')]"
}
}
}
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,44 @@
{
"displayName": "Secure transfer to storage accounts should be enabled",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "Audit requirement of Secure transfer in your storage account. Secure transfer is an option that forces your storage account to accept requests only from secure connections (HTTPS). Use of HTTPS ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking",
"metadata": {
"version": "1.0.1",
"category": "Storage"
},
"parameters": {
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "The effect determines what happens when the policy rule is evaluated to match"
},
"allowedValues": [
"Audit",
"Deny",
"Disabled"
],
"defaultValue": "Audit"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"not": {
"field": "Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly",
"equals": "True"
}
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}

Просмотреть файл

@ -0,0 +1,28 @@
{
"displayName": "Require a tag on resources",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "Enforces existence of a tag. Does not apply to resource groups.",
"metadata": {
"version": "1.0.1",
"category": "Tags"
},
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag, such as 'environment'"
}
}
},
"policyRule": {
"if": {
"field": "[concat('tags[', parameters('tagName'), ']')]",
"exists": "false"
},
"then": {
"effect": "deny"
}
}
}

Просмотреть файл

@ -0,0 +1 @@

Просмотреть файл

@ -0,0 +1 @@

Просмотреть файл

@ -0,0 +1 @@

Просмотреть файл

@ -0,0 +1,15 @@
# Templates for re-use goes here
## Resource group (most common)
Put templates for resource group deployments here
## Subscription
Put templates for subscription deployments here
## Management Group
Put templates for management group deployments here
## Tenant
Put templates for tenant specific deployments here

Просмотреть файл

@ -0,0 +1,178 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"managedByTenantId": {
"type": "string",
"metadata": {
"description": "Add the tenant id provided by the MSP"
}
},
"managedByName": {
"type": "string",
"metadata": {
"description": "Add the tenant name of the provided MSP"
}
},
"managedByDescription": {
"type": "string",
"metadata": {
"description": "Add the description of the offer provided by the MSP"
}
},
"managedByAuthorizations": {
"type": "array",
"metadata": {
"description": "Add the authZ array provided by the MSP"
}
}
},
"variables": {
"policyDefinitionName": "Enable-Azure-Lighthouse",
"rbacOwner": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
},
"resources": [
{
"type": "Microsoft.Authorization/policyDefinitions",
"apiVersion": "2019-09-01",
"name": "[variables('policyDefinitionName')]",
"properties": {
"description": "Policy to enforce Lighthouse on subscriptions, delegating mgmt to MSP",
"displayName": "Enforce Lighthouse on subscriptions",
"mode": "All",
"policyType": "Custom",
"parameters": {
"managedByTenantId": {
"type": "string",
"defaultValue" : "[parameters('managedByTenantId')]",
"metadata": {
"description": "Add the tenant id provided by the MSP"
}
},
"managedByName": {
"type": "string",
"defaultValue" : "[parameters('managedByName')]",
"metadata": {
"description": "Add the tenant name of the provided MSP"
}
},
"managedByDescription": {
"type": "string",
"defaultValue" : "[parameters('managedByDescription')]",
"metadata": {
"description": "Add the description of the offer provided by the MSP"
}
},
"managedByAuthorizations": {
"type": "array",
"defaultValue" : "[parameters('managedByAuthorizations')]",
"metadata": {
"description": "Add the authZ array provided by the MSP"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Resources/subscriptions"
}
]
},
"then": {
"effect": "deployIfNotExists",
"details": {
"type": "Microsoft.ManagedServices/registrationDefinitions",
"deploymentScope": "Subscription",
"existenceScope": "Subscription",
"roleDefinitionIds": [
"[concat('/providers/Microsoft.Authorization/roleDefinitions/', variables('rbacOwner'))]"
],
"existenceCondition": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.ManagedServices/registrationDefinitions"
},
{
"field": "Microsoft.ManagedServices/registrationAssignments/registrationDefinition.managedByTenantId",
"equals": "[[parameters('managedByTenantId')]"
}
]
},
"deployment": {
"location": "westeurope",
"properties": {
"mode": "incremental",
"parameters": {
"managedByTenantId": {
"value": "[[parameters('managedByTenantId')]"
},
"managedByName": {
"value": "[[parameters('managedByName')]"
},
"managedByDescription": {
"value": "[[parameters('managedByDescription')]"
},
"managedByAuthorizations": {
"value": "[[parameters('managedByAuthorizations')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"managedByTenantId": {
"type": "string"
},
"managedByName": {
"type": "string"
},
"managedByDescription": {
"type": "string"
},
"managedByAuthorizations": {
"type": "array"
}
},
"variables": {
"managedByRegistrationName": "[[guid(parameters('managedByName'))]",
"managedByAssignmentName": "[[guid(parameters('managedByName'))]"
},
"resources": [
{
"type": "Microsoft.ManagedServices/registrationDefinitions",
"apiVersion": "2019-06-01",
"name": "[[variables('managedByRegistrationName')]",
"properties": {
"registrationDefinitionName": "[[parameters('managedByName')]",
"description": "[[parameters('managedByDescription')]",
"managedByTenantId": "[[parameters('managedByTenantId')]",
"authorizations": "[[parameters('managedByAuthorizations')]"
}
},
{
"type": "Microsoft.ManagedServices/registrationAssignments",
"apiVersion": "2019-06-01",
"name": "[[variables('managedByAssignmentName')]",
"dependsOn": [
"[[variables('managedByRegistrationName')]"
],
"properties": {
"registrationDefinitionId": "[[resourceId('Microsoft.ManagedServices/registrationDefinitions/', variables('managedByRegistrationName'))]"
}
}
]
}
}
}
}
}
}
}
}
],
"outputs": {
}
}

Просмотреть файл

@ -0,0 +1,34 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"managedByName": {
"value": "NerdsOfNorway"
},
"managedByDescription": {
"value": "This is the ultimate MSP"
},
"managedByTenantId": {
"value": "<Managed_by_tenantId>"
},
"managedByAuthorizations": {
"value": [
{
"principalId": "<Identity_Object_ID>",
"principalIdDisplayName": "Tier 1 Support",
"roleDefinitionId": "b24988ac-6180-42a0-ab88-20f7382dd24c"
},
{
"principalId": "<Identity_Object_ID>",
"principalIdDisplayName": "Automation Account - Full access",
"roleDefinitionId": "18d7d88d-d35e-4fb5-a5c3-7773c20a72d9",
"delegatedRoleDefinitionIds": [
"b24988ac-6180-42a0-ab88-20f7382dd24c",
"92aaf0da-9dab-42b6-94a3-d43ce8d16293",
"91c1777a-f3dc-4fae-b103-61d183457e46"
]
}
]
}
}
}

Просмотреть файл

@ -0,0 +1,34 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
},
"variables": {
},
"resources": [
{
"type": "Microsoft.Authorization/policyDefinitions",
"apiVersion": "2019-01-01",
"name": "locationpolicy",
"properties": {
"policyType": "Custom",
"parameters": {
},
"policyRule": {
"if": {
"field": "location",
"notequals": "westeurope"
},
"then": {
"effect": "audit"
}
}
}
}
],
"outputs": {
}
}

Просмотреть файл

@ -0,0 +1,52 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"targetMG": {
"type": "string",
"metadata": {
"description": "Target Management Group"
},
"defaultValue" : "Platform"
}
},
"variables": {
"mgScope": "[tenantResourceId('Microsoft.Management/managementGroups', parameters('targetMG'))]"
},
"resources": [
{
"type": "Microsoft.Authorization/policyDefinitions",
"apiVersion": "2019-01-01",
"name": "locationpolicy",
"properties": {
"policyType": "Custom",
"parameters": {
},
"policyRule": {
"if": {
"field": "location",
"notequals": "westeurope"
},
"then": {
"effect": "audit"
}
}
}
},
{
"type": "Microsoft.Authorization/policyAssignments",
"apiVersion": "2019-01-01",
"name": "location-lock",
"dependsOn": [
"locationpolicy"
],
"properties": {
"scope": "[variables('mgScope')]",
"policyDefinitionId": "[extensionResourceId(variables('mgScope'), 'Microsoft.Authorization/policyDefinitions', 'locationpolicy')]"
}
}
],
"outputs": {
}
}

Просмотреть файл

@ -0,0 +1,142 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"keyVaultName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the key vault."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Specifies the Azure location where the key vault should be created."
}
},
"enabledForDeployment": {
"type": "bool",
"defaultValue": false,
"allowedValues": [
true,
false
],
"metadata": {
"description": "Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault."
}
},
"enabledForDiskEncryption": {
"type": "bool",
"defaultValue": false,
"allowedValues": [
true,
false
],
"metadata": {
"description": "Specifies whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys."
}
},
"enabledForTemplateDeployment": {
"type": "bool",
"defaultValue": false,
"allowedValues": [
true,
false
],
"metadata": {
"description": "Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault."
}
},
"tenantId": {
"type": "string",
"defaultValue": "[subscription().tenantId]",
"metadata": {
"description": "Specifies the Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet."
}
},
"objectId": {
"type": "string",
"metadata": {
"description": "Specifies the object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must be unique for the list of access policies. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets."
}
},
"keysPermissions": {
"type": "array",
"defaultValue": [
"list"
],
"metadata": {
"description": "Specifies the permissions to keys in the vault. Valid values are: all, encrypt, decrypt, wrapKey, unwrapKey, sign, verify, get, list, create, update, import, delete, backup, restore, recover, and purge."
}
},
"secretsPermissions": {
"type": "array",
"defaultValue": [
"list"
],
"metadata": {
"description": "Specifies the permissions to secrets in the vault. Valid values are: all, get, list, set, delete, backup, restore, recover, and purge."
}
},
"skuName": {
"type": "string",
"defaultValue": "Standard",
"allowedValues": [
"Standard",
"Premium"
],
"metadata": {
"description": "Specifies whether the key vault is a standard vault or a premium vault."
}
}
},
"variables": {
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"name": "[parameters('keyVaultName')]",
"apiVersion": "2018-02-14",
"location": "[parameters('location')]",
"properties": {
"enabledForDeployment": "[parameters('enabledForDeployment')]",
"enabledForDiskEncryption": "[parameters('enabledForDiskEncryption')]",
"enabledForTemplateDeployment": "[parameters('enabledForTemplateDeployment')]",
"tenantId": "[parameters('tenantId')]",
"accessPolicies": [
{
"objectId": "[parameters('objectId')]",
"tenantId": "[parameters('tenantId')]",
"permissions": {
"keys": "[parameters('keysPermissions')]",
"secrets": "[parameters('secretsPermissions')]"
}
}
],
"sku": {
"name": "[parameters('skuName')]",
"family": "A"
},
"networkAcls": {
"defaultAction": "Allow",
"bypass": "AzureServices"
}
}
},
{
"type": "Microsoft.KeyVault/vaults/providers/locks",
"apiVersion": "2016-09-01",
"name": "[concat(parameters('keyVaultName'), '/Microsoft.Authorization/keyVaultDoNotDelete')]",
"dependsOn": [
"[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]"
],
"comments": "Resource lock on key vault",
"properties": {
"level": "CannotDelete"
}
}
],
"outputs": {}
}

Просмотреть файл

@ -0,0 +1,104 @@
{
"$schema": "https://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspaceName": {
"type": "String",
"metadata": {
"description": "Specifies the name of the workspace."
}
},
"data-retention": {
"type": "int",
"defaultValue": 365,
"minValue": 30,
"maxValue": 365,
"metadata": {
"displayName": "Log retention in days",
"description": "Number of days data will be retained for"
}
},
"sku": {
"type": "string",
"allowedValues": [
"pergb2018",
"Free",
"Standalone",
"PerNode",
"Standard",
"Premium"
],
"defaultValue": "pergb2018",
"metadata": {
"description": "Pricing tier: PerGB2018 or legacy tiers (Free, Standalone, PerNode, Standard or Premium) which are not available to all customers."
}
},
"location": {
"type": "String",
"allowedValues": [
"australiacentral",
"australiaeast",
"australiasoutheast",
"brazilsouth",
"canadacentral",
"centralindia",
"centralus",
"eastasia",
"eastus",
"eastus2",
"francecentral",
"japaneast",
"koreacentral",
"northcentralus",
"northeurope",
"southafricanorth",
"southcentralus",
"southeastasia",
"uksouth",
"ukwest",
"westcentralus",
"westeurope",
"westus",
"westus2"
],
"metadata": {
"description": "Specifies the location in which to create the workspace."
}
}
},
"variables": {
},
"resources": [
{
"type": "Microsoft.OperationalInsights/workspaces",
"name": "[parameters('workspaceName')]",
"apiVersion": "2017-03-15-preview",
"location": "[parameters('location')]",
"properties": {
"sku": {
"name": "[parameters('sku')]"
},
"retentionInDays": "[parameters('data-retention')]",
"features": {
"searchVersion": 1,
"legacy": 0,
"enableLogAccessUsingOnlyResourcePermissions": true
}
}
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/locks",
"apiVersion": "2016-09-01",
"name": "[concat(parameters('workspaceName'), '/Microsoft.Authorization/logAnalyticsDoNotDelete')]",
"dependsOn": [
"[parameters('workspaceName')]"
],
"comments": "Resource lock on Log Analytics",
"properties": {
"level": "CannotDelete"
}
}
],
"outputs": {}
}

Просмотреть файл

@ -0,0 +1,68 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountNamePrefix": {
"type": "string"
},
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_ZRS",
"Premium_LRS"
],
"metadata": {
"description": "Storage Account type"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
},
"variables": {
"storageAccountName": "[concat(parameters('storageAccountNamePrefix'), uniquestring(resourceGroup().id))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "StorageV2",
"properties": {
}
},
{
"type": "Microsoft.Storage/storageAccounts/providers/locks",
"apiVersion": "2016-09-01",
"name": "[concat(variables('storageAccountName'), '/Microsoft.Authorization/storageDoNotDelete')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]"
],
"comments": "Resource lock on storage account",
"properties": {
"level": "CannotDelete"
}
}
],
"outputs": {
"storageAccountName": {
"type": "string",
"value": "[variables('storageAccountName')]"
},
"masterKey" : {
"type": "string",
"value": "[listKeys(variables('storageAccountName'), '2019-04-01').keys[0].value]"
}
}
}

Просмотреть файл

@ -0,0 +1,191 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"tags": {
"type": "object",
"defaultValue": {}
},
"osType": {
"type": "string",
"allowedValues": [
"Linux",
"Windows"
],
"defaultValue": "Windows"
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_A1",
"allowedValues": [
"Standard_A1",
"Standard_D2_v2",
"Standard_D2_v3"
]
},
"vmName": {
"type": "string",
"minLength": 1
},
"adminUsername": {
"type": "string",
"defaultValue": "contosoadmin",
"metadata": {
"description": "Admin username on all VMs."
}
},
"subnetId": {
"type": "string",
"minLength": 10
},
"nsgRefId": {
"type": "string",
"minLength": 0,
"defaultValue": ""
},
"publicIPRef": {
"type": "string",
"minLength": 0,
"defaultValue": ""
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "Admin password on all VMs."
}
}
},
"variables": {
"osTypeWindows": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "2016-Datacenter",
"version": "latest"
},
"osTypeLinux": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "16.04.0-LTS",
"version": "latest"
},
"vmName": "[parameters('vmName')]",
"osType": "[if(equals(parameters('osType'), 'Linux'), variables('osTypeLinux'), variables('osTypeWindows'))]",
"osProfile": {
"computerName": "[variables('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"vmSANName": "[concat(uniqueString(concat(subscription().id, resourceGroup().id,'vmsa')), 'ba')]",
"vmOSDiskName": "[concat(variables('vmName'), '_OSDisk')]",
"vmIPConfigName": "[concat(variables('vmName'), 'ipconfig')]",
"vmNicName": "[concat(variables('vmName'), 'nic')]",
"storageAccountType": "Standard_LRS",
"ipConfigurationPublicProperties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[parameters('publicIPRef')]"
},
"subnet": {
"id": "[parameters('subnetId')]"
}
},
"ipConfigurationPrivateProperties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[parameters('subnetId')]"
}
},
"ipConfigurationProperties": "[if(greater(length(parameters('publicIPRef')),1), variables('ipConfigurationPublicProperties'), variables('ipConfigurationPrivateProperties'))]",
"nicPropertiesWithNSG": {
"ipConfigurations": [
{
"name": "[variables('vmIPConfigName')]",
"properties": "[variables('ipConfigurationProperties')]"
}
],
"networkSecurityGroup": {
"condition": "[greater(length(parameters('nsgRefId')),5)]",
"id": "[parameters('nsgRefId')]"
}
},
"nicPropertiesWithoutNSG": {
"ipConfigurations": [
{
"name": "[variables('vmIPConfigName')]",
"properties": "[variables('ipConfigurationProperties')]"
}
]
},
"nicProperties": "[if(greater(length(parameters('nsgRefId')),5), variables('nicPropertiesWithNSG'), variables('nicPropertiesWithoutNSG'))]"
},
"resources": [
{
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('vmNicName')]",
"location": "[resourceGroup().location]",
"apiVersion": "2017-04-01",
"properties": "[variables('nicProperties')]",
"tags": "[parameters('tags')]"
},
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('vmSANName')]",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"properties": {
"accountType": "[variables('storageAccountType')]"
},
"tags": "[parameters('tags')]"
},
{
"type": "Microsoft.Compute/virtualMachines",
"name": "[variables('vmName')]",
"location": "[resourceGroup().location]",
"apiVersion": "2017-03-30",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', variables('vmSANName'))]",
"[concat('Microsoft.Network/networkInterfaces/', variables('vmNicName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"osProfile": "[variables('osProfile')]",
"storageProfile": {
"imageReference": "[variables('osType')]",
"osDisk": {
"name": "[variables('vmOSDiskName')]",
"caching": "ReadWrite",
"createOption": "FromImage"
},
"copy": [
{
"count": 2,
"name": "dataDisks",
"input": {
"diskSizeGB": 1023,
"lun": "[copyIndex('dataDisks')]",
"createOption": "Empty"
}
}
]
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',variables('vmNicName'))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": "true",
"storageUri": "[concat('http://',variables('vmSANName'),'.blob.core.windows.net')]"
}
}
},
"tags": "[parameters('tags')]"
}
],
"outputs": {}
}

Просмотреть файл

@ -0,0 +1,117 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"webAppName": {
"type": "string",
"defaultValue": "[concat('webApp-', uniqueString(resourceGroup().id))]",
"metadata": {
"description": "Web app name."
},
"minLength": 2
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"sku": {
"type": "string",
"defaultValue": "F1",
"metadata": {
"description": "The SKU of App Service Plan."
}
},
"language": {
"type": "string",
"defaultValue": ".net",
"allowedValues": [
".net",
"php",
"node",
"html"
],
"metadata": {
"description": "The language stack of the app."
}
},
"repoUrl": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional Git Repo URL, if empty a 'hello world' app will be deploy from the Azure-Samples repo"
}
}
},
"variables": {
"appServicePlanPortalName": "[concat('AppServicePlan-', parameters('webAppName'))]",
"gitRepoReference":{
".net":"https://github.com/Azure-Samples/app-service-web-dotnet-get-started",
"node":"https://github.com/Azure-Samples/nodejs-docs-hello-world",
"php":"https://github.com/Azure-Samples/php-docs-hello-world",
"html":"https://github.com/Azure-Samples/html-docs-hello-world"
},
"gitRepoUrl":"[if(empty(parameters('repoUrl')), variables('gitRepoReference')[parameters('language')], parameters('repoUrl'))]",
"configReference": {
".net": {
"comments": ".Net app. No additional configuration needed."
},
"html": {
"comments": "HTML app. No additional configuration needed."
},
"php": {
"phpVersion": "7.4"
},
"node": {
"appSettings": [
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "12.15.0"
}
]
}
}
},
"resources": [
{
"apiVersion": "2019-08-01",
"type": "Microsoft.Web/serverfarms",
"name": "[variables('appServicePlanPortalName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('sku')]"
}
},
{
"apiVersion": "2019-08-01",
"type": "Microsoft.Web/sites",
"name": "[parameters('webAppName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanPortalName'))]"
],
"properties": {
"siteConfig": "[variables('configReference')[parameters('language')]]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanPortalName'))]"
},
"resources": [
{
"type": "sourcecontrols",
"apiVersion": "2019-08-01",
"name": "web",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('webAppName'))]"
],
"properties": {
"repoUrl": "[variables('gitRepoUrl')]",
"branch": "master",
"isManualIntegration": true
}
}
]
}
]
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше