diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a9a94b52..5b9d4ccd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,38 +1,38 @@ { "name": "Azure CAF landing zones", - + // Update the 'dockerComposeFile' list if you have more compose files or use different names. "dockerComposeFile": "docker-compose.yml", - + + // Container user to use in VSCode Online and GitHub Codespaces + "containerUser" : "vscode", + // The 'service' property is the name of the service for the container that VS Code should // use. Update this value and .devcontainer/docker-compose.yml to the real service name. "service": "rover", - - // Container user to use in VSCode Online and GitHub Codespaces - "containerUser" : "vscode", - + // The optional 'workspaceFolder' property is the path VS Code should open by default when // connected. This is typically a volume mount in .devcontainer/docker-compose.yml "workspaceFolder": "/tf/caf", - - // Use 'settings' to set *default* container specific settings.json values on container create. + + // Use 'settings' to set *default* container specific settings.json values on container create. // You can edit these settings after create using File > Preferences > Settings > Remote. - "settings": { + "settings": { "files.eol": "\n", "terminal.integrated.shell.linux": "/bin/bash", "editor.tabSize": 2, "terminal.integrated.scrollback": 8000, }, - + // Uncomment the next line if you want start specific services in your Docker Compose config. // "runServices": [], - + // Uncomment this like if you want to keep your containers running after VS Code shuts down. // "shutdownAction": "none", - + // Uncomment the next line to run commands after the container is created. - "postCreateCommand": "cp -R /tmp/.ssh-localhost/* ~/.ssh && chmod 700 ~/.ssh && chmod 600 ~/.ssh/*", - + "postCreateCommand": "cp -R /tmp/.ssh-localhost/* ~/.ssh && sudo chmod 600 ~/.ssh/* && sudo chown -R $(whoami) /tf/caf && git config --global core.editor vi && pre-commit install && pre-commit update", + // Add the IDs of extensions you want installed when the container is created in the array below. "extensions": [ "4ops.terraform", @@ -40,4 +40,4 @@ "ms-azure-devops.azure-pipelines", "omartawfik.github-actions-vscode" ] -} +} \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 3a1e24cc..5bf27616 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -2,26 +2,27 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. #------------------------------------------------------------------------------------------------------------- - + version: '3.7' services: rover: - image: aztfmod/rover:2009.0210 - + image: aztfmod/rover:2010.2808 + user: vscode + labels: - "caf=Azure CAF" - + volumes: # This is where VS Code should expect to find your project's source code # and the value of "workspaceFolder" in .devcontainer/devcontainer.json - ..:/tf/caf - volume-caf-vscode:/home/vscode - ~/.ssh:/tmp/.ssh-localhost:ro - - /var/run/docker.sock:/var/run/docker.sock - + - /var/run/docker.sock:/var/run/docker.sock + # Overrides default command so things don't shut down after the process ends. - command: /bin/sh -c "while sleep 1000; do :; done" - + command: /bin/sh -c "while sleep 1000; do :; done" + volumes: volume-caf-vscode: labels: diff --git a/.github/workflows/landingzones.yml b/.github/workflows/landingzones.yml new file mode 100644 index 00000000..7c0e716b --- /dev/null +++ b/.github/workflows/landingzones.yml @@ -0,0 +1,272 @@ +# +# Copyright (c) Microsoft Corporation +# Licensed under the MIT License. +# + +name: landingzones + +on: + pull_request: + paths-ignore: + - 'documentation/**' + - '_pictures/**' + - 'README.md' + - 'CHANGELOG.md' + push: + paths-ignore: + - 'documentation/**' + - '_pictures/**' + - 'README.md' + - 'CHANGELOG.md' + schedule: + - cron: '0 4 * * *' + +env: + TF_CLI_ARGS: '-no-color' + TF_CLI_ARGS_destroy: '-auto-approve -refresh=false' + ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }} + ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }} + ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }} + ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }} + +jobs: + foundations100: + name: foundations-100 + runs-on: ubuntu-latest + + strategy: + fail-fast: true + max-parallel: 1 + matrix: + random_length: ['5'] + + container: + image: aztfmod/rover:2010.2808 + options: --user 0 + + steps: + - uses: actions/checkout@v2 + + - name: Login azure + run: | + az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}' + az account set -s ${{ env.ARM_SUBSCRIPTION_ID }} + + echo "local user: $(whoami)" + + - name: launchpad + run: | + /tf/rover/rover.sh -lz ${GITHUB_WORKSPACE}/landingzones/caf_launchpad -a apply \ + -var-folder ${GITHUB_WORKSPACE}/landingzones/caf_launchpad/scenario/100 \ + -level level0 \ + -launchpad \ + -parallelism=30 \ + --environment ${{ github.run_id }} \ + '-var random_length=${{ matrix.random_length }}' \ + '-var prefix=g${{ github.run_id }}' \ + '-var tags={testing_job_id="${{ github.run_id }}"}' + + - name: foundations + run: | + /tf/rover/rover.sh -lz ${GITHUB_WORKSPACE}/landingzones/caf_foundations -a apply \ + -level level1 \ + -parallelism=30 \ + --environment ${{ github.run_id }} + + networking100: + name: networking-100 + runs-on: ubuntu-latest + + needs: foundations100 + + strategy: + fail-fast: false + matrix: + config_files: [ + "caf_networking/scenario/100-single-region-hub", + "caf_networking/scenario/101-multi-region-hub", + "caf_networking/scenario/105-hub-and-spoke", + "caf_networking/scenario/106-hub-virtual-wan-firewall" + ] + + container: + image: aztfmod/rover:2010.2808 + options: --user 0 + + steps: + - uses: actions/checkout@v2 + + - name: Login azure + run: | + az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}' + az account set -s ${{ env.ARM_SUBSCRIPTION_ID }} + + - name: deploy example + run: | + /tf/rover/rover.sh -lz ${GITHUB_WORKSPACE}/landingzones/caf_networking/ -a apply \ + -tfstate $(basename ${{ matrix.config_files }}).tfstate \ + -level level2 \ + -parallelism=30 \ + -var-folder ${GITHUB_WORKSPACE}/landingzones/${{ matrix.config_files }} \ + --environment ${{ github.run_id }} + + - name: destroy example + run: | + /tf/rover/rover.sh -lz ${GITHUB_WORKSPACE}/landingzones/caf_networking/ -a destroy \ + -tfstate $(basename ${{ matrix.config_files }}).tfstate \ + -level level2 \ + -parallelism=30 \ + -var-folder ${GITHUB_WORKSPACE}/landingzones/${{ matrix.config_files }} \ + --environment ${{ github.run_id }} \ + -refresh=false \ + -auto-approve + + foundations200: + name: foundations-200 + runs-on: ubuntu-latest + needs: networking100 + if: always() + + strategy: + fail-fast: true + max-parallel: 1 + matrix: + random_length: ['5'] + + container: + image: aztfmod/rover:2010.2808 + options: --user 0 + + steps: + - uses: actions/checkout@v2 + + - name: Login azure + run: | + az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}' + az account set -s ${{ env.ARM_SUBSCRIPTION_ID }} + + echo "local user: $(whoami)" + + - name: launchpad-200-upgrade + run: | + /tf/rover/rover.sh -lz ${GITHUB_WORKSPACE}/landingzones/caf_launchpad -a apply \ + -var-folder ${GITHUB_WORKSPACE}/landingzones/caf_launchpad/scenario/200 \ + -level level0 \ + -launchpad \ + -parallelism=30 \ + --environment ${{ github.run_id }} \ + '-var random_length=${{ matrix.random_length }}' \ + '-var prefix=g${{ github.run_id }}' \ + '-var tags={testing_job_id="${{ github.run_id }}"}' + + - name: foundations-200-upgrade + run: | + /tf/rover/rover.sh -lz ${GITHUB_WORKSPACE}/landingzones/caf_foundations -a apply \ + -level level1 \ + --environment ${{ github.run_id }} + + networking200: + name: networking-200 + runs-on: ubuntu-latest + + needs: foundations200 + + strategy: + fail-fast: false + matrix: + config_files: [ + "caf_networking/scenario/200-single-region-hub", + "caf_networking/scenario/201-multi-region-hub", + "caf_networking/scenario/210-aks-private" + ] + + container: + image: aztfmod/rover:2010.2808 + options: --user 0 + + steps: + - uses: actions/checkout@v2 + + - name: Login azure + run: | + az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}' + az account set -s ${{ env.ARM_SUBSCRIPTION_ID }} + + - name: deploy example + run: | + /tf/rover/rover.sh -lz ${GITHUB_WORKSPACE}/landingzones/caf_networking/ -a apply \ + -tfstate $(basename ${{ matrix.config_files }}).tfstate \ + -level level2 \ + -parallelism=30 \ + -var-folder ${GITHUB_WORKSPACE}/landingzones/${{ matrix.config_files }} \ + --environment ${{ github.run_id }} + + - name: destroy example + run: | + /tf/rover/rover.sh -lz ${GITHUB_WORKSPACE}/landingzones/caf_networking/ -a destroy \ + -tfstate $(basename ${{ matrix.config_files }}).tfstate \ + -level level2 \ + -parallelism=30 \ + -var-folder ${GITHUB_WORKSPACE}/landingzones/${{ matrix.config_files }} \ + --environment ${{ github.run_id }} \ + -refresh=false \ + -auto-approve + + foundations_destroy: + name: foundations_destroy + runs-on: ubuntu-latest + if: always() + needs: networking200 + + strategy: + fail-fast: false + matrix: + random_length: ['5'] + + container: + image: aztfmod/rover:2010.2808 + options: --user 0 + + steps: + - uses: actions/checkout@v2 + + - name: Login azure + run: | + az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}' + az account set -s ${{ env.ARM_SUBSCRIPTION_ID }} + + echo "local user: $(whoami)" + + - name: foundations + run: | + /tf/rover/rover.sh -lz ${GITHUB_WORKSPACE}/landingzones/caf_foundations -a destroy \ + -level level1 \ + -parallelism=30 \ + --environment ${{ github.run_id }} \ + -auto-approve + + - name: Remove launchpad + run: | + /tf/rover/rover.sh -lz ${GITHUB_WORKSPACE}/landingzones/caf_launchpad -a destroy \ + -var-folder ${GITHUB_WORKSPACE}/landingzones/caf_launchpad/scenario/200 \ + -level level0 \ + -launchpad \ + -parallelism=30 \ + --environment ${{ github.run_id }} \ + '-var random_length=${{ matrix.random_length }}' \ + '-var prefix=g${{ github.run_id }}' \ + '-var tags={testing_job_id="${{ github.run_id }}"}' \ + -auto-approve + + + - name: Complete purge + if: ${{ always() }} + run: | + for i in `az monitor diagnostic-settings subscription list -o tsv --query "value[?contains(name, '${{ github.run_id }}' )].name"`; do echo "purging subscription diagnostic-settings: $i" && $(az monitor diagnostic-settings subscription delete --name $i --yes); done + for i in `az monitor log-profiles list -o tsv --query '[].name'`; do az monitor log-profiles delete --name $i; done + for i in `az ad group list --query "[?contains(displayName, '${{ github.run_id }}')].objectId" -o tsv`; do echo "purging Azure AD group: $i" && $(az ad group delete --verbose --group $i || true); done + for i in `az ad app list --query "[?contains(displayName, '${{ github.run_id }}')].appId" -o tsv`; do echo "purging Azure AD app: $i" && $(az ad app delete --verbose --id $i || true); done + for i in `az keyvault list-deleted --query "[?tags.environment=='${{ github.run_id }}'].name" -o tsv`; do az keyvault purge --name $i; done + for i in `az group list --query "[?tags.environment=='${{ github.run_id }}'].name" -o tsv`; do echo "purging resource group: $i" && $(az group delete -n $i -y --no-wait || true); done + for i in `az role assignment list --query "[?contains(roleDefinitionName, '${{ github.run_id }}')].roleDefinitionName" -o tsv`; do echo "purging role assignment: $i" && $(az role assignment delete --role $i || true); done + for i in `az role definition list --query "[?contains(roleName, '${{ github.run_id }}')].roleName" -o tsv`; do echo "purging custom role definition: $i" && $(az role definition delete --name $i || true); done diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml deleted file mode 100644 index 192de5cb..00000000 --- a/.github/workflows/master.yml +++ /dev/null @@ -1,278 +0,0 @@ -# -# Copyright (c) Microsoft Corporation -# Licensed under the MIT License. -# - -name: landingzones - -on: - pull_request: - branches: - - master - push: - branches: - - master - paths-ignore: - - 'documentation/**' - - '_pictures/**' - - 'README.md' - - 'CHANGELOG.md' - schedule: - - cron: '0 0 * * *' - -env: - TF_CLI_ARGS: '-no-color' - TF_CLI_ARGS_destroy: '-auto-approve -refresh=false' - ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }} - ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }} - ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }} - ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }} - TFVARS_PATH: '/tf/caf/caf-terraform-landingzones' - -jobs: - tfsec: - name: Run TFsec - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Terraform security scan - uses: triat/terraform-security-scan@v2.0.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - level0: - name: level0 - runs-on: ubuntu-latest - - strategy: - fail-fast: false - max-parallel: 1 - matrix: - region: ["westus2"] - convention: ["random"] - - container: - image: aztfmod/rover:2009.0210 - options: --user 0 - - steps: - - uses: actions/checkout@v2 - - - name: Login azure - run: | - az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}' - az account set -s ${{ env.ARM_SUBSCRIPTION_ID }} - - echo "local user: $(whoami)" - - - name: Locate launchpad - run: | - ln -s ${GITHUB_WORKSPACE} /tf/caf - - id=$(az storage account list --query "[?tags.tfstate=='level0' && tags.environment=='${{ github.run_id }}']" -o json | jq -r .[0].id) - - if [ "${id}" == "null" ]; then - /tf/rover/rover.sh -lz /tf/caf/caf-terraform-landingzones/landingzones/launchpad -a apply \ - -launchpad \ - --environment ${{ github.run_id }} \ - '-var prefix=g${{ github.run_id }}' \ - '-var location=${{ matrix.region }}' \ - '-var convention=${{ matrix.convention }}' \ - '-var tags={testing_job_id="${{ github.run_id }}"}' - fi - - caf_foundations: - name: caf_foundations - runs-on: ubuntu-latest - - needs: level0 - - strategy: - fail-fast: false - matrix: - landingzone: ["landingzone_caf_foundations"] - region: ["southeastasia"] - convention: ["random"] - environment: ["integration-tests"] - - container: - image: aztfmod/rover:2009.0210 - options: --user 0 - - steps: - - uses: actions/checkout@v2 - - - name: setup context - id: context - run: | - ln -s ${GITHUB_WORKSPACE} /tf/caf - echo "ls /tf/caf" && ls -lsa /tf/caf - ls -lsa /tmp - - # workspace='caffoundationsci' - # echo ::set-env name=TF_VAR_workspace::${workspace} - - - name: Login azure - run: | - az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}' - az account set -s ${{ env.ARM_SUBSCRIPTION_ID }} - - echo "local user: $(whoami)" - - - name: deploy caf_foundations - run: | - /tf/rover/rover.sh -lz /tf/caf/caf-terraform-landingzones/landingzones/${{ matrix.landingzone }} -a apply \ - --environment ${{ github.run_id }} \ - -var prefix=g${{ github.run_id}} \ - '-var tags={testing_job_id="${{ github.run_id }}"}' \ - '-var-file ${{ env.TFVARS_PATH }}/environments/${{ matrix.environment }}/${{ matrix.landingzone }}/${{ matrix.landingzone }}_${{ matrix.region }}_${{ matrix.convention }}.tfvars' - - landingzones: - name: landingzones - runs-on: ubuntu-latest - - needs: [level0, caf_foundations] - - strategy: - fail-fast: false - matrix: - landingzone: ["landingzone_networking"] - examples: ["101-multiple-vnets", "102-multiple-vnets-peering", "103-hub-vnet-with-firewall", "104-hub-vnet-with-firewall-bastion", "105-hub-virtual-wan-firewall"] - convention: ["cafrandom"] - - container: - image: aztfmod/rover:2009.0210 - options: --user 0 - - steps: - - uses: actions/checkout@v2 - - - name: setup context - id: context - run: | - ln -s ${GITHUB_WORKSPACE} /tf/caf - echo "ls /tf/caf" && ls -lsa /tf/caf - ls -lsa /tmp - - - name: Login azure - run: | - az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}' - az account set -s ${{ env.ARM_SUBSCRIPTION_ID }} - - echo "local user: $(whoami)" - - - name: Deploy landing_zone - run: | - /tf/rover/rover.sh -lz /tf/caf/caf-terraform-landingzones/landingzones/${{ matrix.landingzone }} -a apply \ - -env ${{ github.run_id }} \ - '-var tags={testing_job_id="${{ github.run_id }}"}' \ - -tfstate ${{ matrix.examples }}_landingzone_networking.tfstate \ - '-var-file ${{ env.TFVARS_PATH }}/landingzones/${{ matrix.landingzone }}/examples/${{ matrix.examples }}/configuration.tfvars' - - - name: Destroy landing_zone - if: always() - run: | - /tf/rover/rover.sh -lz /tf/caf/caf-terraform-landingzones/landingzones/${{ matrix.landingzone }} -a destroy \ - --environment ${{ github.run_id }} \ - '-var tags={testing_job_id="${{ github.run_id }}"}' \ - -tfstate ${{ matrix.examples }}_landingzone_networking.tfstate \ - '-var-file ${{ env.TFVARS_PATH }}/landingzones/${{ matrix.landingzone }}/examples/${{ matrix.examples }}/configuration.tfvars' - - - caf_foundations_destroy: - name: caf_foundations_destroy - runs-on: ubuntu-latest - if: always() - needs: landingzones - - strategy: - fail-fast: false - matrix: - landingzone: ["landingzone_caf_foundations"] - region: ["southeastasia"] - convention: ["random"] - environment: ["integration-tests"] - - container: - image: aztfmod/rover:2009.0210 - options: --user 0 - - steps: - - uses: actions/checkout@v2 - - - name: setup context - id: context - run: | - ln -s ${GITHUB_WORKSPACE} /tf/caf - echo "ls /tf/caf" && ls -lsa /tf/caf - ls -lsa /tmp - - # workspace='caffoundationsci' - # echo ::set-env name=TF_VAR_workspace::${workspace} - - - name: Login azure - run: | - az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}' - az account set -s ${{ env.ARM_SUBSCRIPTION_ID }} - - echo "local user: $(whoami)" - - - name: destroy caf_foundations - run: | - /tf/rover/rover.sh -lz /tf/caf/caf-terraform-landingzones/landingzones/${{ matrix.landingzone }} -a destroy \ - --environment ${{ github.run_id }} \ - -var prefix=g${{ github.run_id}} \ - '-var tags={testing_job_id="${{ github.run_id }}"}' \ - '-var-file ${{ env.TFVARS_PATH }}/environments/${{ matrix.environment }}/${{ matrix.landingzone }}/${{ matrix.landingzone }}_${{ matrix.region }}_${{ matrix.convention }}.tfvars' \ - '-auto-approve' - - level0_destroy: - name: level0_destroy - runs-on: ubuntu-latest - if: always() - needs: caf_foundations_destroy - - strategy: - fail-fast: false - matrix: - region: ["westus2"] - convention: ["random"] - - container: - image: aztfmod/rover:2009.0210 - options: --user 0 - - steps: - - uses: actions/checkout@v2 - - - name: Login azure - run: | - az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}' - az account set -s ${{ env.ARM_SUBSCRIPTION_ID }} - - echo "local user: $(whoami)" - - - name: Remove launchpad - run: | - ln -s ${GITHUB_WORKSPACE} /tf/caf - - /tf/rover/rover.sh -lz /tf/caf/caf-terraform-landingzones/landingzones/launchpad -a destroy \ - -launchpad \ - -env ${{ github.run_id }} \ - '-var prefix=g${{ github.run_id }}' \ - '-var location=${{ matrix.region }}' \ - '-var convention=${{ matrix.convention }}' \ - '-var tags={testing_job_id="${{ github.run_id }}"}' \ - -auto-approve - - - - name: Complete purge - if: ${{ always() }} - run: | - for i in `az monitor log-profiles list -o tsv --query '[].name'`; do az monitor log-profiles delete --name $i; done - for i in `az ad group list --query "[?contains(displayName, '${{ github.run_id }}')].objectId" -o tsv`; do echo "purging Azure AD group: $i" && $(az ad group delete --verbose --group $i || true); done - for i in `az ad app list --query "[?contains(displayName, '${{ github.run_id }}')].appId" -o tsv`; do echo "purging Azure AD app: $i" && $(az ad app delete --verbose --id $i || true); done - for i in `az group list --query "[?tags.testing_job_id=='${{ github.run_id }}'].name" -o tsv`; do echo "purging resource group: $i" && $(az group delete -n $i -y --no-wait || true); done - for i in `az role assignment list --query "[?contains(roleDefinitionName, '${{ github.run_id }}')].roleDefinitionName" -o tsv`; do echo "purging role assignment: $i" && $(az role assignment delete --role $i || true); done - for i in `az role definition list --query "[?contains(roleName, '${{ github.run_id }}')].roleName" -o tsv`; do echo "purging custom role definition: $i" && $(az role definition delete --name $i || true); done diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..1851272c --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +# See http://pre-commit.com for more information +# See http://pre-commit.com/hooks.html for more hooks +repos: + - repo: git://github.com/antonbabenko/pre-commit-terraform + rev: v1.43.0 + hooks: + - id: terraform_fmt + # - id: terraform_docs + # - id: terraform_tflint + # - id: terraform_tfsec + - repo: git://github.com/pre-commit/pre-commit-hooks + rev: v3.3.0 + hooks: + - id: check-merge-conflict + - id: trailing-whitespace + - id: check-yaml + - id: check-added-large-files + # - repo: git://github.com/markdownlint/markdownlint + # rev: v0.9.0 + # hooks: + # - id: markdownlint \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d555d9c..2e83f62d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ -## v8.0.2001 (August 2020) +## v9.0.2009 (September 2020) + +BREAKING CHANGES: + +* Iterating on our new key-based iterative model to simplify deployment and maintenance, this is a major refactoring that will bring compatibility with enterprise-scale landing zones and extensible platform for construction sets (solutions and applications) deployed on top of core landing zones. + +FEATURES: +* **added support for azurerm 2.28 :** On all sample landing zones [azurerm provider](https://github.com/terraform-providers/terraform-provider-azurerm/releases/tag/v2.28.0) + +## v8.0.2008 (August 2020) BREAKING CHANGES: diff --git a/README.md b/README.md index 75ca2e7b..91a696e3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![VScodespaces](https://img.shields.io/endpoint?url=https%3A%2F%2Faka.ms%2Fvso-badge)](https://online.visualstudio.com/environments/new?name=caf%20landing%20zones&repo=azure/caf-terraform-landingzones) [![Gitter](https://badges.gitter.im/aztfmod/community.svg)](https://gitter.im/aztfmod/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - # Azure Cloud Adoption Framework landing zones for Terraform Microsoft [Cloud Adoption Framework for Azure](https://aka.ms/caf) provides you with guidance and best practices to adopt Azure. @@ -24,25 +23,64 @@ Cloud Adoption Framework for Azure Terraform landing zones is an Open Source pro * Propose a prescriptive guidance on how to enable DevOps for infrastructure as code on Microsoft Azure. * Foster a community of Azure *Terraformers* using a common set of practices and sharing best practices. +## What's new in this release + +This release is relying extensively on Terraform 0.13 capabilities (module iterations, conditional modules, variables validation, etc.). + +Those new features allow more complex and more dynamic code composition. The following concepts are used: + +* **No-code environment composition**: a landing zone environment can be composed customizing variable files and code must be robust enough to accommodate combinations and composition. +* **Flexible foundations to meet customer needs**: everything is customizable at all layers. +* **Key-based configuration and customization**: all configuration objects will call each other based on the object keys. +* **Iteration-based objects deployment**: a landing zone calls all its modules, iterating on complex objects for technical resources deployment. +* **Enterprise-scale support**: added support for foundations landing zones to optionally leverage Azure Enterprise-scale module. +* **Terraform Cloud/Enterprise bootstrap**: added initial support for Hashicorp Terraform Cloud/Enterprise to support environment bootstrap. + ## Getting started See our [Getting Started](./documentation/getting_started/getting_started.md) on your laptop, or on the web with [Getting Started on VSCodespaces](./documentation/getting_started/getting_started_codespaces.md). See our [Getting Started Video](https://www.youtube.com/watch?v=t1exCkWft60) +## Sample configuration repository + +When starting an enterprise deployment, we recommend you start creating a configuration repository where you start crafting you configuration environment. + +You can find the [starter repository here](https://github.com/Azure/caf-terraform-landingzones-starter) + ## Documentation More details on how to develop, deploy and operate with landing zones can be found in the reference section [here](./documentation/README.md) ## Sample landing zones -Currently we provide you with the following sample landing zones: +Currently we provide you with the following core sample landing zones: -| Name | Purpose | -|---------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [landingzone_caf_foundations](./landingzones/landingzone_caf_foundations) | setup all the fundamentals for a subscription (logging, accounting, security.). You can find all details of the caf_foundations landing zone [Here](./landingzones/landingzone_caf_foundations/readme.md) | -| [landingzone_networking](./landingzones/landingzone_networking) | enables creation of any Azure networking combination of Virtual Networks-based hub-and-spoke topologies or Azure Virtual WAN based topologies. | -| [launchpad](./landingzones/launchpad) | provides the state management capabilities and security features leveraging Azure storage for the backend, provides secret management and modular approach to support plugin for Azure DevOps automated pipeline creation (and others) | +| Name | Purpose | +|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [caf_foundations](./landingzones/caf_foundations) | setup all the fundamentals for a subscription (logging, accounting, security.). You can find all details of the caf_foundations landing zone [Here](./landingzones/landingzone_caf_foundations/readme.md) | +| [caf_networking](./landingzones/caf_networking) | enables creation of any Azure networking combination of Virtual Networks-based hub-and-spoke topologies or Azure Virtual WAN based topologies. | +| [caf_shared_services](./landingzones/caf_shared_services) | provides shared services like monitoring, Azure Backup, Azure Site Recovery etc. | +| [caf_launchpad](./landingzones/caf_launchpad) | provides the state management capabilities and security features leveraging Azure storage for the backend, provides secret management and modular approach to support plugin for Azure DevOps automated pipeline creation (and others) | + +For each landing zones, we provide different level of configuration examples to meet different purposes: +| level | scenario | requirements | +|-------|----------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------| +| 100 | Start with this one! basic functionalities and features, no RBAC or security hardening - for demo and simple POC | working on any subscription with Owner permissions | +| 200 | intermediate functionalities includes diagnostics features and Azure Active Directory groups | may need custom AAD permissions | +| 300 | advanced functionalities, includes RBAC features, virtual network and private link scenario and reduced portal view for hardened items | need custom AAD permissions | +| 400 | advanced functionalities, includes RBAC features and security hardening | need custom AAD permissions | + +## Landing zone solutions + +Once you deploy the core components, you can leverage the following additional solution landing zones (work in progress!): + +| Solution | URL | +|---------------------------|-------------------------------------------------------| +| Azure Kubernetes Services | https://github.com/aztfmod/landingzone_aks | +| Data and Analytics | https://github.com/aztfmod/landingzone_data_analytics | +| SAP HANA on Azure | Coming Soon | +| Shared Image Gallery | Coming soon | ## Repositories diff --git a/documentation/enterprise/bootstrap_account_provisioning.md b/documentation/enterprise/bootstrap_account_provisioning.md new file mode 100644 index 00000000..d3e04dc3 --- /dev/null +++ b/documentation/enterprise/bootstrap_account_provisioning.md @@ -0,0 +1,155 @@ +# Setting up identity bootstrap account + +The purpose of the CAF Level 0 (L0) bootstrap Azure AD application is to own the creation of the launchpads. During that process a new Azure AD application is created with less permissions on the directory and also more specific Azure permissions to fulfill the Azure operations of the +level0 (subscription creation for example) + +This document explains the manual process to create the L0 Azure AD app and the following information must be captured: + +| Variable | Item | Value | +| -------------------- | ------------------------ | ---- | +|ARM\_CLIENT\_ID | Application (client) ID | | +|ARM\_CLIENT\_SECRET | Client secret | | +|ARM\_TENANT\_ID | Directory (tenant) ID | | +|ARM\_SUBSCRIPTION\_ID | Subscription ID | | + +## Create Azure AD L0 App + +Go to Azure Active Directory + +![](./images/Bootstrap/image1.png) + +Create a **new** Azure **Active Directory Application** + +![](./images/Bootstrap/image2.png) + +![](./images/Bootstrap/image3.png) + +From the property pane select "**API permissions**" + +![](./images/Bootstrap/image4.png) + +**Remove** the default one + +![](./images/Bootstrap/image5.png) + +**Confirm the deletion** + +![](./images/Bootstrap/image6.png) + +Click on "**Add a permission**" + +![](./images/Bootstrap/image7.png) + +Select "**Application permissions**" + +![](./images/Bootstrap/image8.png) + +Select from "**Application**", "**Application.ReadWrite.OwnedBy**" + +![](./images/Bootstrap/image9.png) + +Then from "**Directory**" select "**Directory.ReadWrite.All**" + +![](./images/Bootstrap/image10.png) + +Complete the operation by pressing the blue button "**Add permissions**" + +Click again on "*Add permission*" + +![](./images/Bootstrap/image11.png) + +Select the "**Microsoft Graph**" + +![](./images/Bootstrap/image12.png) + +Select "**Application permissions**" + +![](./images/Bootstrap/image13.png) + +From "**AppRoleAssignment**" select "**AppRoleAssignment.ReadWrite.All**" + +![](./images/Bootstrap/image14.png) + +From "**DelegatedPermissionGrant**" select "**DelegatedPermissionGrant.ReadWrite.All**" + +![](./images/Bootstrap/image15.png) + +From "**Directory**" select "**Directory.ReadWrite.All**" + +![](./images/Bootstrap/MSGraph_directory.png) + +Complete the operation by clicking on the blue button "**Add permissions**" + +You need to be logged-in with a user who has directory role "**Global Admin**" or permission to grant consents. When ready press the button "**Grant admin consent for \[name of your tenant\]**" + +![](./images/Bootstrap/Grant_Admin_Consent.png) + +Confirm + +![](./images/Bootstrap/image17.png) + +You can see the consents have been given with the green tick button + +![](./images/Bootstrap/Granted_Admin_Consent.png) + +Now the Azure Active Directory Application has been created and given the right permission on the APIs, you need to set a complex password. + +From the property pane select "**Certificates & secrets**" + +![](./images/Bootstrap/image19.png) + +Click on "**New client secret**" + +![](./images/Bootstrap/image20.png) + +Put a description -- *date of the creation of the secret* as an example + +![](./images/Bootstrap/image21.png) + +When ready click on the blue button "Add". Note the password will be displayed only after the creation. Copy the password as you will not be able to retrieve it again later. If you missed that step, delete the password and recreate a new one. + +![](./images/Bootstrap/image22.png) + +### Capture the tenant ID + +![](./images/Bootstrap/image23.png) + +Capture the client ID + +![](./images/Bootstrap/image24.png) + +### Capture the subscription ID + +From the Azure Portal search bar, type "**Subscription**" + +![](./images/Bootstrap/image25.png) + +Capture the subscription ID + +![](./images/Bootstrap/image26.png) + +## Grant subscription owner to level0-security + +![](./images/Bootstrap/image25.png) + +Click on the subscription + +![](./images/Bootstrap/image26.png) + +Go to "**Access control (IAM)**" + +![](./images/Bootstrap/image27.png) + +Select "**Add**".. "**Add role assignment**" + +![](./images/Bootstrap/image28.png) + +Select Role as "**Owner**". Set the Azure Active Directory application name you created earlier. + +![](./images/Bootstrap/image29.png) + +Click on the name and then on the "**save**" button + +![](./images/Bootstrap/image30.png) + +If all the steps have been completed successfully, you are ready to deploy the level 0 open source launchpad. \ No newline at end of file diff --git a/documentation/enterprise/environment_setup_Azure_DevOps.md b/documentation/enterprise/environment_setup_Azure_DevOps.md new file mode 100644 index 00000000..d3a74485 --- /dev/null +++ b/documentation/enterprise/environment_setup_Azure_DevOps.md @@ -0,0 +1,97 @@ +# Enterprise Adoption Guide on Cloud Adoption Framework for Azure - Landing zones on Terraform + +## Overview + +In this guide, we summarize steps to get started in an enteprise environment. + + +# Get Started (Step By Step) + +![](./images/Enterprise/Getting_Started.png) + +## Azure Sandpit Environment + +Successful implementations tend to focus on building first a sandpit/innovation hub environment where all stakeholders (IT operations, security, compliance, information protection, finance, and business) define their requirements. + +The DevOps team focuses on building, automating, testing modules, and landing zones to create an infrastructure environment that is good enough. + +We define a sandpit environment as an environment where innovation and experimentations can happen "freely". +As such is it composed of: +- One or more subscriptions that are isolated from ANY customer environment. +- A separate Azure AD tenant space. + +## Azure DevOps + +### Projects + +Ideally multiple projects needed to fully utilize Azure landing zones capabilities: + +* **Main Project** - Repository of your private Terraform code and project management for landing zones adoption in your organization +* **Configuration Projects** - For each environments (Production, Non-production, Sandpit) that you plan to leverage Azure Terraform landing zone, dedicated project in Azure Devops is needed to fully utilize the automation mechanism provided. This will reduce the risk and minimize error on mixing environments configuration files(.tfvars),pipelines and variables. + +Examples Azure DevOps setup: + +| Organization | Project | Purpose | +| ------------ | ------- | ------- | +| Contoso | Azure Terraform Landing Zone | Project Management of LZ and Repository for custom terraform code that specific to Contoso requirements | +| Contoso | contososandpit | Repo to Store configuration file (tfvars), Pipeline, agent pool specific to sandpit | +| Contoso | contosodev | Repo to Store configuration file (tfvars), Pipeline, agent pool specific to nonprod | +| Contoso | contosoprod | Repo to Store configuration file (tfvars), Pipeline, agent pool specific to prod | + +

+ +#### Sandpit IaC Configuration: + +![](./images/Enterprise/Sandpit_IAC.png) + +
+ +#### Prod & NonProd IaC Configuration: + +![](./images/Enterprise/Prod_NonPROD_IAC.png) + + + +### Repositories + +During the lifecycle of the landing zones deployment you will probably find that it is easier to work first with a mono-repository environment but we recommend using multiple repositories as follow: +* **Configuration repository**: [this template can be used](https://github.com/azure/caf-terraform-landingzones-starter) as configuration repository for CAF landing zones, containing definition of the configuration for your different environments. +* **Logic repository**: this Azure CAF landing zone repository. Documentation to come on how to fork this repository. + +This approach allows you to easily: +* check-in your configuration in your specific Git repository. +* resync the code with the public codebase for updates. +* customize the code if needed and contribute back to the community. + +### Full IaC Architecture (Contoso example) + +![](./images/Enterprise/environment_seperation.png) + +## Bootstrap process + +### Bootstrap identity +In order to start consuming Azure Terraform landing zones, we need to create a privileged account to boostrap the environment. + +You can opt for: +1. Using an user account with enough permission (Azure Active Directory Global Administrator) +2. Provision the identity bootstrap account with Azure AD application, you can refer to [the following documentation](./bootstrap_account_provisioning.md) + +## Next steps + +Once you done on those 3 important steps your organization is ready to adopt Azure Terraform Landing Zone. You can start by [following this documentation](../getting_started/getting_started.md) in order to setup your local development environment. + +
+ +*if you are using Azure AD application for bootstrapping you might need to login with below command (with all the details from previous step [from following documentation](./bootstrap_account_provisioning.md)): + +```bash +export ARM_CLIENT_ID= +export ARM_CLIENT_SECRET= +export ARM_TENANT_ID= +export ARM_SUBSCRIPTION_ID= + +az login --service-principal -u ${ARM_CLIENT_ID} -p ${ARM_CLIENT_SECRET} --tenant ${ARM_TENANT_ID} +az account set --subscription ${ARM_SUBSCRIPTION_ID} +``` + +You are good to go. Start with launchpad and continue with higher level landing zones. diff --git a/documentation/enterprise/images/Bootstrap/Grant_Admin_Consent.PNG b/documentation/enterprise/images/Bootstrap/Grant_Admin_Consent.PNG new file mode 100644 index 00000000..7e3afc76 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/Grant_Admin_Consent.PNG differ diff --git a/documentation/enterprise/images/Bootstrap/Granted_Admin_Consent.PNG b/documentation/enterprise/images/Bootstrap/Granted_Admin_Consent.PNG new file mode 100644 index 00000000..277a97ad Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/Granted_Admin_Consent.PNG differ diff --git a/documentation/enterprise/images/Bootstrap/MSGraph_directory.PNG b/documentation/enterprise/images/Bootstrap/MSGraph_directory.PNG new file mode 100644 index 00000000..c97e8215 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/MSGraph_directory.PNG differ diff --git a/documentation/enterprise/images/Bootstrap/image1.png b/documentation/enterprise/images/Bootstrap/image1.png new file mode 100644 index 00000000..a0601911 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image1.png differ diff --git a/documentation/enterprise/images/Bootstrap/image10.png b/documentation/enterprise/images/Bootstrap/image10.png new file mode 100644 index 00000000..08517fdd Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image10.png differ diff --git a/documentation/enterprise/images/Bootstrap/image11.png b/documentation/enterprise/images/Bootstrap/image11.png new file mode 100644 index 00000000..f975e0c9 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image11.png differ diff --git a/documentation/enterprise/images/Bootstrap/image12.png b/documentation/enterprise/images/Bootstrap/image12.png new file mode 100644 index 00000000..9e23ed72 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image12.png differ diff --git a/documentation/enterprise/images/Bootstrap/image13.png b/documentation/enterprise/images/Bootstrap/image13.png new file mode 100644 index 00000000..aae41a84 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image13.png differ diff --git a/documentation/enterprise/images/Bootstrap/image14.png b/documentation/enterprise/images/Bootstrap/image14.png new file mode 100644 index 00000000..259e0830 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image14.png differ diff --git a/documentation/enterprise/images/Bootstrap/image15.png b/documentation/enterprise/images/Bootstrap/image15.png new file mode 100644 index 00000000..6c313428 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image15.png differ diff --git a/documentation/enterprise/images/Bootstrap/image16.png b/documentation/enterprise/images/Bootstrap/image16.png new file mode 100644 index 00000000..0e0c981f Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image16.png differ diff --git a/documentation/enterprise/images/Bootstrap/image17.png b/documentation/enterprise/images/Bootstrap/image17.png new file mode 100644 index 00000000..ed587e35 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image17.png differ diff --git a/documentation/enterprise/images/Bootstrap/image18.png b/documentation/enterprise/images/Bootstrap/image18.png new file mode 100644 index 00000000..b4ee5e6e Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image18.png differ diff --git a/documentation/enterprise/images/Bootstrap/image19.png b/documentation/enterprise/images/Bootstrap/image19.png new file mode 100644 index 00000000..fcf29f94 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image19.png differ diff --git a/documentation/enterprise/images/Bootstrap/image2.png b/documentation/enterprise/images/Bootstrap/image2.png new file mode 100644 index 00000000..7232e5fa Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image2.png differ diff --git a/documentation/enterprise/images/Bootstrap/image20.png b/documentation/enterprise/images/Bootstrap/image20.png new file mode 100644 index 00000000..93d49318 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image20.png differ diff --git a/documentation/enterprise/images/Bootstrap/image21.png b/documentation/enterprise/images/Bootstrap/image21.png new file mode 100644 index 00000000..29d32d93 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image21.png differ diff --git a/documentation/enterprise/images/Bootstrap/image22.png b/documentation/enterprise/images/Bootstrap/image22.png new file mode 100644 index 00000000..25adbf4c Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image22.png differ diff --git a/documentation/enterprise/images/Bootstrap/image23.png b/documentation/enterprise/images/Bootstrap/image23.png new file mode 100644 index 00000000..1f177f7d Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image23.png differ diff --git a/documentation/enterprise/images/Bootstrap/image24.png b/documentation/enterprise/images/Bootstrap/image24.png new file mode 100644 index 00000000..b1b4b01f Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image24.png differ diff --git a/documentation/enterprise/images/Bootstrap/image25.png b/documentation/enterprise/images/Bootstrap/image25.png new file mode 100644 index 00000000..f2006a41 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image25.png differ diff --git a/documentation/enterprise/images/Bootstrap/image26.png b/documentation/enterprise/images/Bootstrap/image26.png new file mode 100644 index 00000000..316d65ae Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image26.png differ diff --git a/documentation/enterprise/images/Bootstrap/image27.png b/documentation/enterprise/images/Bootstrap/image27.png new file mode 100644 index 00000000..9a3dfa8b Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image27.png differ diff --git a/documentation/enterprise/images/Bootstrap/image28.png b/documentation/enterprise/images/Bootstrap/image28.png new file mode 100644 index 00000000..10044518 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image28.png differ diff --git a/documentation/enterprise/images/Bootstrap/image29.png b/documentation/enterprise/images/Bootstrap/image29.png new file mode 100644 index 00000000..08852556 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image29.png differ diff --git a/documentation/enterprise/images/Bootstrap/image3.png b/documentation/enterprise/images/Bootstrap/image3.png new file mode 100644 index 00000000..fc90dea0 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image3.png differ diff --git a/documentation/enterprise/images/Bootstrap/image30.png b/documentation/enterprise/images/Bootstrap/image30.png new file mode 100644 index 00000000..53ed7e3a Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image30.png differ diff --git a/documentation/enterprise/images/Bootstrap/image4.png b/documentation/enterprise/images/Bootstrap/image4.png new file mode 100644 index 00000000..957d7290 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image4.png differ diff --git a/documentation/enterprise/images/Bootstrap/image5.png b/documentation/enterprise/images/Bootstrap/image5.png new file mode 100644 index 00000000..c214fc8f Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image5.png differ diff --git a/documentation/enterprise/images/Bootstrap/image6.png b/documentation/enterprise/images/Bootstrap/image6.png new file mode 100644 index 00000000..399f1e09 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image6.png differ diff --git a/documentation/enterprise/images/Bootstrap/image7.png b/documentation/enterprise/images/Bootstrap/image7.png new file mode 100644 index 00000000..370ccb04 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image7.png differ diff --git a/documentation/enterprise/images/Bootstrap/image8.png b/documentation/enterprise/images/Bootstrap/image8.png new file mode 100644 index 00000000..dd745105 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image8.png differ diff --git a/documentation/enterprise/images/Bootstrap/image9.png b/documentation/enterprise/images/Bootstrap/image9.png new file mode 100644 index 00000000..0411cf76 Binary files /dev/null and b/documentation/enterprise/images/Bootstrap/image9.png differ diff --git a/documentation/enterprise/images/Enterprise/Getting_Started.png b/documentation/enterprise/images/Enterprise/Getting_Started.png new file mode 100644 index 00000000..5d2aeb15 Binary files /dev/null and b/documentation/enterprise/images/Enterprise/Getting_Started.png differ diff --git a/documentation/enterprise/images/Enterprise/Prod_NonPROD_IAC.png b/documentation/enterprise/images/Enterprise/Prod_NonPROD_IAC.png new file mode 100644 index 00000000..f8f1b4ba Binary files /dev/null and b/documentation/enterprise/images/Enterprise/Prod_NonPROD_IAC.png differ diff --git a/documentation/enterprise/images/Enterprise/Sandpit_IAC.png b/documentation/enterprise/images/Enterprise/Sandpit_IAC.png new file mode 100644 index 00000000..2ca1d53a Binary files /dev/null and b/documentation/enterprise/images/Enterprise/Sandpit_IAC.png differ diff --git a/documentation/enterprise/images/Enterprise/environment_seperation.png b/documentation/enterprise/images/Enterprise/environment_seperation.png new file mode 100644 index 00000000..3e408679 Binary files /dev/null and b/documentation/enterprise/images/Enterprise/environment_seperation.png differ diff --git a/documentation/getting_started/getting_started.md b/documentation/getting_started/getting_started.md index 22529fbb..d952bfd5 100644 --- a/documentation/getting_started/getting_started.md +++ b/documentation/getting_started/getting_started.md @@ -40,8 +40,6 @@ You will have to accept local mapping to your filesystem when Docker prompts you After a while, your environment is ready, note on the lower left part of Visual Studio Code, that you are now in your Azure CAF rover, which is your environment to use Azure landing zones. -## Deploying your first landing zone - You must be authenticated first: For that we will rely on Azure authentication as completed by Azure Cli, via browser method: @@ -55,35 +53,52 @@ We recommend that you verify the output of the login and make sure the subscript az account set --subscription ``` -On the first run, you need to use the launchpad to create the foundations for Terraform environment: +## Deploying the DevOps requirements + +On the first run, you need to use the launchpad to create the foundations for Terraform environment. This will set storage accounts to store the state files, and key vaults to get you started with a secure environment. It can eventually be upgraded to support your DevOps environment (pipelines, etc.) + +You can find more information on the launchpad settings [Here](../../landingzones/caf_launchpad) ```bash -rover -lz /tf/caf/landingzones/launchpad -a apply -launchpad +rover -launchpad -lz /tf/caf/landingzones/caf_launchpad \ +-var-folder /tf/caf/landingzones/caf_launchpad/scenario/100 \ +-a apply ``` -This command will interactively prompt you for *var.location*, asking for the name of a supported Azure region **where you want to deploy the Terraform state and dependencies**. You can specify that in the argument as in the following example: +## Deploying the foundations + +Next step is to deploy the foundations (this typically could include management groups, policies, etc.). We can start with it empty, and enrich it later. + +You can find more information on the launchpad settings [Here](../../landingzones/caf_launchpad) + + +Get started with the basic foundations: ```bash -rover -lz /tf/caf/landingzones/launchpad -a apply -launchpad -var 'location=westus' +rover -lz /tf/caf/landingzones/caf_foundations \ +-level level1 \ +-a apply ``` -You can then launch your first landing zone! +## Deploying a networking scenario -Please note that each landing zone come with its own deployment settings, which may deploy resources in different region than where you set the foundations. +You can deploy one of the typical Azure network topologies (hub, hub and spoke, Virtual WAN). -You are ready to start: +Have a look at the example scenario [Here](../../landingzones/caf_networking) and pick one you want to deploy. + +You can deploy a simple hub networking using: ```bash -rover -lz /tf/caf/landingzones/landingzone_caf_foundations -a plan +rover -lz /tf/caf/landingzones/caf_networking \ +-level level2 \ +-var-folder /tf/caf/landingzones/caf_networking/scenario/100-single-region-hub \ +-a apply ``` -```bash -rover -lz /tf/caf/landingzones/landingzone_caf_foundations -a apply -``` +## Destroying your test + +Once you are done testing, just use the same commands as before, juste replace the last line ```-a apply``` by ```-a destroy```. -```bash -rover -lz /tf/caf/landingzones/landingzone_caf_foundations -a destroy -``` ## Updating your development environment diff --git a/documentation/getting_started/getting_started_codespaces.md b/documentation/getting_started/getting_started_codespaces.md index 38437dd4..ee31f3ed 100644 --- a/documentation/getting_started/getting_started_codespaces.md +++ b/documentation/getting_started/getting_started_codespaces.md @@ -36,7 +36,7 @@ Open a Terminal using ```CTRL``` + ```J``` or ```Command``` + ```J``` You are ready to use landing zones by launching the rover as below: ```bash -/tf/rover/rover.sh +rover ``` ![Create](../../_pictures/getting_started/vs_codespaces_rover.png) @@ -47,7 +47,7 @@ You must be authenticated first: For that we will rely on Azure authentication as completed by Azure Cli, via browser method: ```bash -/tf/rover/rover.sh login +rover login ``` We recommend that you verify the output of the login and make sure the subscription selected by default is the one you want to work on. If not, you can use the following switch: @@ -56,34 +56,49 @@ We recommend that you verify the output of the login and make sure the subscript az account set --subscription ``` -On the first run, you need to apply the launchpad as the first landing zone: + +## Deploying the DevOps requirements + +On the first run, you need to use the launchpad to create the foundations for Terraform environment. This will set storage accounts to store the state files, and key vaults to get you started with a secure environment. It can eventually be upgraded to support your DevOps environment (pipelines, etc.) + +You can find more information on the launchpad settings [Here](../../landingzones/caf_launchpad) ```bash -/tf/rover/rover.sh -lz /tf/caf/landingzones/launchpad -a apply -launchpad +rover -launchpad -lz /tf/caf/landingzones/caf_launchpad \ +-var-folder /tf/caf/landingzones/caf_launchpad/scenario/100 \ +-a apply ``` -You can specify a location for the launchpad using the following command: +## Deploying the foundations + +Next step is to deploy the foundations (this typically could include management groups, policies, etc.). We can start with it empty, and enrich it later. + +You can find more information on the launchpad settings [Here](../../landingzones/caf_launchpad) + + +Get started with the basic foundations: ```bash -/tf/rover/rover.sh -lz /tf/caf/landingzones/launchpad -a apply -launchpad -var location=westus +rover -lz /tf/caf/landingzones/caf_foundations \ +-level level1 \ +-a apply ``` -You can then launch your first landing zone! +## Deploying a networking scenario -Please note that each landing zone come with its own deployment settings, which may deploy resources in different region than where you set the foundations. +You can deploy one of the typical Azure network topologies (hub, hub and spoke, Virtual WAN). -You are ready to start: +Have a look at the example scenario [Here](../../landingzones/caf_networking) and pick one you want to deploy. + +You can deploy a simple hub networking using: ```bash -/tf/rover/rover.sh -lz /tf/caf/landingzones/landingzone_caf_foundations -a plan +rover -lz /tf/caf/landingzones/caf_networking \ +-level level2 \ +-var-folder /tf/caf/landingzones/caf_networking/scenario/100-single-region-hub \ +-a apply ``` -```bash -/tf/rover/rover.sh -lz /tf/caf/landingzones/landingzone_caf_foundations -a apply -``` +## Destroying your test -```bash -/tf/rover/rover.sh -lz /tf/caf/landingzones/landingzone_caf_foundations -a destroy -``` - -Happy deployment with Azure landing zones, let us know your feedback and how you need it to evolve. +Once you are done testing, just use the same commands as before, juste replace the last line ```-a apply``` by ```-a destroy```. diff --git a/environments/integration-tests/landingzone_caf_foundations/landingzone_caf_foundations_southeastasia_random.tfvars b/environments/integration-tests/landingzone_caf_foundations/landingzone_caf_foundations_southeastasia_random.tfvars deleted file mode 100644 index 609dc8ff..00000000 --- a/environments/integration-tests/landingzone_caf_foundations/landingzone_caf_foundations_southeastasia_random.tfvars +++ /dev/null @@ -1,225 +0,0 @@ -# Sample Cloud Adoption Framework foundations landing zone - -## globalsettings -global_settings = { - #specifies the set of locations you are going to use in this landing zone - location_map = { - southeastasia = "southeastasia" - eastasia = "eastasia" - } - - #naming convention to be used as defined in naming convention module, accepted values are cafclassic, cafrandom, random, passthrough - convention = "cafrandom" - - #Set of tags for core operations - tags_hub = { - owner = "CAF" - deploymentType = "Terraform" - costCenter = "1664" - BusinessUnit = "SHARED" - DR = "NON-DR-ENABLED" - } - - # Set of resource groups to land the foundations - resource_groups_hub = { - southeastasia = { - HUB-CORE-SEC = { - name = "hub-core-sec-sea" - location = "southeastasia" - } - HUB-OPERATIONS = { - name = "hub-operations-sea" - location = "southeastasia" - } - } - eastasia = { - HUB-CORE-SEC = { - name = "hub-core-sec-hk" - location = "southeastasia" - } - HUB-OPERATIONS = { - name = "hub-operations-hk" - location = "southeastasia" - } - } - } -} - -## accounting settings -accounting_settings = { - - # Azure diagnostics logs retention period - southeastasia = { - # Azure Subscription activity logs retention period - azure_activity_log_enabled = false - azure_activity_logs_name = "actlogs" - azure_activity_logs_event_hub = false - azure_activity_logs_retention = 365 - azure_activity_audit = { - log = [ - # ["Audit category name", "Audit enabled)"] - ["Administrative", true], - ["Security", true], - ["ServiceHealth", true], - ["Alert", true], - ["Recommendation", true], - ["Policy", true], - ["Autoscale", true], - ["ResourceHealth", true], - ] - } - azure_diagnostics_logs_name = "diaglogs" - azure_diagnostics_logs_event_hub = false - - #Logging and monitoring - analytics_workspace_name = "caflalogs-sg" - - ##Log analytics solutions to be deployed - solution_plan_map = { - NetworkMonitoring = { - "publisher" = "Microsoft" - "product" = "OMSGallery/NetworkMonitoring" - }, - ADAssessment = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ADAssessment" - }, - ADReplication = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ADReplication" - }, - AgentHealthAssessment = { - "publisher" = "Microsoft" - "product" = "OMSGallery/AgentHealthAssessment" - }, - DnsAnalytics = { - "publisher" = "Microsoft" - "product" = "OMSGallery/DnsAnalytics" - }, - ContainerInsights = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ContainerInsights" - }, - KeyVaultAnalytics = { - "publisher" = "Microsoft" - "product" = "OMSGallery/KeyVaultAnalytics" - } - } - } - eastasia = { - # Azure Subscription activity logs retention period - azure_activity_log_enabled = false - azure_activity_logs_name = "actlogs" - azure_activity_logs_event_hub = false - azure_activity_logs_retention = 365 - azure_activity_audit = { - log = [ - # ["Audit category name", "Audit enabled)"] - ["Administrative", true], - ["Security", true], - ["ServiceHealth", true], - ["Alert", true], - ["Recommendation", true], - ["Policy", true], - ["Autoscale", true], - ["ResourceHealth", true], - ] - } - azure_diagnostics_logs_name = "diaglogs" - azure_diagnostics_logs_event_hub = false - - #Logging and monitoring - analytics_workspace_name = "caflalogs-hk" - - ##Log analytics solutions to be deployed - solution_plan_map = { - NetworkMonitoring = { - "publisher" = "Microsoft" - "product" = "OMSGallery/NetworkMonitoring" - }, - ADAssessment = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ADAssessment" - }, - ADReplication = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ADReplication" - }, - AgentHealthAssessment = { - "publisher" = "Microsoft" - "product" = "OMSGallery/AgentHealthAssessment" - }, - DnsAnalytics = { - "publisher" = "Microsoft" - "product" = "OMSGallery/DnsAnalytics" - }, - ContainerInsights = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ContainerInsights" - }, - KeyVaultAnalytics = { - "publisher" = "Microsoft" - "product" = "OMSGallery/KeyVaultAnalytics" - } - } - } -} - -## governance -governance_settings = { - southeastasia = { - #current code supports only two levels of managemenr groups and one root - deploy_mgmt_groups = false - management_groups = { - root = { - name = "caf-rootmgmtgroup" - subscriptions = [] - #list your subscriptions ID in this field as ["GUID1", "GUID2"] - children = { - child1 = { - name = "tree1child1" - subscriptions = [] - } - child2 = { - name = "tree1child2" - subscriptions = [] - } - child3 = { - name = "tree1child3" - subscriptions = [] - } - } - } - } - - policy_matrix = { - #autoenroll_asc = true - to be implemented via builtin policies - autoenroll_monitor_vm = true - autoenroll_netwatcher = false - - no_public_ip_spoke = false - cant_create_ip_spoke = false - managed_disks_only = true - restrict_locations = false - list_of_allowed_locs = ["southeastasia", "eastasia"] - restrict_supported_svc = false - list_of_supported_svc = ["Microsoft.Network/publicIPAddresses", "Microsoft.Compute/disks"] - msi_location = "southeastasia" - } - } - eastasia = {} -} - -## security -security_settings = { - #Azure Security Center Configuration - enable_security_center = false - security_center = { - contact_email = "email@email.com" - contact_phone = "9293829328" - alerts_to_admins = true - alert_notifications = true - } - #Enables Azure Sentinel on the Log Analaytics repo - enable_sentinel = true -} diff --git a/environments/integration-tests/landingzone_hub_mesh/landingzone_hub_mesh.tfvars b/environments/integration-tests/landingzone_hub_mesh/landingzone_hub_mesh.tfvars deleted file mode 100644 index 2ba9d9cf..00000000 --- a/environments/integration-tests/landingzone_hub_mesh/landingzone_hub_mesh.tfvars +++ /dev/null @@ -1,172 +0,0 @@ -# Configuration sample for Azure Virtual WAN hub and spoke -virtual_hub_config = { - virtual_wan = { - resource_group_name = "virtualwan" - name = "ContosovWAN" - dns_name = "private.contoso.com" - - hubs = { - hub1 = { - hub_name = "SEA-HUB" - region = "southeastasia" - hub_address_prefix = "10.0.3.0/24" - deploy_firewall = true - peerings = {} - firewall_name = "azfwsg" - firewall_resource_groupe_name = "azfwsg" - deploy_p2s = false - p2s_config = { - name = "caf-sea-vpn-p2s" - scale_unit = 2 - connection_configuration = { - name = "client-connections" - vpn_client_address_pool = { - address_prefixes = ["192.168.0.0/24"] - } - } - server_config = { - vpn_authentication_types = ["Certificate"] - client_root_certificate = { - name = "DigiCert-Federated-ID-Root-CA" - public_cert_data = < - # optional if the virtual network has been provisionned outside. - hub_to_vitual_network_traffic_allowed = true - vitual_network_to_hub_gateways_traffic_allowed = true - internet_security_enabled = false - } - } - deploy_p2s = false - p2s_config = {} - deploy_s2s = false - s2s_config = {} - deploy_er = false - er_config = {} - } - } - } -} - -spokes = { - spoke1 = { - rg = { - name = "virtualhub-spoke-test" - location = "eastasia" - } - peering_name = "spoke1-hub-hk-link" - network = { - vnet = { - name = "Core-Network" - address_space = ["10.0.10.0/24"] - } - specialsubnets = {} - - subnets = { - subnet0 = { - name = "Web_tier" - cidr = ["10.0.10.0/26"] - nsg_name = "Web_tier_nsg" - nsg = [ - { - name = "HTTP-In", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "80" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "HTTPS-In", - priority = "101" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - ] - } - subnet2 = { - name = "Data_tier" - cidr = ["10.0.10.128/26"] - nsg_name = "Data_tier_nsg" - nsg = [ - { - name = "TDS-In", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "UDP" - source_port_range = "*" - destination_port_range = "1433" - source_address_prefix = "*" - destination_address_prefix = "*" - } - ] - } - } - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - } -} \ No newline at end of file diff --git a/environments/integration-tests/landingzone_hub_spoke/landingzone_hub_spoke.tfvars b/environments/integration-tests/landingzone_hub_spoke/landingzone_hub_spoke.tfvars deleted file mode 100644 index 189e469a..00000000 --- a/environments/integration-tests/landingzone_hub_spoke/landingzone_hub_spoke.tfvars +++ /dev/null @@ -1,435 +0,0 @@ -# Configuration sample for a hub and spoke environment -# definition of variables for the virtual network -rg_network = { - CORE-NET = { - name = "network-core" - } - TRANSIT-NET = { - name = "network-transit" - } - EDGE-NET = { - name = "network-edge" - } -} - -# settings for the core network blueprint -core_networking = { - shared_services_vnet = { - vnet = { - name = "Core-Network" - address_space = ["10.0.0.0/8"] - } - specialsubnets = { - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = ["10.0.4.0/24"] - } - GatewaySubnet = { - name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway - cidr = ["10.0.255.224/27"] - } - } - subnets = { - subnet0 = { - name = "Active_Directory" - cidr = ["10.0.1.0/24"] - nsg_name = "Active_Directory_nsg" - nsg = [ - { - name = "W32Time", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "UDP" - source_port_range = "*" - destination_port_range = "123" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "RPC-Endpoint-Mapper", - priority = "101" - direction = "Inbound" - access = "Allow" - protocol = "UDP" - source_port_range = "*" - destination_port_range = "135" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "Kerberos-password-change", - priority = "102" - direction = "Inbound" - access = "Allow" - protocol = "*" - source_port_range = "*" - destination_port_range = "464" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "RPC-Dynamic-range", - priority = "103" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "49152-65535" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "LDAP", - priority = "104" - direction = "Inbound" - access = "Allow" - protocol = "*" - source_port_range = "*" - destination_port_range = "389" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "LDAP-SSL", - priority = "105" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "636" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "LDAP-GC", - priority = "106" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3268" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "LDAP-GC-SSL", - priority = "107" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3269" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "DNS", - priority = "108" - direction = "Inbound" - access = "Allow" - protocol = "*" - source_port_range = "*" - destination_port_range = "53" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "Kerberos", - priority = "109" - direction = "Inbound" - access = "Allow" - protocol = "*" - source_port_range = "*" - destination_port_range = "88" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "SMB", - priority = "110" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "445" - source_address_prefix = "*" - destination_address_prefix = "*" - } - ] - } - subnet1 = { - name = "AzureBastionSubnet" #Must be called AzureBastionSubnet - cidr = ["10.0.0.128/25"] - nsg_name = "AzureBastionSubnet_nsg" - nsg = [ - { - name = "bastion-in-allow", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-443", - priority = "120" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "135" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "Kerberos-password-change", - priority = "121" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "4443" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-vnet-out-allow-22", - priority = "103" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-vnet-out-allow-3389", - priority = "101" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-azure-out-allow", - priority = "120" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "AzureCloud" - } - ] - } - } - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - - } - - # Settings for the public IP address to be used for Azure Firewall - # Must be standard and static for - firewall_ip_addr_config = { - ip_name = "firewall" - allocation_method = "Static" - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the Azure Firewall settings - az_fw_config = { - name = "azfw" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AzureFirewallApplicationRule", true, true, 30], - ["AzureFirewallNetworkRule", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the UDR object - udr_web_to_az_firewall = { - nexthop_type = "VirtualAppliance" - prefix = "0.0.0.0/0" - route_name = "web_to_az_firewall" - subnet_to_udr = "Web_tier" - nexthop_ip = "" - } - udr_transit_to_az_firewall = { - nexthop_type = "VirtualAppliance" - prefix = "10.0.1.0/24" - route_name = "transit_to_az_firewall" - subnet_to_udr = "GatewaySubnet" - nexthop_ip = "" - } - - ## DDoS standard configuration - enable_ddos_standard = false - ddos_name = "ddos_protection_plan" - - ## settings for Azure bastion configuration - ## not enabled, uncomment the code in the networking shared services blueprint. - enable_bastion = false - bastion_ip_addr_config = { - ip_name = "bastion" - ip_addr = { - allocation_method = "Static" - #Dynamic Public IP Addresses aren't allocated until they're assigned to a resource (such as a Virtual Machine or a Load Balancer) by design within Azure - - #properties below are optional - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - #dns_prefix = "arnaudmytest" - #timeout = 15 #TCP timeout for idle connections. The value can be set between 4 and 30 minutes. - #zones = [1] #1 zone number, IP address must be standard, ZoneRedundant argument is not supported in provider at time of writing - #reverse_fqdn = "" - #public_ip_prefix_id = "/subscriptions/00000000-00000-0000-0000-000000000000/resourceGroups/uqvh-hub-ingress-net/providers/Microsoft.Network/publicIPPrefixes/myprefix" - #refer to the prefix and check sku types are same in IP and prefix - } - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - bastion_config = { - name = "azurebastion" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["BastionAuditLogs", true, true, 30], - ] - metric = [ - # ["AllMetrics", true, true, 30], - ] - } - } - - - # Settings for the Virtual Network gateway to be created - provision_gateway = false - gateway_config = { - gateway_type = "VPN" - # Possible values are "VPN" or "ExpressRoute" - vpn_gateway_name = "vpngateway" - active_active = false - #An active-active gateway requires a HighPerformance or an UltraPerformance sku. If false, an active-standby gateway will be created. Defaults to false. - enable_bgp = false - #If true, BGP (Border Gateway Protocol) will be enabled for this Virtual Network Gateway. Defaults to false. - vpn_gateway_sku = "Basic" - #Valid options are Basic, Standard, HighPerformance, UltraPerformance, ErGw1AZ, ErGw2AZ, ErGw3AZ, VpnGw1, VpnGw2, VpnGw3, VpnGw1AZ, VpnGw2AZ, and VpnGw3AZ - #and depend on the gateway_type (ER or VPN) and vpn_type arguments, ie: PolicyBased gateway only supports the Basic sku. - vpn_gateway_type = "RouteBased" - #The routing type of the Virtual Network Gateway. Valid options are RouteBased or PolicyBased. Defaults to RouteBased. - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["GatewayDiagnosticLog", true, true, 30], - ["TunnelDiagnosticLog", true, true, 30], - ["RouteDiagnosticLog", true, true, 30], - ["IKEDiagnosticLog", true, true, 30], - ["P2SDiagnosticLog", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - pip = { - name = "vpn" - allocation_method = "Dynamic" - sku = "Basic" - #For basic SKU, you can pick the zone to be deployed - if you want multi zone - pick Standard IP and pick AZ aware VPN gateway SKU - #dns_prefix = "arnaudvpn" - #zones = ["1"] - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - } - - #Settings for the connection to be established - #Settings for the local network connection - connection_name = "onpremconnection" - remote_network_connect = true - - remote_network = { - gateway_name = "caf_local_network" - gateway_ip = "1.2.3.4" - gateway_adress_space = ["1.0.0.0/8"] - - bgp_settings = { - # asn = - # bgp_peering_address = - # peer_weight = - } - } - - ##Settings for the Azure Key Vault - akv_config = { - name = "vpn-akv" - akv_features = { - enabled_for_disk_encryption = true - enabled_for_deployment = true - enabled_for_template_deployment = true - } - sku_name = "standard" - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AuditEvent", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - -} \ No newline at end of file diff --git a/environments/integration-tests/landingzone_hub_spoke/landingzone_hub_spoke_bastion.tfvars b/environments/integration-tests/landingzone_hub_spoke/landingzone_hub_spoke_bastion.tfvars deleted file mode 100644 index 2ef89c49..00000000 --- a/environments/integration-tests/landingzone_hub_spoke/landingzone_hub_spoke_bastion.tfvars +++ /dev/null @@ -1,265 +0,0 @@ -# Configuration sample for a hub and spoke environment -# definition of variables for the virtual network -rg_network = { - CORE-NET = { - name = "network-core" - } - TRANSIT-NET = { - name = "network-transit" - } - EDGE-NET = { - name = "network-edge" - } -} - -# settings for the core network blueprint -core_networking = { - shared_services_vnet = { - vnet = { - name = "Core-Network" - address_space = ["10.0.0.0/8"] - } - specialsubnets = { - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = "10.0.4.0/24" - } - GatewaySubnet = { - name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway - cidr = "10.0.255.224/27" - } - } - subnets = { - subnet0 = { - name = "Active_Directory" - cidr = "10.0.1.0/24" - nsg_inbound = [ - # {"Name", "Priority", "Direction", "Action", "Protocol", "source_port_range", "destination_port_range", "source_address_prefix", "destination_address_prefix" }, - ["W32Time", "100", "Inbound", "Allow", "udp", "*", "123", "*", "*"], - ["RPC-Endpoint-Mapper", "101", "Inbound", "Allow", "tcp", "*", "135", "*", "*"], - ["Kerberos-password-change", "102", "Inbound", "Allow", "*", "*", "464", "*", "*"], - ["RPC-Dynamic-range", "103", "Inbound", "Allow", "tcp", "*", "49152-65535", "*", "*"], - ["LDAP", "104", "Inbound", "Allow", "*", "*", "389", "*", "*"], - ["LDAP-SSL", "105", "Inbound", "Allow", "tcp", "*", "636", "*", "*"], - ["LDAP-GC", "106", "Inbound", "Allow", "tcp", "*", "3268", "*", "*"], - ["LDAP-GC-SSL", "107", "Inbound", "Allow", "tcp", "*", "3269", "*", "*"], - ["DNS", "108", "Inbound", "Allow", "*", "*", "53", "*", "*"], - ["Kerberos", "109", "Inbound", "Allow", "*", "*", "88", "*", "*"], - ["SMB", "110", "Inbound", "Allow", "tcp", "*", "445", "*", "*"], - ] - } - subnet1 = { - name = "AzureBastionSubnet" #Must be called AzureBastionSubnet - cidr = "10.0.0.128/25" - nsg_inbound = [ - ["bastion-in-allow", "100", "Inbound", "Allow", "tcp", "*", "443", "*", "*"], - ["bastion-control-in-allow-443", "120", "Inbound", "Allow", "tcp", "*", "443", "GatewayManager", "*"], - ["bastion-control-in-allow-4443", "121", "Inbound", "Allow", "tcp", "*", "4443", "GatewayManager", "*"], - ] - nsg_outbound = [ - ["bastion-vnet-out-allow-22", "100", "Outbound", "Allow", "tcp", "*", "22", "*", "VirtualNetwork"], - ["bastion-vnet-out-allow-3389", "101", "Outbound", "Allow", "tcp", "*", "3389", "*", "VirtualNetwork"], - ["bastion-azure-out-allow", "120", "Outbound", "Allow", "tcp", "*", "443", "*", "AzureCloud"], - ] - } - } - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - - # Settings for the public IP address to be used for Azure Firewall - # Must be standard and static for - firewall_ip_addr_config = { - ip_name = "firewall" - allocation_method = "Static" - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the Azure Firewall settings - az_fw_config = { - name = "azfw" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AzureFirewallApplicationRule", true, true, 30], - ["AzureFirewallNetworkRule", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the UDR object - udr_web_to_az_firewall = { - nexthop_type = "VirtualAppliance" - prefix = "0.0.0.0/0" - route_name = "web_to_az_firewall" - subnet_to_udr = "Web_tier" - nexthop_ip = "" - } - udr_transit_to_az_firewall = { - nexthop_type = "VirtualAppliance" - prefix = "10.0.1.0/24" - route_name = "transit_to_az_firewall" - subnet_to_udr = "GatewaySubnet" - nexthop_ip = "" - } - - ## DDoS standard configuration - enable_ddos_standard = false - ddos_name = "ddos_protection_plan" - - ## settings for Azure bastion configuration - ## not enabled, uncomment the code in the networking shared services blueprint. - enable_bastion = true - bastion_ip_addr_config = { - ip_name = "bastion" - ip_addr = { - allocation_method = "Static" - #Dynamic Public IP Addresses aren't allocated until they're assigned to a resource (such as a Virtual Machine or a Load Balancer) by design within Azure - - #properties below are optional - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - #dns_prefix = "arnaudmytest" - #timeout = 15 #TCP timeout for idle connections. The value can be set between 4 and 30 minutes. - #zones = [1] #1 zone number, IP address must be standard, ZoneRedundant argument is not supported in provider at time of writing - #reverse_fqdn = "" - #public_ip_prefix_id = "/subscriptions/00000000-00000-0000-0000-000000000000/resourceGroups/uqvh-hub-ingress-net/providers/Microsoft.Network/publicIPPrefixes/myprefix" - #refer to the prefix and check sku types are same in IP and prefix - } - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - bastion_config = { - name = "azurebastion" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["BastionAuditLogs", true, true, 30], - ] - metric = [ - # ["AllMetrics", true, true, 30], - ] - } - } - - - # Settings for the Virtual Network gateway to be created - provision_gateway = false - gateway_config = { - gateway_type = "VPN" - # Possible values are "VPN" or "ExpressRoute" - vpn_gateway_name = "vpngateway" - active_active = false - #An active-active gateway requires a HighPerformance or an UltraPerformance sku. If false, an active-standby gateway will be created. Defaults to false. - enable_bgp = false - #If true, BGP (Border Gateway Protocol) will be enabled for this Virtual Network Gateway. Defaults to false. - vpn_gateway_sku = "Basic" - #Valid options are Basic, Standard, HighPerformance, UltraPerformance, ErGw1AZ, ErGw2AZ, ErGw3AZ, VpnGw1, VpnGw2, VpnGw3, VpnGw1AZ, VpnGw2AZ, and VpnGw3AZ - #and depend on the gateway_type (ER or VPN) and vpn_type arguments, ie: PolicyBased gateway only supports the Basic sku. - vpn_gateway_type = "RouteBased" - #The routing type of the Virtual Network Gateway. Valid options are RouteBased or PolicyBased. Defaults to RouteBased. - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["GatewayDiagnosticLog", true, true, 30], - ["TunnelDiagnosticLog", true, true, 30], - ["RouteDiagnosticLog", true, true, 30], - ["IKEDiagnosticLog", true, true, 30], - ["P2SDiagnosticLog", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - pip = { - name = "vpn" - allocation_method = "Dynamic" - sku = "Basic" - #For basic SKU, you can pick the zone to be deployed - if you want multi zone - pick Standard IP and pick AZ aware VPN gateway SKU - #dns_prefix = "arnaudvpn" - #zones = ["1"] - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - } - - #Settings for the connection to be established - #Settings for the local network connection - connection_name = "onpremconnection" - remote_network_connect = true - - remote_network = { - gateway_name = "caf_local_network" - gateway_ip = "1.2.3.4" - gateway_adress_space = ["1.0.0.0/8"] - - bgp_settings = { - # asn = - # bgp_peering_address = - # peer_weight = - } - } - - ##Settings for the Azure Key Vault - akv_config = { - name = "vpn-akv" - akv_features = { - enabled_for_disk_encryption = true - enabled_for_deployment = true - enabled_for_template_deployment = true - } - sku_name = "standard" - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AuditEvent", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - -} \ No newline at end of file diff --git a/environments/integration-tests/landingzone_hub_spoke/landingzone_hub_spoke_no_bastion.tfvars b/environments/integration-tests/landingzone_hub_spoke/landingzone_hub_spoke_no_bastion.tfvars deleted file mode 100644 index 852df83a..00000000 --- a/environments/integration-tests/landingzone_hub_spoke/landingzone_hub_spoke_no_bastion.tfvars +++ /dev/null @@ -1,265 +0,0 @@ -# Configuration sample for a hub and spoke environment -# definition of variables for the virtual network -rg_network = { - CORE-NET = { - name = "network-core" - } - TRANSIT-NET = { - name = "network-transit" - } - EDGE-NET = { - name = "network-edge" - } -} - -# settings for the core network blueprint -core_networking = { - shared_services_vnet = { - vnet = { - name = "Core-Network" - address_space = ["10.0.0.0/8"] - } - specialsubnets = { - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = "10.0.4.0/24" - } - GatewaySubnet = { - name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway - cidr = "10.0.255.224/27" - } - } - subnets = { - subnet0 = { - name = "Active_Directory" - cidr = "10.0.1.0/24" - nsg_inbound = [ - # {"Name", "Priority", "Direction", "Action", "Protocol", "source_port_range", "destination_port_range", "source_address_prefix", "destination_address_prefix" }, - ["W32Time", "100", "Inbound", "Allow", "udp", "*", "123", "*", "*"], - ["RPC-Endpoint-Mapper", "101", "Inbound", "Allow", "tcp", "*", "135", "*", "*"], - ["Kerberos-password-change", "102", "Inbound", "Allow", "*", "*", "464", "*", "*"], - ["RPC-Dynamic-range", "103", "Inbound", "Allow", "tcp", "*", "49152-65535", "*", "*"], - ["LDAP", "104", "Inbound", "Allow", "*", "*", "389", "*", "*"], - ["LDAP-SSL", "105", "Inbound", "Allow", "tcp", "*", "636", "*", "*"], - ["LDAP-GC", "106", "Inbound", "Allow", "tcp", "*", "3268", "*", "*"], - ["LDAP-GC-SSL", "107", "Inbound", "Allow", "tcp", "*", "3269", "*", "*"], - ["DNS", "108", "Inbound", "Allow", "*", "*", "53", "*", "*"], - ["Kerberos", "109", "Inbound", "Allow", "*", "*", "88", "*", "*"], - ["SMB", "110", "Inbound", "Allow", "tcp", "*", "445", "*", "*"], - ] - } - subnet1 = { - name = "AzureBastionSubnet" #Must be called AzureBastionSubnet - cidr = "10.0.0.128/25" - nsg_inbound = [ - ["bastion-in-allow", "100", "Inbound", "Allow", "tcp", "*", "443", "*", "*"], - ["bastion-control-in-allow-443", "120", "Inbound", "Allow", "tcp", "*", "443", "GatewayManager", "*"], - ["bastion-control-in-allow-4443", "121", "Inbound", "Allow", "tcp", "*", "4443", "GatewayManager", "*"], - ] - nsg_outbound = [ - ["bastion-vnet-out-allow-22", "100", "Outbound", "Allow", "tcp", "*", "22", "*", "VirtualNetwork"], - ["bastion-vnet-out-allow-3389", "101", "Outbound", "Allow", "tcp", "*", "3389", "*", "VirtualNetwork"], - ["bastion-azure-out-allow", "120", "Outbound", "Allow", "tcp", "*", "443", "*", "AzureCloud"], - ] - } - } - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - - # Settings for the public IP address to be used for Azure Firewall - # Must be standard and static for - firewall_ip_addr_config = { - ip_name = "firewall" - allocation_method = "Static" - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the Azure Firewall settings - az_fw_config = { - name = "azfw" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AzureFirewallApplicationRule", true, true, 30], - ["AzureFirewallNetworkRule", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the UDR object - udr_web_to_az_firewall = { - nexthop_type = "VirtualAppliance" - prefix = "0.0.0.0/0" - route_name = "web_to_az_firewall" - subnet_to_udr = "Web_tier" - nexthop_ip = "" - } - udr_transit_to_az_firewall = { - nexthop_type = "VirtualAppliance" - prefix = "10.0.1.0/24" - route_name = "transit_to_az_firewall" - subnet_to_udr = "GatewaySubnet" - nexthop_ip = "" - } - - ## DDoS standard configuration - enable_ddos_standard = false - ddos_name = "ddos_protection_plan" - - ## settings for Azure bastion configuration - ## not enabled, uncomment the code in the networking shared services blueprint. - enable_bastion = false - bastion_ip_addr_config = { - ip_name = "bastion" - ip_addr = { - allocation_method = "Static" - #Dynamic Public IP Addresses aren't allocated until they're assigned to a resource (such as a Virtual Machine or a Load Balancer) by design within Azure - - #properties below are optional - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - #dns_prefix = "arnaudmytest" - #timeout = 15 #TCP timeout for idle connections. The value can be set between 4 and 30 minutes. - #zones = [1] #1 zone number, IP address must be standard, ZoneRedundant argument is not supported in provider at time of writing - #reverse_fqdn = "" - #public_ip_prefix_id = "/subscriptions/00000000-00000-0000-0000-000000000000/resourceGroups/uqvh-hub-ingress-net/providers/Microsoft.Network/publicIPPrefixes/myprefix" - #refer to the prefix and check sku types are same in IP and prefix - } - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - bastion_config = { - name = "azurebastion" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["BastionAuditLogs", true, true, 30], - ] - metric = [ - # ["AllMetrics", true, true, 30], - ] - } - } - - - # Settings for the Virtual Network gateway to be created - provision_gateway = false - gateway_config = { - gateway_type = "VPN" - # Possible values are "VPN" or "ExpressRoute" - vpn_gateway_name = "vpngateway" - active_active = false - #An active-active gateway requires a HighPerformance or an UltraPerformance sku. If false, an active-standby gateway will be created. Defaults to false. - enable_bgp = false - #If true, BGP (Border Gateway Protocol) will be enabled for this Virtual Network Gateway. Defaults to false. - vpn_gateway_sku = "Basic" - #Valid options are Basic, Standard, HighPerformance, UltraPerformance, ErGw1AZ, ErGw2AZ, ErGw3AZ, VpnGw1, VpnGw2, VpnGw3, VpnGw1AZ, VpnGw2AZ, and VpnGw3AZ - #and depend on the gateway_type (ER or VPN) and vpn_type arguments, ie: PolicyBased gateway only supports the Basic sku. - vpn_gateway_type = "RouteBased" - #The routing type of the Virtual Network Gateway. Valid options are RouteBased or PolicyBased. Defaults to RouteBased. - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["GatewayDiagnosticLog", true, true, 30], - ["TunnelDiagnosticLog", true, true, 30], - ["RouteDiagnosticLog", true, true, 30], - ["IKEDiagnosticLog", true, true, 30], - ["P2SDiagnosticLog", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - pip = { - name = "vpn" - allocation_method = "Dynamic" - sku = "Basic" - #For basic SKU, you can pick the zone to be deployed - if you want multi zone - pick Standard IP and pick AZ aware VPN gateway SKU - #dns_prefix = "arnaudvpn" - #zones = ["1"] - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - } - - #Settings for the connection to be established - #Settings for the local network connection - connection_name = "onpremconnection" - remote_network_connect = true - - remote_network = { - gateway_name = "caf_local_network" - gateway_ip = "1.2.3.4" - gateway_adress_space = ["1.0.0.0/8"] - - bgp_settings = { - # asn = - # bgp_peering_address = - # peer_weight = - } - } - - ##Settings for the Azure Key Vault - akv_config = { - name = "vpn-akv" - akv_features = { - enabled_for_disk_encryption = true - enabled_for_deployment = true - enabled_for_template_deployment = true - } - sku_name = "standard" - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AuditEvent", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - -} \ No newline at end of file diff --git a/environments/integration-tests/landingzone_networking/landingzone_networking.tfvars b/environments/integration-tests/landingzone_networking/landingzone_networking.tfvars deleted file mode 100644 index 6f2c5bd2..00000000 --- a/environments/integration-tests/landingzone_networking/landingzone_networking.tfvars +++ /dev/null @@ -1,85 +0,0 @@ -resource_groups = { - vnet_us = { - name = "vnet-hub-us" - location = "westus2" - useprefix = true - max_length = 40 - } -} - -vnets = { - hub_us = { - resource_group_key = "vnet_us" - location = "westus2" - vnet = { - name = "hub" - address_space = ["10.10.100.0/24"] - } - specialsubnets = { - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = ["10.10.100.192/26"] - } - } - subnets = { - } - # Override the default var.diagnostics.vnet - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - -} - -firewalls = { - # Southeastasia firewall (do not change the key when created) - westus2 = { - location = "westus2" - resource_group_key = "vnet_us" - vnet_key = "hub_us" - - # Settings for the public IP address to be used for Azure Firewall - # Must be standard and static for - firewall_ip_addr_config = { - ip_name = "firewall" - allocation_method = "Static" - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the Azure Firewall settings - az_fw_config = { - name = "azfw" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AzureFirewallApplicationRule", true, true, 30], - ["AzureFirewallNetworkRule", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - } - -} \ No newline at end of file diff --git a/environments/integration-tests/landingzone_secure_vnet_dmz/landingzone_secure_vnet_dmz.tfvars b/environments/integration-tests/landingzone_secure_vnet_dmz/landingzone_secure_vnet_dmz.tfvars deleted file mode 100644 index 68d6f84d..00000000 --- a/environments/integration-tests/landingzone_secure_vnet_dmz/landingzone_secure_vnet_dmz.tfvars +++ /dev/null @@ -1,420 +0,0 @@ -# definition of variables for the virtual network -rg_network = { - CORE-NET = { - name = "-network-core" - } - TRANSIT-NET = { - name = "-network-transit" - } - EDGE-NET = { - name = "-network-edge" - } -} - -# settings for the core network blueprint -core_networking = { - shared_services_vnet = { - vnet = { - name = "Core-Network" - address_space = ["10.0.0.0/8"] - } - specialsubnets = { - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = ["10.0.4.0/24"] - } - GatewaySubnet = { - name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway - cidr = ["10.0.255.224/27"] - } - } - subnets = { - subnet0 = { - name = "Web_tier" - cidr = ["10.0.1.0/24"] - nsg_name = "Web_tier_nsg" - nsg = [ - { - name = "HTTP-In", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "80" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "HTTPS-In", - priority = "101" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - ] - } - subnet1 = { - name = "Business_tier" - cidr = ["10.0.2.0/24"] - nsg_name = "Business_tier_nsg" - nsg = [ - { - name = "HTTP-In", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "80" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "HTTPS-In", - priority = "101" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "HTTP-Out", - priority = "100" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "80" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "HTTPS-Out", - priority = "101" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - ] - } - subnet2 = { - name = "Data_tier" - cidr = ["10.0.3.0/24"] - nsg_name = "Data_tier_nsg" - nsg = [ - { - name = "TDS-In", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "UDP" - source_port_range = "*" - destination_port_range = "1433" - source_address_prefix = "*" - destination_address_prefix = "*" - } - ] - } - subnet3 = { - name = "AzureBastionSubnet" #Must be called AzureBastionSubnet - cidr = ["10.0.0.128/25"] - nsg_name = "AzureBastionSubnet_nsg" - nsg = [ - { - name = "bastion-in-allow", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-443", - priority = "120" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "135" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "Kerberos-password-change", - priority = "121" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "4443" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-vnet-out-allow-22", - priority = "103" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-vnet-out-allow-3389", - priority = "101" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-azure-out-allow", - priority = "120" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "AzureCloud" - } - ] - } - } - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - # netwatcher = { - # create = true - # #create the network watcher for a subscription and for the location of the vnet - # name = "arnaud-nw-test" - # #name of the network watcher to be created - - # flow_logs_settings = { - # enabled = true - # retention = true - # period = 7 - # } - - # traffic_analytics_settings = { - # enabled = true - # } - # } - } - - # Settings for the public IP address to be used for Azure Firewall - # Must be standard and static for - ip_addr_config = { - ip_name = "firewall" - allocation_method = "Static" - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the Azure Firewall settings - az_fw_config = { - name = "azfw" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AzureFirewallApplicationRule", true, true, 30], - ["AzureFirewallNetworkRule", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the UDR object - udr_web_to_az_firewall = { - nexthop_type = "VirtualAppliance" - prefix = "0.0.0.0/0" - route_name = "web_to_az_firewall" - subnet_to_udr = "Web_tier" - nexthop_ip = "" - } - udr_transit_to_az_firewall = { - nexthop_type = "VirtualAppliance" - prefix = "10.0.1.0/24" - route_name = "transit_to_az_firewall" - subnet_to_udr = "GatewaySubnet" - nexthop_ip = "" - } - - ## DDoS standard configuration - enable_ddos_standard = false - ddos_name = "ddos_protection_plan" - - ## settings for Azure bastion configuration - ## not enabled, uncomment the code in the networking shared services blueprint. - enable_bastion = true - bastion_ip_addr_config = { - ip_name = "bastion" - ip_addr = { - allocation_method = "Static" - #Dynamic Public IP Addresses aren't allocated until they're assigned to a resource (such as a Virtual Machine or a Load Balancer) by design within Azure - - #properties below are optional - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - #dns_prefix = "arnaudmytest" - #timeout = 15 #TCP timeout for idle connections. The value can be set between 4 and 30 minutes. - #zones = [1] #1 zone number, IP address must be standard, ZoneRedundant argument is not supported in provider at time of writing - #reverse_fqdn = "" - #public_ip_prefix_id = "/subscriptions/00000000-00000-0000-0000-000000000000/resourceGroups/uqvh-hub-ingress-net/providers/Microsoft.Network/publicIPPrefixes/myprefix" - #refer to the prefix and check sku types are same in IP and prefix - } - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - bastion_config = { - name = "azurebastionalz" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["BastionAuditLogs", true, true, 30], - ] - metric = [ - # ["AllMetrics", true, true, 30], - ] - } - - } - - - # Settings for the Virtual Network gateway to be created - provision_gateway = false - gateway_config = { - gateway_type = "VPN" - # Possible values are "VPN" or "ExpressRoute" - vpn_gateway_name = "vpngateway" - active_active = false - #An active-active gateway requires a HighPerformance or an UltraPerformance sku. If false, an active-standby gateway will be created. Defaults to false. - enable_bgp = false - #If true, BGP (Border Gateway Protocol) will be enabled for this Virtual Network Gateway. Defaults to false. - vpn_gateway_sku = "Basic" - #Valid options are Basic, Standard, HighPerformance, UltraPerformance, ErGw1AZ, ErGw2AZ, ErGw3AZ, VpnGw1, VpnGw2, VpnGw3, VpnGw1AZ, VpnGw2AZ, and VpnGw3AZ - #and depend on the gateway_type (ER or VPN) and vpn_type arguments, ie: PolicyBased gateway only supports the Basic sku. - vpn_gateway_type = "RouteBased" - #The routing type of the Virtual Network Gateway. Valid options are RouteBased or PolicyBased. Defaults to RouteBased. - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["GatewayDiagnosticLog", true, true, 30], - ["TunnelDiagnosticLog", true, true, 30], - ["RouteDiagnosticLog", true, true, 30], - ["IKEDiagnosticLog", true, true, 30], - ["P2SDiagnosticLog", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - pip = { - name = "vpn" - allocation_method = "Dynamic" - sku = "Basic" - #For basic SKU, you can pick the zone to be deployed - if you want multi zone - pick Standard IP and pick AZ aware VPN gateway SKU - #dns_prefix = "arnaudvpn" - #zones = ["1"] - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - } - - #Settings for the connection to be established - #Settings for the local network connection - connection_name = "onpremconnection" - remote_network_connect = true - - remote_network = { - gateway_name = "caf_local_network" - gateway_ip = "1.2.3.4" - gateway_adress_space = ["1.0.0.0/8"] - - bgp_settings = { - # asn = - # bgp_peering_address = - # peer_weight = - } - } - - ##Settings for the Azure Key Vault - akv_config = { - name = "vpn-akv" - akv_features = { - enabled_for_disk_encryption = true - enabled_for_deployment = true - enabled_for_template_deployment = true - } - sku_name = "standard" - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AuditEvent", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - -} \ No newline at end of file diff --git a/environments/integration-tests/landingzone_starter/landingzone_starter.tfvars b/environments/integration-tests/landingzone_starter/landingzone_starter.tfvars deleted file mode 100644 index c4c88a5b..00000000 --- a/environments/integration-tests/landingzone_starter/landingzone_starter.tfvars +++ /dev/null @@ -1 +0,0 @@ -# nothing \ No newline at end of file diff --git a/environments/integration-tests/landingzone_vdc_demo/landingzone_vdc_demo.tfvars b/environments/integration-tests/landingzone_vdc_demo/landingzone_vdc_demo.tfvars deleted file mode 100644 index 39ae21b9..00000000 --- a/environments/integration-tests/landingzone_vdc_demo/landingzone_vdc_demo.tfvars +++ /dev/null @@ -1,577 +0,0 @@ -# settings for the shared network blueprint -resource_groups_shared_services = { - HUB-CORE-NET = { - name = "-hub-network-shared" - location = "southeastasia" - } -} - -enable_ddos_standard = false -ddos_name = "ddos_protection_plan" - -shared_services_vnet = { - vnet = { - name = "Shared-Services" - address_space = ["10.101.4.0/22"] - dns = [] - } - specialsubnets = { - } - subnets = { - subnet0 = { - name = "Critical_Applications" - cidr = ["10.101.4.0/25"] - nsg_name = "Critical_Applications_nsg" - service_endpoints = [] - } - subnet1 = { - name = "Active_Directory" - cidr = ["10.101.4.128/27"] - service_endpoints = [] - nsg_name = "Active_Directory_nsg" - nsg = [ - { - name = "W32Time", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "UDP" - source_port_range = "*" - destination_port_range = "123" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "RPC-Endpoint-Mapper", - priority = "101" - direction = "Inbound" - access = "Allow" - protocol = "UDP" - source_port_range = "*" - destination_port_range = "135" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "Kerberos-password-change", - priority = "102" - direction = "Inbound" - access = "Allow" - protocol = "*" - source_port_range = "*" - destination_port_range = "464" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "RPC-Dynamic-range", - priority = "103" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "49152-65535" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "LDAP", - priority = "104" - direction = "Inbound" - access = "Allow" - protocol = "*" - source_port_range = "*" - destination_port_range = "389" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "LDAP-SSL", - priority = "105" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "636" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "LDAP-GC", - priority = "106" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3268" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "LDAP-GC-SSL", - priority = "107" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3269" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "DNS", - priority = "108" - direction = "Inbound" - access = "Allow" - protocol = "*" - source_port_range = "*" - destination_port_range = "53" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "Kerberos", - priority = "109" - direction = "Inbound" - access = "Allow" - protocol = "*" - source_port_range = "*" - destination_port_range = "88" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "SMB", - priority = "110" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "445" - source_address_prefix = "*" - destination_address_prefix = "*" - } - ] - } - subnet2 = { - name = "SQL_Servers" - cidr = ["10.101.4.160/27"] - service_endpoints = [] - nsg_name = "Data_tier_nsg" - nsg = [ - { - name = "TDS-In", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "UDP" - source_port_range = "*" - destination_port_range = "1433" - source_address_prefix = "*" - destination_address_prefix = "*" - } - ] - } - subnet4 = { - name = "AzureBastionSubnet" - cidr = ["10.101.4.192/27"] - nsg_name = "AzureBastionSubnet_nsg" - nsg = [ - { - name = "bastion-in-allow", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-443", - priority = "120" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "135" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "Kerberos-password-change", - priority = "121" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "4443" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-vnet-out-allow-22", - priority = "103" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-vnet-out-allow-3389", - priority = "101" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-azure-out-allow", - priority = "120" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "AzureCloud" - } - ] - } - } - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } -} - -## settings for Azure bastion configuration -## not enabled, uncomment the code in the networking shared services blueprint. -enable_bastion = true -bastion_config = { - name = "azurebastion" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["BastionAuditLogs", true, true, 30], - ] - metric = [ - # ["AllMetrics", true, true, 30], - ] - } - ip_name = "caf-pip-bastion" - ip_addr = { - allocation_method = "Static" - #Dynamic Public IP Addresses aren't allocated until they're assigned to a resource (such as a Virtual Machine or a Load Balancer) by design within Azure - - #properties below are optional - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - #dns_prefix = "arnaudmytest" - #timeout = 15 #TCP timeout for idle connections. The value can be set between 4 and 30 minutes. - #zones = [1] #1 zone number, IP address must be standard, ZoneRedundant argument is not supported in provider at time of writing - #reverse_fqdn = "" - #public_ip_prefix_id = "/subscriptions/00000000-00000-0000-0000-000000000000/resourceGroups/uqvh-hub-ingress-net/providers/Microsoft.Network/publicIPPrefixes/myprefix" - #refer to the prefix and check sku types are same in IP and prefix - } - ip_diags = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } -} - - -# settings for the shared egress blueprint -resource_groups_shared_egress = { - HUB-EGRESS-NET = { - name = "-hub-network-egress" - location = "southeastasia" - } -} - -# Settings for the shared services egress vnet - note that Azure Firewall subnet must be at least /26 -networking_egress = { - vnet = { - name = "Shared-Egress" - address_space = ["10.0.0.0/25"] - dns = ["192.168.0.16", "192.168.0.64"] - } - specialsubnets = { - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" - cidr = ["10.0.0.0/26"] - service_endpoints = [] - } - } - subnets = { - subnet1 = { - name = "Network_Monitoring" - cidr = ["10.0.0.64/26"] - nsg_name = "Network_Monitoring_nsg" - } - } - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } -} - -# Settings for the public IP address to be used for egress -# Must be standard and static for Azure Firewall -ip_addr_config = { - ip_name = "caf-pip-egress" - allocation_method = "Static" - #Dynamic Public IP Addresses aren't allocated until they're assigned to a resource (such as a Virtual Machine or a Load Balancer) by design within Azure - - #properties below are optional - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - #dns_prefix = "arnaudmytest" - #timeout = 15 #TCP timeout for idle connections. The value can be set between 4 and 30 minutes. - #zones = [1] #1 zone number, IP address must be standard, ZoneRedundant argument is not supported in provider at time of writing - #reverse_fqdn = "" - #public_ip_prefix_id = "/subscriptions/00000000-00000-0000-0000-000000000000/resourceGroups/uqvh-hub-ingress-net/providers/Microsoft.Network/publicIPPrefixes/myprefix" - #refer to the prefix and check sku types are same in IP and prefix - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } -} - -# Settings for the Azure Firewall settings -az_fw_config = { - name = "az-fw-caf" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AzureFirewallApplicationRule", true, true, 30], - ["AzureFirewallNetworkRule", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } -} - -# Settings for the UDR object -udr_object = { - nexthop_type = "VirtualAppliance" - prefix = "0.0.0.0/0" - route_name = "myWay" - subnets_to_udr = "" - nexthop_ip = "" -} - -# settings for the transit network blueprint - -#resource group creation -resource_groups_shared_transit = { - HUB-NET-TRANSIT = { - name = "-hub-network-transit" - location = "southeastasia" - } -} - -# Settings for the shared services egress vnet -networking_transit = { - vnet = { - name = "Shared-Transit" - address_space = ["172.16.0.0/23"] - dns = ["192.168.0.16", "192.168.0.64"] - } - specialsubnets = { - GatewaySubnet = { - name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway - cidr = ["172.16.0.0/24"] - service_endpoints = [] - } - } - subnets = { - subnet1 = { - name = "NetworkMonitoring" - cidr = ["172.16.1.0/24"] - nsg_name = "NetworkMonitoring_msg" - service_endpoints = [] - } - } - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } -} - -# Settings for the public IP address to be used for egress -public_ip_addr = { - name = "caf-pip-vpn" - allocation_method = "Dynamic" - sku = "Basic" - #For basic SKU, you can pick the zone to be deployed - if you want multi zone - pick Standard IP and pick AZ aware VPN gateway SKU - #dns_prefix = "arnaudvpn" - #zones = ["1"] - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } -} - -# Settings for the Virtual Network gateway to be created -provision_gateway = false -gateway_config = { - gateway_type = "VPN" - # Possible values are "VPN" or "ExpressRoute" - vpn_gateway_name = "mygateway" - active_active = false - #An active-active gateway requires a HighPerformance or an UltraPerformance sku. If false, an active-standby gateway will be created. Defaults to false. - enable_bgp = false - #If true, BGP (Border Gateway Protocol) will be enabled for this Virtual Network Gateway. Defaults to false. - vpn_gateway_sku = "Basic" - #Valid options are Basic, Standard, HighPerformance, UltraPerformance, ErGw1AZ, ErGw2AZ, ErGw3AZ, VpnGw1, VpnGw2, VpnGw3, VpnGw1AZ, VpnGw2AZ, and VpnGw3AZ - #and depend on the gateway_type (ER or VPN) and vpn_type arguments, ie: PolicyBased gateway only supports the Basic sku. - vpn_gateway_type = "RouteBased" - #The routing type of the Virtual Network Gateway. Valid options are RouteBased or PolicyBased. Defaults to RouteBased. - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["GatewayDiagnosticLog", true, true, 30], - ["TunnelDiagnosticLog", true, true, 30], - ["RouteDiagnosticLog", true, true, 30], - ["IKEDiagnosticLog", true, true, 30], - ["P2SDiagnosticLog", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } -} - - -#Settings for the connection to be established -#Settings for the local network connection -connection_name = "onpremconnection" -remote_network_connect = true - -remote_network = { - gateway_name = "caf_local_network" - gateway_ip = "1.2.3.4" - gateway_adress_space = ["1.0.0.0/8"] -} - -##Settings for the Azure Key Vault - -akv_config = { - name = "techakv" - akv_features = { - enabled_for_disk_encryption = true - enabled_for_deployment = true - enabled_for_template_deployment = true - } - sku_name = "premium" - # network_acls = { - # bypass = "AzureServices" - # default_action = "Deny" - # } - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AuditEvent", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } -} - -# settings for the operations blueprint - -# #Azure Site Recovery Configuration -asr_config = { - asr_vault_name = "asr" - asr_diags = { - log_analytics_destination_type = "Dedicated" - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AzureBackupReport", true, true, 30], - ["CoreAzureBackup", true, true, 30], - ["AddonAzureBackupAlerts", true, true, 30], - ["AddonAzureBackupJobs", true, true, 30], - ["AddonAzureBackupPolicy", true, true, 30], - ["AddonAzureBackupProtectedInstance", true, true, 30], - ["AddonAzureBackupStorage", true, true, 30], - ["AzureSiteRecoveryJobs", true, true, 30], - ["AzureSiteRecoveryEvents", true, true, 30], - ["AzureSiteRecoveryReplicatedItems", true, true, 30], - ["AzureSiteRecoveryReplicationStats", true, true, 30], - ["AzureSiteRecoveryRecoveryPoints", true, true, 30], - ["AzureSiteRecoveryReplicationDataUploadRate", true, true, 30], - ["AzureSiteRecoveryProtectedDiskDataChurn", true, true, 30], - ] - metric = [ - #["AllMetrics", 60, True], - ] - } -} - - -#Azure Automation account name -auto_config = { - auto_account = "azauto" - auto_diags = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["JobLogs", true, true, 30], - ["JobStreams", true, true, 30], - ["DscNodeStatus", true, true, 30], - ] - metric = [ - # ["Category name", "Metric Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 30], - ] - } -} \ No newline at end of file diff --git a/landingzones/caf_foundations/README.md b/landingzones/caf_foundations/README.md new file mode 100644 index 00000000..6ed7e238 --- /dev/null +++ b/landingzones/caf_foundations/README.md @@ -0,0 +1,40 @@ +# Cloud Adoption Framework for Azure - Landing zones on Terraform - Foundations + +The foundations landing zone allows you to manage the core components of an environment: + +* Management groups +* Policies +* Auditing and Accounting, deployment or connection to existing ones. + +Foundations landing zone operates at **level 1**. + +For a review of the hierarchy approach of Cloud Adoption Framework for Azure landing zones on Terraform, you can refer to [the following documentation](../../documentation/code_architecture/hierarchy.md). + +
+ +## Components + +CAF foundations landing zone leverages the enterprise-scale module in order to deploy its core components. + +## Deploying CAF foundations + +By default, the content of this landing zone is empty unless you specify a configuration file to enable it. + +```bash +# To deploy the CAF foundations in passthrough mode +rover -lz /tf/caf/landingzones/caf_foundations \ +-level level1 \ +-a apply +``` + +## Deploying CAF foundations with enterprise-scale (experimental) + +This is currently work in progress. +Use the following configuration file in order to get started with the enterprise-scale module integration: + +```bash +rover -lz /tf/caf/landingzones/caf_foundations \ +-var-folder /tf/caf/landingzones/caf_foundations/scenario/200 \ +-level level1 \ +-a apply +``` diff --git a/landingzones/landingzone_networking/backend.azurerm b/landingzones/caf_foundations/backend.azurerm similarity index 100% rename from landingzones/landingzone_networking/backend.azurerm rename to landingzones/caf_foundations/backend.azurerm diff --git a/landingzones/caf_foundations/es_main.tf b/landingzones/caf_foundations/es_main.tf new file mode 100644 index 00000000..92eab72e --- /dev/null +++ b/landingzones/caf_foundations/es_main.tf @@ -0,0 +1,25 @@ + +module "enterprise_scale" { + source = "Azure/caf-enterprise-scale/azurerm" + version = "0.0.6-preview" + + root_parent_id = data.azurerm_client_config.current.tenant_id + + # Define a custom ID to use for the root Management Group + # Also used as a prefix for all core Management Group IDs + root_id = "caf" + + # Control whether to deploy the default core landing zones // default = true + deploy_core_landing_zones = false + + # Control whether to deploy the demo landing zones // default = false + deploy_demo_landing_zones = false + + # Set a path for the custom archetype library path + library_path = try(format("%s%s", path.root, var.enterprise_scale.library_path), "") + + # Deploys the custom landing zone configuration as defined in config file + custom_landing_zones = try(var.enterprise_scale.management_groups, {}) + + default_location = local.global_settings.regions[local.global_settings.default_region] +} \ No newline at end of file diff --git a/landingzones/caf_foundations/locals.remote_tfstates.tf b/landingzones/caf_foundations/locals.remote_tfstates.tf new file mode 100644 index 00000000..3bb21c81 --- /dev/null +++ b/landingzones/caf_foundations/locals.remote_tfstates.tf @@ -0,0 +1,57 @@ +locals { + landingzone = { + current = { + storage_account_name = var.tfstate_storage_account_name + container_name = var.tfstate_container_name + resource_group_name = var.tfstate_resource_group_name + } + lower = { + storage_account_name = var.lower_storage_account_name + container_name = var.lower_container_name + resource_group_name = var.lower_resource_group_name + } + } +} + +data "terraform_remote_state" "remote" { + for_each = try(var.landingzone.tfstates, {}) + + backend = var.landingzone.backend_type + config = { + storage_account_name = local.landingzone[try(each.value.level, "current")].storage_account_name + container_name = local.landingzone[try(each.value.level, "current")].container_name + resource_group_name = local.landingzone[try(each.value.level, "current")].resource_group_name + key = each.value.tfstate + } +} + +locals { + landingzone_tag = { + "landingzone" = var.landingzone.key + } + + tags = merge(var.tags, local.landingzone_tag, { "level" = var.landingzone.level }, { "environment" = local.global_settings.environment }, { "rover_version" = var.rover_version }) + + global_settings = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings + + diagnostics = { + diagnostics_definition = merge(data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.diagnostics_definition, var.diagnostics_definition) + diagnostics_destinations = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.diagnostics_destinations + storage_accounts = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.storage_accounts + log_analytics = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.log_analytics + } + + + + remote = { + managed_identities = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.managed_identities[key], {})) + } + azuread_groups = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.azuread_groups[key], {})) + } + vnets = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.vnets[key], {})) + } + } +} diff --git a/landingzones/caf_foundations/main.tf b/landingzones/caf_foundations/main.tf new file mode 100644 index 00000000..4bc35db8 --- /dev/null +++ b/landingzones/caf_foundations/main.tf @@ -0,0 +1,63 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 2.32.0" + } + azuread = { + source = "hashicorp/azuread" + version = "~> 1.0.0" + } + random = { + source = "hashicorp/random" + version = "~> 2.2.1" + } + null = { + source = "hashicorp/null" + version = "~> 2.1.0" + } + tls = { + source = "hashicorp/tls" + version = "~> 2.2.0" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~> 1.1.0" + } + } + required_version = ">= 0.13" +} + + +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + } + } +} + +data "azurerm_client_config" "current" {} +data "azurerm_subscription" "current" {} + +locals { + + # Update the tfstates map + tfstates = merge( + map(var.landingzone.key, + map( + "storage_account_name", var.tfstate_storage_account_name, + "container_name", var.tfstate_container_name, + "resource_group_name", var.tfstate_resource_group_name, + "key", var.tfstate_key, + "level", var.landingzone.level, + "tenant_id", var.tenant_id, + "subscription_id", data.azurerm_client_config.current.subscription_id + ) + ) + , + data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.tfstates + ) + +} + diff --git a/landingzones/caf_foundations/output.tf b/landingzones/caf_foundations/output.tf new file mode 100644 index 00000000..1c546018 --- /dev/null +++ b/landingzones/caf_foundations/output.tf @@ -0,0 +1,27 @@ +output global_settings { + value = local.global_settings + sensitive = true +} + +output diagnostics { + value = local.diagnostics + sensitive = true +} + +output vnets { + value = local.remote.vnets + sensitive = true +} +output managed_identities { + value = local.remote.managed_identities + sensitive = true +} +output azuread_groups { + value = local.remote.azuread_groups + sensitive = true +} + +output tfstates { + value = local.tfstates + sensitive = true +} diff --git a/landingzones/caf_foundations/scenario/200/enterprise_scale.tfvars b/landingzones/caf_foundations/scenario/200/enterprise_scale.tfvars new file mode 100644 index 00000000..63abe196 --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/enterprise_scale.tfvars @@ -0,0 +1,45 @@ +landingzone = { + backend_type = "azurerm" + global_settings_key = "launchpad" + level = "level1" + key = "caf_foundations" + tfstates = { + launchpad = { + level = "lower" + tfstate = "caf_launchpad.tfstate" + } + } +} + +enterprise_scale = { + #path to the policies definition and assignment repo + library_path = "/scenario/200/lib" + + #management groups hierarchy configuration + management_groups = { + caf = { + display_name = "CAF-RootManagementGroup" + parent_management_group_id = "" + subscription_ids = [] + archetype_config = { + archetype_id = "es_root" + parameters = {} + access_control = {} + } + } + child-caf = { + display_name = "CAF-ChildManagementGroup" + parent_management_group_id = "caf" + subscription_ids = [] + archetype_config = { + archetype_id = "es_management" + parameters = { + ES-Deploy-ForwardDiagLog = { + logAnalytics = "central_logs_region1" + } + } + access_control = {} + } + } + } +} \ No newline at end of file diff --git a/landingzones/caf_foundations/scenario/200/lib/archetype_definition_es_management.tmpl.json b/landingzones/caf_foundations/scenario/200/lib/archetype_definition_es_management.tmpl.json new file mode 100644 index 00000000..e6d18b5d --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/lib/archetype_definition_es_management.tmpl.json @@ -0,0 +1,12 @@ +{ + "es_management": { + "policy_assignments": [ + "ES-Deploy-ASC-Standard" + ], + "policy_definitions": [ + ], + "policy_set_definitions": [], + "role_assignments": [], + "role_definitions": [] + } +} \ No newline at end of file diff --git a/landingzones/caf_foundations/scenario/200/lib/archetype_definition_es_root.json b/landingzones/caf_foundations/scenario/200/lib/archetype_definition_es_root.json new file mode 100644 index 00000000..e41b04f6 --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/lib/archetype_definition_es_root.json @@ -0,0 +1,13 @@ +{ + "es_root": { + "policy_assignments": [ + "ES-Deploy-ASC-Standard" + ], + "policy_definitions": [ + "ES-Deploy-ASC-Standard" + ], + "policy_set_definitions": [], + "role_assignments": [], + "role_definitions": [] + } +} \ No newline at end of file diff --git a/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_allowed_resource-locations.tmpl.json b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_allowed_resource-locations.tmpl.json new file mode 100644 index 00000000..ae28ea45 --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_allowed_resource-locations.tmpl.json @@ -0,0 +1,28 @@ +{ + "name": "ES-Allowed-Locations", + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2019-09-01", + "properties": { + "description": "Specifies the allowed locations (regions) where resources can be deployed", + "displayName": "ES-Allowed-Resource-Locations", + "notScopes": [], + "parameters": { + "listOfAllowedLocations": { + "value": [ + "uksouth", + "ukwest" + ] + } + }, + "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c", + "scope": "${current_scope_resource_id}" + }, + "sku": { + "name": "A0", + "tier": "Free" + }, + "location": "${default_location}", + "identity": { + "type": "None" + } +} diff --git a/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_allowed_resourcegroup-locations.tmpl.json b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_allowed_resourcegroup-locations.tmpl.json new file mode 100644 index 00000000..b0017458 --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_allowed_resourcegroup-locations.tmpl.json @@ -0,0 +1,28 @@ +{ + "name": "ES-Allowed-RSG-Locations", + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2019-09-01", + "properties": { + "description": "Specifies the allowed locations (regions) where Resource Groups can be deployed", + "displayName": "ES-Allowed-ResourceGroup-Locations", + "notScopes": [], + "parameters": { + "listOfAllowedLocations": { + "value": [ + "uksouth", + "ukwest" + ] + } + }, + "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/e765b5de-1225-4ba3-bd56-1ac6695af988", + "scope": "${current_scope_resource_id}" + }, + "sku": { + "name": "A0", + "tier": "Free" + }, + "location": "${default_location}", + "identity": { + "type": "None" + } +} diff --git a/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_asc_ce.tmpl.json b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_asc_ce.tmpl.json new file mode 100644 index 00000000..4417b6a0 --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_asc_ce.tmpl.json @@ -0,0 +1,28 @@ +{ + "name": "ES-Deploy-ASC-ContExport", + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2019-09-01", + "properties": { + "description": "Deploy ASC Continuous Export To Log Analytics Workspace.", + "displayName": "ES-Deploy-ASC-ContinuousExportToWorkspace", + "notScopes": [], + "parameters": { + "resourceGroupLocation": { + "value": null + }, + "workspaceResourceId": { + "value": null + } + }, + "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/ES-Deploy-ASC-ContinuousExportToWorkspace", + "scope": "${current_scope_resource_id}" + }, + "sku": { + "name": "A0", + "tier": "Free" + }, + "location": "${default_location}", + "identity": { + "type": "SystemAssigned" + } +} diff --git a/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_asc_monitoring.tmpl.json b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_asc_monitoring.tmpl.json new file mode 100644 index 00000000..ba6d2186 --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_asc_monitoring.tmpl.json @@ -0,0 +1,88 @@ +{ + "name": "ES-Deploy-ASC-Monitoring", + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2019-09-01", + "properties": { + "description": "Enable Monitoring in Azure Security Center.", + "displayName": "ES-Deploy-ASC-Monitoring", + "notScopes": [], + "parameters": { + "aadAuthenticationInSqlServerMonitoringEffect": { + "value": "Disabled" + }, + "diskEncryptionMonitoringEffect": { + "value": "Disabled" + }, + "encryptionOfAutomationAccountMonitoringEffect": { + "value": "Disabled" + }, + "identityDesignateLessThanOwnersMonitoringEffect": { + "value": "Disabled" + }, + "identityDesignateMoreThanOneOwnerMonitoringEffect": { + "value": "Disabled" + }, + "identityEnableMFAForWritePermissionsMonitoringEffect": { + "value": "Disabled" + }, + "identityRemoveDeprecatedAccountMonitoringEffect": { + "value": "Disabled" + }, + "identityRemoveDeprecatedAccountWithOwnerPermissionsMonitoringEffect": { + "value": "Disabled" + }, + "identityRemoveExternalAccountWithOwnerPermissionsMonitoringEffect": { + "value": "Disabled" + }, + "identityRemoveExternalAccountWithReadPermissionsMonitoringEffect": { + "value": "Disabled" + }, + "identityRemoveExternalAccountWithWritePermissionsMonitoringEffect": { + "value": "Disabled" + }, + "jitNetworkAccessMonitoringEffect": { + "value": "Disabled" + }, + "networkSecurityGroupsOnSubnetsMonitoringEffect": { + "value": "AuditIfNotExists" + }, + "sqlDbEncryptionMonitoringEffect": { + "value": "Disabled" + }, + "sqlManagedInstanceAdvancedDataSecurityEmailAdminsMonitoringEffect": { + "value": "Disabled" + }, + "sqlManagedInstanceAdvancedDataSecurityEmailsMonitoringEffect": { + "value": "Disabled" + }, + "sqlServerAdvancedDataSecurityEmailAdminsMonitoringEffect": { + "value": "Disabled" + }, + "sqlServerAdvancedDataSecurityMonitoringEffect": { + "value": "Disabled" + }, + "systemUpdatesMonitoringEffect": { + "value": "Disabled" + }, + "useRbacRulesMonitoringEffect": { + "value": "Disabled" + }, + "vmssSystemUpdatesMonitoringEffect": { + "value": "Disabled" + }, + "windowsDefenderExploitGuardMonitoringEffect": { + "value": "Disabled" + } + }, + "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8", + "scope": "${current_scope_resource_id}" + }, + "sku": { + "name": "A0", + "tier": "Free" + }, + "location": "${default_location}", + "identity": { + "type": "SystemAssigned" + } +} diff --git a/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_asc_standard.tmpl.json b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_asc_standard.tmpl.json new file mode 100644 index 00000000..1786a9c3 --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_asc_standard.tmpl.json @@ -0,0 +1,21 @@ +{ + "name": "ES-Deploy-ASC-Standard", + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2019-09-01", + "properties": { + "description": "Deploy Azure Security Center Standard Tier.", + "displayName": "ES-Deploy-ASC-Standard", + "notScopes": [], + "parameters": {}, + "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/ES-Deploy-ASC-Standard", + "scope": "${current_scope_resource_id}" + }, + "sku": { + "name": "A0", + "tier": "Free" + }, + "location": "${default_location}", + "identity": { + "type": "SystemAssigned" + } +} diff --git a/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_diag_activitylog.tmpl.json b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_diag_activitylog.tmpl.json new file mode 100644 index 00000000..7bf367af --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_diag_activitylog.tmpl.json @@ -0,0 +1,25 @@ +{ + "name": "ES-Deploy-ForwardActLogs", + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2019-09-01", + "properties": { + "description": "Ensures that Activity Log Diagnostics settings are set to push logs into Log Analytics workspace.", + "displayName": "ES-Deploy-Diagnostics-ForwardActivityLogs", + "notScopes": [], + "parameters": { + "logAnalytics": { + "value": null + } + }, + "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/ES-Deploy-Diagnostics-LogAnalytics", + "scope": "${current_scope_resource_id}" + }, + "sku": { + "name": "A0", + "tier": "Free" + }, + "location": "${default_location}", + "identity": { + "type": "SystemAssigned" + } +} diff --git a/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_diag_loganalytics.tmpl.json b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_diag_loganalytics.tmpl.json new file mode 100644 index 00000000..6cae9535 --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/lib/policy_assignment_es_deploy_diag_loganalytics.tmpl.json @@ -0,0 +1,25 @@ +{ + "name": "ES-Deploy-ForwardDiagLog", + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2019-09-01", + "properties": { + "description": "Ensures that Azure resources are configured to forward diagnostic logs and metrics to an Azure Log Analytics workspace.", + "displayName": "ES-Deploy-Diagnostics-ForwardDiagnosticLogs", + "notScopes": [], + "parameters": { + "logAnalytics": { + "value": null + } + }, + "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policySetDefinitions/ES-Deploy-Diagnostics-LogAnalytics", + "scope": "${current_scope_resource_id}" + }, + "sku": { + "name": "A0", + "tier": "Free" + }, + "location": "${default_location}", + "identity": { + "type": "SystemAssigned" + } +} diff --git a/landingzones/caf_foundations/scenario/200/lib/policy_definition_es_deploy_asc_standard.json b/landingzones/caf_foundations/scenario/200/lib/policy_definition_es_deploy_asc_standard.json new file mode 100644 index 00000000..d75c1298 --- /dev/null +++ b/landingzones/caf_foundations/scenario/200/lib/policy_definition_es_deploy_asc_standard.json @@ -0,0 +1,284 @@ +{ + "name": "ES-Deploy-ASC-Standard", + "type": "Microsoft.Authorization/policyDefinitions", + "apiVersion": "2019-09-01", + "properties": { + "description": "Ensures that subscriptions have Security Center Standard enabled.", + "displayName": "ES-Deploy-ASC-Standard", + "mode": "All", + "parameters": { + "pricingTierVMs": { + "type": "String", + "metadata": { + "displayName": "pricingTierVMs", + "description": "" + }, + "allowedValues": [ + "Standard", + "Free" + ], + "defaultValue": "Standard" + }, + "pricingTierSqlServers": { + "type": "String", + "metadata": { + "displayName": "pricingTierSqlServers", + "description": "" + }, + "allowedValues": [ + "Standard", + "Free" + ], + "defaultValue": "Standard" + }, + "pricingTierAppServices": { + "type": "String", + "metadata": { + "displayName": "pricingTierAppServices", + "description": "" + }, + "allowedValues": [ + "Standard", + "Free" + ], + "defaultValue": "Standard" + }, + "pricingTierStorageAccounts": { + "type": "String", + "metadata": { + "displayName": "pricingTierStorageAccounts", + "description": "" + }, + "allowedValues": [ + "Standard", + "Free" + ], + "defaultValue": "Standard" + }, + "pricingTierContainerRegistry": { + "type": "String", + "metadata": { + "displayName": "pricingTierContainerRegistry", + "description": "" + }, + "allowedValues": [ + "Standard", + "Free" + ], + "defaultValue": "Standard" + }, + "pricingTierKeyVaults": { + "type": "String", + "metadata": { + "displayName": "pricingTierKeyVaults", + "description": "" + }, + "allowedValues": [ + "Standard", + "Free" + ], + "defaultValue": "Standard" + }, + "pricingTierKubernetesService": { + "type": "String", + "metadata": { + "displayName": "pricingTierKubernetesService", + "description": "" + }, + "allowedValues": [ + "Standard", + "Free" + ], + "defaultValue": "Standard" + } + }, + "policyRule": { + "if": { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.Resources/subscriptions" + } + ] + }, + "then": { + "effect": "deployIfNotExists", + "details": { + "type": "Microsoft.Security/pricings", + "deploymentScope": "subscription", + "existenceScope": "subscription", + "roleDefinitionIds": [ + "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635" + ], + "existenceCondition": { + "allOf": [ + { + "field": "Microsoft.Security/pricings/pricingTier", + "equals": "Standard" + }, + { + "field": "type", + "equals": "Microsoft.Security/pricings" + } + ] + }, + "deployment": { + "location": "northeurope", + "properties": { + "mode": "incremental", + "parameters": { + "pricingTierVMs": { + "value": "[parameters('pricingTierVMs')]" + }, + "pricingTierSqlServers": { + "value": "[parameters('pricingTierSqlServers')]" + }, + "pricingTierAppServices": { + "value": "[parameters('pricingTierAppServices')]" + }, + "pricingTierStorageAccounts": { + "value": "[parameters('pricingTierStorageAccounts')]" + }, + "pricingTierContainerRegistry": { + "value": "[parameters('pricingTierContainerRegistry')]" + }, + "pricingTierKeyVaults": { + "value": "[parameters('pricingTierKeyVaults')]" + }, + "pricingTierKubernetesService": { + "value": "[parameters('pricingTierKubernetesService')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "pricingTierVMs": { + "type": "string", + "metadata": { + "description": "pricingTierVMs" + } + }, + "pricingTierSqlServers": { + "type": "string", + "metadata": { + "description": "pricingTierSqlServers" + } + }, + "pricingTierAppServices": { + "type": "string", + "metadata": { + "description": "pricingTierAppServices" + } + }, + "pricingTierStorageAccounts": { + "type": "string", + "metadata": { + "description": "pricingTierStorageAccounts" + } + }, + "pricingTierContainerRegistry": { + "type": "string", + "metadata": { + "description": "ContainerRegistry" + } + }, + "pricingTierKeyVaults": { + "type": "string", + "metadata": { + "description": "KeyVaults" + } + }, + "pricingTierKubernetesService": { + "type": "string", + "metadata": { + "description": "KubernetesService" + } + } + }, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Security/pricings", + "apiVersion": "2018-06-01", + "name": "VirtualMachines", + "properties": { + "pricingTier": "[parameters('pricingTierVMs')]" + } + }, + { + "type": "Microsoft.Security/pricings", + "apiVersion": "2018-06-01", + "name": "StorageAccounts", + "dependsOn": [ + "[concat('Microsoft.Security/pricings/VirtualMachines')]" + ], + "properties": { + "pricingTier": "[parameters('pricingTierStorageAccounts')]" + } + }, + { + "type": "Microsoft.Security/pricings", + "apiVersion": "2018-06-01", + "name": "AppServices", + "dependsOn": [ + "[concat('Microsoft.Security/pricings/StorageAccounts')]" + ], + "properties": { + "pricingTier": "[parameters('pricingTierAppServices')]" + } + }, + { + "type": "Microsoft.Security/pricings", + "apiVersion": "2018-06-01", + "name": "SqlServers", + "dependsOn": [ + "[concat('Microsoft.Security/pricings/AppServices')]" + ], + "properties": { + "pricingTier": "[parameters('pricingTierSqlServers')]" + } + }, + { + "type": "Microsoft.Security/pricings", + "apiVersion": "2018-06-01", + "name": "KeyVaults", + "dependsOn": [ + "[concat('Microsoft.Security/pricings/SqlServers')]" + ], + "properties": { + "pricingTier": "[parameters('pricingTierKeyVaults')]" + } + }, + { + "type": "Microsoft.Security/pricings", + "apiVersion": "2018-06-01", + "name": "KubernetesService", + "dependsOn": [ + "[concat('Microsoft.Security/pricings/KeyVaults')]" + ], + "properties": { + "pricingTier": "[parameters('pricingTierKubernetesService')]" + } + }, + { + "type": "Microsoft.Security/pricings", + "apiVersion": "2018-06-01", + "name": "ContainerRegistry", + "dependsOn": [ + "[concat('Microsoft.Security/pricings/KubernetesService')]" + ], + "properties": { + "pricingTier": "[parameters('pricingTierContainerRegistry')]" + } + } + ], + "outputs": {} + } + } + } + } + } + } + } +} diff --git a/landingzones/caf_foundations/variables.tf b/landingzones/caf_foundations/variables.tf new file mode 100644 index 00000000..b69a305e --- /dev/null +++ b/landingzones/caf_foundations/variables.tf @@ -0,0 +1,53 @@ +# Map of the remote data state +variable lower_storage_account_name {} +variable lower_container_name {} +variable lower_resource_group_name {} + +variable tfstate_storage_account_name { + description = "This value is propulated by the rover" +} +variable tfstate_container_name { + description = "This value is propulated by the rover" +} +variable tfstate_key { + description = "This value is propulated by the rover" +} +variable tfstate_resource_group_name { + description = "This value is propulated by the rover" +} + +variable landingzone { + default = { + backend_type = "azurerm" + global_settings_key = "launchpad" + level = "level1" + key = "foundations" + tfstates = { + launchpad = { + level = "lower" + tfstate = "caf_launchpad.tfstate" + } + } + } +} + +variable tenant_id {} +variable rover_version {} +variable logged_user_objectId { + default = null +} +variable logged_aad_app_objectId { + default = null +} +variable tags { + type = map + default = {} +} + +variable enterprise_scale { + default = {} +} + +variable diagnostics_definition { + default = {} +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/azdo.tf b/landingzones/caf_launchpad/add-ons/azure_devops/azdo.tf new file mode 100644 index 00000000..0f12bccd --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/azdo.tf @@ -0,0 +1,15 @@ +# The PAT token must be provisioned in a different deployment +provider "azuredevops" { + org_service_url = var.azure_devops.url + personal_access_token = data.azurerm_key_vault_secret.pat.value +} + +data "azurerm_key_vault_secret" "pat" { + name = var.azure_devops.pats["admin"].secret_name + key_vault_id = local.remote.keyvaults[var.azure_devops.pats["admin"].lz_key][var.azure_devops.pats["admin"].keyvault_key].id + +} + +data "azuredevops_project" "project" { + project_name = var.azure_devops.project +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/azdo_agent_pools.tf b/landingzones/caf_launchpad/add-ons/azure_devops/azdo_agent_pools.tf new file mode 100644 index 00000000..7832ba6e --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/azdo_agent_pools.tf @@ -0,0 +1,52 @@ + +locals { + organization_agent_pools = try(var.azure_devops.organization_agent_pools, {}) + project_agent_pools = try(var.azure_devops.project_agent_pools, {}) +} + + +## Agent pools +## Those pools are created in the organization, not the project +resource "azuredevops_agent_pool" "pool" { + for_each = try(var.azure_devops.organization_agent_pools, {}) + + name = each.value.name + auto_provision = lookup(each.value, "auto_provision", false) +} + +# +# add the agent pools into the project +# + +data "azuredevops_agent_pool" "pool" { + depends_on = [azuredevops_agent_pool.pool] + for_each = try(var.azure_devops.project_agent_pools, {}) + + name = each.value.name +} + +resource "azuredevops_agent_queue" "agent_queue" { + for_each = data.azuredevops_agent_pool.pool + + project_id = data.azuredevops_project.project.id + agent_pool_id = each.value.id + + lifecycle { + ignore_changes = [ + agent_pool_id + ] + } +} + +# +# Grant acccess to queue to all pipelines in the project +# + +resource "azuredevops_resource_authorization" "queue" { + for_each = data.azuredevops_agent_pool.pool + + project_id = data.azuredevops_project.project.id + resource_id = azuredevops_agent_queue.agent_queue[each.key].id + type = "queue" + authorized = true +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/azdo_pipelines.tf b/landingzones/caf_launchpad/add-ons/azure_devops/azdo_pipelines.tf new file mode 100644 index 00000000..6fe4fdcb --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/azdo_pipelines.tf @@ -0,0 +1,43 @@ +data "azuredevops_git_repositories" "repos" { + project_id = data.azuredevops_project.project.id +} + + +locals { + repositories = zipmap(tolist(data.azuredevops_git_repositories.repos.repositories.*.name), tolist(data.azuredevops_git_repositories.repos.repositories)) +} + +resource "azuredevops_build_definition" "build_definition" { + + for_each = try(var.azure_devops.pipelines, {}) + project_id = data.azuredevops_project.project.id + name = each.value.name + path = each.value.folder + + variable_groups = lookup(each.value, "variable_group_keys", null) == null ? null : [ + for key in each.value.variable_group_keys : + azuredevops_variable_group.variable_group[key].id + ] + + repository { + repo_id = local.repositories[each.value.git_repo_name].id + repo_type = each.value.repo_type + yml_path = each.value.yaml + branch_name = lookup(each.value, "branch_name", null) + # service_connection_id = lookup(each.value, "repo_type", null) == "github" ? null : azuredevops_serviceendpoint_azurerm.github[each.value.service_connection_key].id + } + + ci_trigger { + use_yaml = true + } + + dynamic "variable" { + for_each = try(each.value.variables, {}) + + content { + name = variable.key + value = variable.value + } + } + +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/azdo_service_endpoint.tf b/landingzones/caf_launchpad/add-ons/azure_devops/azdo_service_endpoint.tf new file mode 100644 index 00000000..760919a2 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/azdo_service_endpoint.tf @@ -0,0 +1,36 @@ + +data "azurerm_key_vault_secret" "client_secret" { + depends_on = [module.caf] + for_each = try(var.azure_devops.service_endpoints, {}) + + name = format("%s-client-secret", local.combined.aad_apps[var.landingzone.key][each.value.aad_app_key].keyvaults[each.value.secret_keyvault_key].secret_name_client_secret) + key_vault_id = local.combined.aad_apps[var.landingzone.key][each.value.aad_app_key].keyvaults[each.value.secret_keyvault_key].id +} + +resource "azuredevops_serviceendpoint_azurerm" "azure" { + depends_on = [module.caf] + for_each = try(var.azure_devops.service_endpoints, {}) + + project_id = data.azuredevops_project.project.id + service_endpoint_name = each.value.endpoint_name + credentials { + serviceprincipalid = local.combined.aad_apps[var.landingzone.key][each.value.aad_app_key].azuread_application.application_id + serviceprincipalkey = data.azurerm_key_vault_secret.client_secret[each.key].value + } + azurerm_spn_tenantid = local.combined.aad_apps[var.landingzone.key][each.value.aad_app_key].tenant_id + azurerm_subscription_id = each.value.subscription_id + azurerm_subscription_name = each.value.subscription_name +} + +# +# Grant acccess to service endpoint to all pipelines in the project +# + +resource "azuredevops_resource_authorization" "endpoint" { + for_each = azuredevops_serviceendpoint_azurerm.azure + + project_id = data.azuredevops_project.project.id + resource_id = each.value.id + type = "endpoint" + authorized = true +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/azdo_variable_groups.tf b/landingzones/caf_launchpad/add-ons/azure_devops/azdo_variable_groups.tf new file mode 100644 index 00000000..7cd1ed1c --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/azdo_variable_groups.tf @@ -0,0 +1,39 @@ +# +# permissions required: +# - vso.variablegroups_manage (create) +# + vso.buid (update) +# + vso.build_execute (destroy) +# +resource "azuredevops_variable_group" "variable_group" { + for_each = try(var.azure_devops.variable_groups, {}) + + project_id = data.azuredevops_project.project.id + name = each.value.name + description = try(each.value.description, null) + allow_access = try(each.value.allow_access, false) + + dynamic "key_vault" { + for_each = lookup(each.value, "keyvault", null) == null ? [] : [1] + + content { + name = try(each.value.keyvault.lz_key, null) == null ? local.combined.keyvaults[var.landingzone.key][each.value.keyvault.keyvault_key].name : local.combined.keyvaults[each.value.keyvault.lz_key][each.value.keyvault.keyvault_key].name + service_endpoint_id = azuredevops_serviceendpoint_azurerm.azure[each.value.keyvault.serviceendpoint_key].id + } + } + + dynamic "variable" { + for_each = { + for key, variable in each.value.variables : key => { + name = key == "name" ? variable : key + value = key == "name" ? null : variable + } + } + + content { + # When used with Keyvault, the name must be the keyvault secret name and value must not be set + name = variable.value.name + value = variable.value.value + } + } + +} diff --git a/landingzones/launchpad/add-ons/azure_devops/backend.azurerm b/landingzones/caf_launchpad/add-ons/azure_devops/backend.azurerm similarity index 100% rename from landingzones/launchpad/add-ons/azure_devops/backend.azurerm rename to landingzones/caf_launchpad/add-ons/azure_devops/backend.azurerm diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/documentation/images/pat_token.png b/landingzones/caf_launchpad/add-ons/azure_devops/documentation/images/pat_token.png new file mode 100644 index 00000000..84fc549c Binary files /dev/null and b/landingzones/caf_launchpad/add-ons/azure_devops/documentation/images/pat_token.png differ diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/locals.remote_tfstates.tf b/landingzones/caf_launchpad/add-ons/azure_devops/locals.remote_tfstates.tf new file mode 100644 index 00000000..0cfe65a6 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/locals.remote_tfstates.tf @@ -0,0 +1,84 @@ +locals { + landingzone = { + current = { + storage_account_name = var.tfstate_storage_account_name + container_name = var.tfstate_container_name + resource_group_name = var.tfstate_resource_group_name + } + lower = { + storage_account_name = var.lower_storage_account_name + container_name = var.lower_container_name + resource_group_name = var.lower_resource_group_name + } + } +} + +data "terraform_remote_state" "remote" { + for_each = try(var.landingzone.tfstates, {}) + + backend = var.landingzone.backend_type + config = { + storage_account_name = local.landingzone[try(each.value.level, "current")].storage_account_name + container_name = local.landingzone[try(each.value.level, "current")].container_name + resource_group_name = local.landingzone[try(each.value.level, "current")].resource_group_name + key = each.value.tfstate + } +} + +locals { + landingzone_tag = { + "landingzone" = var.landingzone.key + } + + tags = merge(var.tags, local.landingzone_tag, { "level" = var.landingzone.level }, { "environment" = local.global_settings.environment }, { "rover_version" = var.rover_version }) + + global_settings = { + prefix = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings.prefix + prefix_with_hyphen = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings.prefix_with_hyphen + prefix_start_alpha = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings.prefix_start_alpha + default_region = try(var.global_settings.default_region, data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings.default_region) + environment = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings.environment + regions = try(var.global_settings.regions, data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings.regions) + passthrough = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings.passthrough + random_length = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings.random_length + } + + diagnostics = { + diagnostics_definition = merge(data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.diagnostics_definition, var.diagnostics_definition) + diagnostics_destinations = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.diagnostics_destinations + storage_accounts = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.storage_accounts + log_analytics = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.log_analytics + } + + + combined = { + aad_apps = merge(local.remote.aad_apps, map(var.landingzone.key, module.caf.aad_apps)) + azuread_groups = merge(local.remote.azuread_groups, map(var.landingzone.key, module.caf.azuread_groups)) + keyvaults = merge(local.remote.keyvaults, map(var.landingzone.key, module.caf.keyvaults)) + managed_identities = merge(local.remote.managed_identities, map(var.landingzone.key, module.caf.managed_identities)) + } + + remote = { + aad_apps = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.aad_apps[key], {})) + } + + azuread_groups = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.azuread_groups[key], {})) + } + + keyvaults = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.keyvaults[key], {})) + } + + managed_identities = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.managed_identities[key], {})) + } + + vnets = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.vnets[key], {})) + } + } + + +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/main.tf b/landingzones/caf_launchpad/add-ons/azure_devops/main.tf new file mode 100644 index 00000000..8ef2817b --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/main.tf @@ -0,0 +1,69 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 2.32.0" + } + azuread = { + source = "hashicorp/azuread" + version = "~> 1.0.0" + } + random = { + source = "hashicorp/random" + version = "~> 2.2.1" + } + null = { + source = "hashicorp/null" + version = "~> 2.1.0" + } + external = { + source = "hashicorp/external" + version = "~> 1.2.0" + } + azuredevops = { + source = "terraform-providers/azuredevops" + version = "~> 0.0.1" + } + tls = { + source = "hashicorp/tls" + version = "~> 2.2.0" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~>1.1.0" + } + } + required_version = ">= 0.13" +} + +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + } + } +} + +data "azurerm_client_config" "current" {} + + +locals { + + + tfstates = merge( + map(var.landingzone.backend_type, + map( + "storage_account_name", var.tfstate_storage_account_name, + "container_name", var.tfstate_container_name, + "resource_group_name", var.tfstate_resource_group_name, + "key", var.tfstate_key, + "level", var.landingzone.level, + "tenant_id", var.tenant_id, + "subscription_id", data.azurerm_client_config.current.subscription_id + ) + ) + , + data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.tfstates + ) + +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/output.tf b/landingzones/caf_launchpad/add-ons/azure_devops/output.tf new file mode 100644 index 00000000..c8ebf3f9 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/output.tf @@ -0,0 +1,6 @@ +output keyvaults { + value = map( + var.landingzone.key, module.caf.keyvaults + ) + sensitive = true +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/readme.md b/landingzones/caf_launchpad/add-ons/azure_devops/readme.md new file mode 100644 index 00000000..405ddcd4 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/readme.md @@ -0,0 +1,48 @@ +# Cloud Adoption Framework for Azure - Landing zones on Terraform - Azure Devops add-on + +The Azure Devops add-ons allow you to setup you Azure Devops environment as a platform to automate all your subsequent landing zone deployment from level 0 until level 4 through Azure pipelines with self hosted agents. + +* Azure Devops: + - Agent Pools (Organization and Project Level) + - Service Endpoint + - Variables and Variable Groups + - Pipelines + +* Azure (Connection with Azure Devops): + - Azure AD Application + - Custom Role + - Keyvault and access policies for Azure AD App + +Azure Devops add-on landing zone operates at **level 0** + +For a review of the hierarchy approach of Cloud Adoption Framework for Azure landing zones on Terraform, you can refer to [the following documentation](../../documentation/code_architecture/hierarchy.md). + +## Dependencies + +Landing zone: +* CAF Launchpad (Scenario 200 or above) + +Azure Devops (example): +* Organization: https://dev.azure.com/azure-terraform +* Project : contoso_demo (https://dev.azure.com/azure-terraform/contoso_demo) +* Repo : caf-configuration (https://dev.azure.com/azure-terraform/contoso_demo/_git/caf-configuration) + - In order for pipeline to work properly, YAML file should be in this repo and referred accordingly under pipeline section in azure_devops.tfvars + - sample yaml attached [here](./scenario/200-contoso_demo/pipeline/rover.yaml). + +Azure: +* PAT Token : PAT Token should be updated in keyvault secret that deployed by launchpad LZ as below + +![](./documentation/images/pat_token.png) + +## Deployment + +```bash +rover -lz /tf/caf/landingzones/caf_launchpad/add-ons/azure_devops \ + -tfstate azure_devops-contoso_demo.tfstate \ + -var-folder /tf/caf/landingzones/caf_launchpad/add-ons/azure_devops/scenario/200-contoso_demo \ + -parallelism 30 \ + -level level0 \ + -a apply -env sandpit +``` + +We are planning to release more examples on how to deploy the Azure Devops Agents. diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/scenario/200-contoso_demo/azure_devops.tfvars b/landingzones/caf_launchpad/add-ons/azure_devops/scenario/200-contoso_demo/azure_devops.tfvars new file mode 100644 index 00000000..bf0bd6c1 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/scenario/200-contoso_demo/azure_devops.tfvars @@ -0,0 +1,232 @@ + + +azure_devops = { + + url = "https://dev.azure.com/azure-terraform/" + project = "contoso_demo" + + # PAT Token should be updated manually to the keyvault after running launchpad + pats = { + admin = { + secret_name = "azdo-pat-admin" + lz_key = "launchpad" + keyvault_key = "secrets" + } + } + + organization_agent_pools = { + level0 = { + name = "caf-sandpit-level0" + auto_provision = false # When set to false the agent pool is not populated automatically into the devops projects (recommended) + } + level1 = { + name = "caf-sandpit-level1" + auto_provision = false + } + level2 = { + name = "caf-sandpit-level2" + auto_provision = false + } + level3 = { + name = "caf-sandpit-level3" + auto_provision = false + } + level4 = { + name = "caf-sandpit-level4" + auto_provision = false + } + } + + project_agent_pools = { + level0 = { + name = "caf-sandpit-level0" + } + level1 = { + name = "caf-sandpit-level1" + } + level2 = { + name = "caf-sandpit-level2" + } + level3 = { + name = "caf-sandpit-level3" + } + level4 = { + name = "caf-sandpit-level4" + } + } + + service_endpoints = { + contoso_demo = { + endpoint_name = "terraformdev (terraformdev.onmicrosoft.com) - contoso_demo" + subscription_name = "ase-landingzone" + subscription_id = "1d53e782-9f46-4720-b6b3-cff29106e9f6" + aad_app_key = "contoso_demo" + secret_keyvault_key = "devops" + } + } + + variable_groups = { + global = { + name = "release-global" # changing that name requires to change it in the devops agents yaml variables group + allow_access = true + variables = { + HOME_FOLDER_USER = "vsts_azpcontainer" + ROVER_IMAGE = "aztfmod/rover:2010.2808" + TF_CLI_ARGS = "'-no-color'" + TF_CLI_ARGS_init = "" + TF_CLI_ARGS_plan = "'-input=false'" + TF_VAR_ARGS_destroy = "'-auto-approve -refresh=false'" + ENVIRONMENT = "sandpit" + LANDINGZONE_BRANCH = "2010.0.0" + } + } + + level0 = { + name = "release-level0" + allow_access = true + variables = { + TF_VAR_pipeline_level = "level0" + ARM_USE_MSI = "true" + AGENT_POOL = "caf-sandpit-level0" + } + } + + level0_kv = { + name = "release-level0-msi" + allow_access = true + keyvault = { + lz_key = "launchpad" + keyvault_key = "level0" + serviceendpoint_key = "contoso_demo" + } + variables = { + name = "msi-resource-id" + } + } + + level1 = { + name = "release-level1" + allow_access = true + variables = { + TF_VAR_pipeline_level = "level1" + ARM_USE_MSI = "true" + AGENT_POOL = "caf-sandpit-level1" + } + } + + level1_kv = { + name = "release-level1-msi" + allow_access = true + keyvault = { + lz_key = "launchpad" + keyvault_key = "level1" + serviceendpoint_key = "contoso_demo" + } + variables = { + name = "msi-resource-id" + } + } + + level2 = { + name = "release-level2" + allow_access = true + variables = { + TF_VAR_pipeline_level = "level2" + ARM_USE_MSI = "true" + AGENT_POOL = "caf-sandpit-level2" + } + } + + level2_kv = { + name = "release-level2-msi" + allow_access = true + keyvault = { + lz_key = "launchpad" + keyvault_key = "level2" + serviceendpoint_key = "contoso_demo" + } + variables = { + name = "msi-resource-id" + } + } + + level3 = { + name = "release-level3" + allow_access = true + variables = { + TF_VAR_pipeline_level = "level3" + ARM_USE_MSI = "true" + AGENT_POOL = "caf-sandpit-level3" + } + } + + level3_kv = { + name = "release-level3-msi" + allow_access = true + keyvault = { + lz_key = "launchpad" + keyvault_key = "level3" + serviceendpoint_key = "contoso_demo" + } + variables = { + name = "msi-resource-id" + } + } + } + + pipelines = { + + # + # Agent pools + # + + devops_agent_level1_plan = { + name = "devops_agent_level1_plan" + folder = "\\configuration\\level1" + yaml = "configuration/pipeline/rover.yaml" + repo_type = "TfsGit" + git_repo_name = "caf-configuration" + variables = { + landingZoneName = "azdo-agent-level1", + terraformAction = "plan", + tfstateName = "azdo-agent-level1.tfstate" + configPath = "/configuration/level1/azuredevops/agent" + landingZonePath = "/public/landingzones/caf_launchpad/add-ons/azure_devops_agent" + level = "level1" + } + variable_group_keys = ["global", "level0", "level0_kv"] + } + devops_agent_level1_apply = { + name = "devops_agent_level1_apply" + folder = "\\configuration\\level1" + yaml = "configuration/pipeline/rover.yaml" + repo_type = "TfsGit" + git_repo_name = "caf-configuration" + variables = { + landingZoneName = "azdo-agent-level1", + terraformAction = "apply", + tfstateName = "azdo-agent-level1.tfstate" + configPath = "/configuration/level1/azuredevops/agent" + landingZonePath = "/public/landingzones/caf_launchpad/add-ons/azure_devops_agent" + level = "level1" + } + variable_group_keys = ["global", "level0", "level0_kv"] + } + devops_agent_level1_destroy = { + name = "devops_agent_level1_destroy" + folder = "\\configuration\\level1" + yaml = "configuration/pipeline/rover.yaml" + repo_type = "TfsGit" + git_repo_name = "caf-configuration" + variables = { + landingZoneName = "azdo-agent-level1", + terraformAction = "destroy", + tfstateName = "azdo-agent-level1.tfstate" + configPath = "/configuration/level1/azuredevops/agent" + landingZonePath = "/public/landingzones/caf_launchpad/add-ons/azure_devops_agent" + level = "level1" + } + variable_group_keys = ["global", "level0", "level0_kv"] + } + } +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/scenario/200-contoso_demo/configurations.tfvars b/landingzones/caf_launchpad/add-ons/azure_devops/scenario/200-contoso_demo/configurations.tfvars new file mode 100644 index 00000000..e4d8208f --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/scenario/200-contoso_demo/configurations.tfvars @@ -0,0 +1,123 @@ +landingzone = { + backend_type = "azurerm" + global_settings_key = "launchpad" + level = "level0" + key = "azdo-contoso_demo" + tfstates = { + launchpad = { + level = "current" + tfstate = "caf_launchpad.tfstate" + } + } +} + +resource_groups = { + rg1 = { + name = "devops-agents-security" + } +} + + +keyvaults = { + devops = { + name = "devops" + resource_group_key = "rg1" + sku_name = "standard" + + creation_policies = { + keyvault_level0_rw = { + # Reference a key to an azure ad group + lz_key = "launchpad" + azuread_group_key = "keyvault_level0_rw" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + } +} + +keyvault_access_policies_azuread_apps = { + level0 = { + contoso_demo = { + lz_key = "launchpad" + azuread_app_key = "contoso_demo" + secret_permissions = ["Get", "List"] + } + } + level1 = { + contoso_demo = { + lz_key = "launchpad" + azuread_app_key = "contoso_demo" + secret_permissions = ["Get", "List"] + } + } + level2 = { + contoso_demo = { + lz_key = "launchpad" + azuread_app_key = "contoso_demo" + secret_permissions = ["Get", "List"] + } + } + level3 = { + contoso_demo = { + lz_key = "launchpad" + azuread_app_key = "contoso_demo" + secret_permissions = ["Get", "List"] + } + } + level4 = { + contoso_demo = { + lz_key = "launchpad" + azuread_app_key = "contoso_demo" + secret_permissions = ["Get", "List"] + } + } +} + + +azuread_apps = { + + contoso_demo = { + useprefix = true + application_name = "caf-level4-contoso_demo" + password_expire_in_days = 60 + tenant_name = "terraformdev.onmicrosoft.com" + reply_urls = ["https://localhost"] + keyvaults = { + devops = { + secret_prefix = "aadapp-caf-level4-azdo-contoso_demo" + } + } + } + +} + +custom_role_definitions = { + + caf-azdo-to-azure-subscription = { + name = "caf-azure-devops-azure-app-service-improvement-program-TO-azure-subscription" + useprefix = true + description = "CAF Custom role for service principal in Azure Devops to access resources" + permissions = { + actions = [ + "Microsoft.Resources/subscriptions/read", + "Microsoft.KeyVault/vaults/read" + ] + } + } + +} + + +role_mapping = { + custom_role_mapping = { + subscriptions = { + logged_in_subscription = { + "caf-azdo-to-azure-subscription" = { + azuread_apps = { + keys = ["contoso_demo"] + } + } + } + } + } +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/scenario/200-contoso_demo/pipeline/rover.yaml b/landingzones/caf_launchpad/add-ons/azure_devops/scenario/200-contoso_demo/pipeline/rover.yaml new file mode 100644 index 00000000..ef3e3153 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/scenario/200-contoso_demo/pipeline/rover.yaml @@ -0,0 +1,71 @@ +parameters: + - name: timeoutInMinutes + displayName: 'Timeout in minutes' + type: number + default: 60 + + variables: + - group: release-global + + resources: + containers: + - container: rover + image: $(ROVER_IMAGE) + options: --user 0:0 -e TF_PLUGIN_CACHE_DIR="/home/$(HOME_FOLDER_USER)/plugin-cache" -e TF_DATA_DIR="/home/$(HOME_FOLDER_USER)" + + trigger: none + + jobs: + - job: CAF_Rover + + displayName: Azure Landing Zone + + pool: $(AGENT_POOL) + + continueOnError: false + + workspace: + clean: all + + container: rover + + timeoutInMinutes: ${{ parameters.timeoutInMinutes }} + + steps: + - checkout: self + + - bash: | + git clone --branch $(LANDINGZONE_BRANCH) https://github.com/Azure/caf-terraform-landingzones.git ${BUILD_REPOSITORY_LOCALPATH}/public 2>/dev/null + + az login --identity -u $(msi-resource-id) + + /tf/rover/rover.sh -lz ${BUILD_REPOSITORY_LOCALPATH}$(landingZonePath) \ + -tfstate $(tfstateName) \ + -var-folder ${BUILD_REPOSITORY_LOCALPATH}$(configPath) \ + -parallelism=30 \ + -level $(level) \ + -a $(terraformAction) \ + -env $(ENVIRONMENT) + + condition: ne(variables['terraformAction'], 'destroy') + failOnStderr: true + displayName: 'Terraform $(terraformAction)' + + - bash: | + git clone --branch $(LANDINGZONE_BRANCH) https://github.com/Azure/caf-terraform-landingzones.git ${BUILD_REPOSITORY_LOCALPATH}/public 2>/dev/null + + az login --identity -u $(msi-resource-id) + + /tf/rover/rover.sh -lz ${BUILD_REPOSITORY_LOCALPATH}$(landingZonePath) \ + -tfstate $(tfstateName) \ + -var-folder ${BUILD_REPOSITORY_LOCALPATH}$(configPath) \ + -parallelism=30 \ + -level $(level) \ + -a $(terraformAction) \ + -auto-approve \ + -env $(ENVIRONMENT) + + condition: eq(variables['terraformAction'], 'destroy') + failOnStderr: true + displayName: 'Terraform destroy' + \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/solution.tf b/landingzones/caf_launchpad/add-ons/azure_devops/solution.tf new file mode 100644 index 00000000..b0053938 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/solution.tf @@ -0,0 +1,36 @@ +module "caf" { + source = "aztfmod/caf/azurerm" + version = "~> 0.4" + + current_landingzone_key = var.landingzone.key + tenant_id = var.tenant_id + tfstates = local.tfstates + tags = local.tags + global_settings = local.global_settings + diagnostics = local.diagnostics + diagnostic_storage_accounts = var.diagnostic_storage_accounts + logged_user_objectId = var.logged_user_objectId + logged_aad_app_objectId = var.logged_aad_app_objectId + resource_groups = var.resource_groups + storage_accounts = var.storage_accounts + azuread_groups = var.azuread_groups + keyvaults = var.keyvaults + keyvault_access_policies = var.keyvault_access_policies + keyvault_access_policies_azuread_apps = var.keyvault_access_policies_azuread_apps + role_mapping = var.role_mapping + custom_role_definitions = var.custom_role_definitions + azuread_apps = var.azuread_apps + compute = { + virtual_machines = var.virtual_machines + } + storage = { + storage_account_blobs = var.storage_account_blobs + } + + remote_objects = { + keyvaults = local.remote.keyvaults + vnets = local.remote.vnets + managed_identities = local.remote.managed_identities + azuread_groups = local.remote.azuread_groups + } +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops/variables.tf b/landingzones/caf_launchpad/add-ons/azure_devops/variables.tf new file mode 100644 index 00000000..b7dcb314 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops/variables.tf @@ -0,0 +1,98 @@ +# Map of the remote data state for lower level +variable lower_storage_account_name {} +variable lower_container_name {} +variable lower_resource_group_name {} + +variable tfstate_storage_account_name {} +variable tfstate_container_name {} +variable tfstate_key {} +variable tfstate_resource_group_name {} + +variable global_settings { + default = {} +} +variable tenant_id {} +variable landingzone { +} +variable rover_version { + default = null +} + +variable logged_user_objectId { + default = null +} +variable logged_aad_app_objectId { + default = null +} +variable tags { + default = null +} +variable app_service_environments { + default = {} +} +variable app_service_plans { + default = {} +} +variable app_services { + default = {} +} +variable diagnostics_definition { + default = {} +} +variable resource_groups { + default = {} +} +variable network_security_group_definition { + default = {} +} +variable vnets { + default = {} +} +variable azurerm_redis_caches { + default = {} +} +variable mssql_servers { + default = {} +} +variable storage_accounts { + default = {} +} +variable storage_account_blobs { + default = {} +} +variable azuread_groups { + default = {} +} +variable keyvaults { + default = {} +} +variable keyvault_access_policies { + default = {} +} +variable keyvault_access_policies_azuread_apps { + default = {} +} +variable virtual_machines { + default = {} +} +variable diagnostic_storage_accounts { + default = {} +} +variable virtual_machine_extension_scripts { + default = {} +} +variable azure_devops { + default = {} +} +variable role_mapping { + default = {} +} +variable custom_role_definitions { + default = {} +} +variable azuread_apps { + default = {} +} +variable dynamic_keyvault_secrets { + default = {} +} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/backend.azurerm b/landingzones/caf_launchpad/add-ons/azure_devops_agent/backend.azurerm similarity index 100% rename from landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/backend.azurerm rename to landingzones/caf_launchpad/add-ons/azure_devops_agent/backend.azurerm diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/keyvault.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/keyvault.tf new file mode 100644 index 00000000..bd324dfc --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/keyvault.tf @@ -0,0 +1,23 @@ +module secret { + source = "./secret" + for_each = { + for key, value in var.settings : key => value + if try(value.value, null) == null + } + + name = each.value.secret_name + value = try(each.value.value, null) == null ? try(var.objects[each.value.output_key][each.value.resource_key][each.value.attribute_key], var.objects[each.value.output_key][each.value.attribute_key]) : each.value.value + keyvault_id = var.keyvault_id +} + +module secret_immutable { + source = "./secret_immutable" + for_each = { + for key, value in var.settings : key => value + if try(value.value, null) == "" + } + + name = each.value.secret_name + value = try(each.value.value, null) == null ? try(var.objects[each.value.output_key][each.value.resource_key][each.value.attribute_key], var.objects[each.value.output_key][each.value.attribute_key]) : each.value.value + keyvault_id = var.keyvault_id +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret/keyvault_secret.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret/keyvault_secret.tf new file mode 100644 index 00000000..0eca69eb --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret/keyvault_secret.tf @@ -0,0 +1,5 @@ +resource "azurerm_key_vault_secret" "secret" { + name = var.name + value = var.value + key_vault_id = var.keyvault_id +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret/variables.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret/variables.tf new file mode 100644 index 00000000..8b97a9f9 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret/variables.tf @@ -0,0 +1,3 @@ +variable name {} +variable value {} +variable keyvault_id {} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret_immutable/keyvault_secret.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret_immutable/keyvault_secret.tf new file mode 100644 index 00000000..98b32c97 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret_immutable/keyvault_secret.tf @@ -0,0 +1,12 @@ +resource "azurerm_key_vault_secret" "secret" { + count = var.value == "" ? 1 : 0 + name = var.name + value = var.value + key_vault_id = var.keyvault_id + + lifecycle { + ignore_changes = [ + value + ] + } +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret_immutable/variables.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret_immutable/variables.tf new file mode 100644 index 00000000..8b97a9f9 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/secret_immutable/variables.tf @@ -0,0 +1,3 @@ +variable name {} +variable value {} +variable keyvault_id {} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/variables.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/variables.tf new file mode 100644 index 00000000..543e89b4 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_keyvault_secrets/variables.tf @@ -0,0 +1,3 @@ +variable settings {} +variable objects {} +variable keyvault_id {} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_secrets.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_secrets.tf new file mode 100644 index 00000000..0f3a2a39 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/dynamic_secrets.tf @@ -0,0 +1,9 @@ + +module dynamic_keyvault_secrets { + source = "./dynamic_keyvault_secrets" + for_each = try(var.dynamic_keyvault_secrets, {}) + + settings = each.value + keyvault_id = module.caf.keyvaults[each.key].id + objects = module.caf +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/extensions/devops_selfhosted_agent.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/extensions/devops_selfhosted_agent.tf new file mode 100644 index 00000000..5372db55 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/extensions/devops_selfhosted_agent.tf @@ -0,0 +1,44 @@ + +resource "azurerm_virtual_machine_extension" "devops_selfhosted_agent" { + for_each = { + for key, value in var.extensions : key => value + if key == "devops_selfhosted_agent" + } + + name = "install_azure_devops_agent" + + virtual_machine_id = var.virtual_machine_id + publisher = "Microsoft.Azure.Extensions" + type = "CustomScript" + type_handler_version = "2.1" + + #timestamp: use this field only to trigger a re-run of the script by changing value of this field. + # Any integer value is acceptable; it must only be different than the previous value. + settings = jsonencode( + { + "timestamp" : each.value.version, + "fileUris" : concat(local.devops_selfhosted_agent.file_uris, local.devops_selfhosted_agent.storage_account_blobs_urls), + + } + ) + protected_settings = jsonencode( + { + "commandToExecute" : format("bash %s '%s' '%s' '%s' '%s' '%s' '%s' '%s'", var.extensions[each.key].agent_init_script, var.settings[each.key].azure_devops.url, var.settings[each.key].agent_pat, var.settings[each.key].azure_devops.agent_pool.name, var.settings[each.key].azure_devops.agent_pool.agent_name_prefix, var.settings[each.key].azure_devops.agent_pool.num_agents, var.settings[each.key].admin_username, var.settings[each.key].azure_devops.rover_version) + } + ) + +} + +locals { + devops_selfhosted_agent = { + file_uris = flatten( + [ + for file_uris_key, file in try(var.extensions.devops_selfhosted_agent.fileUris, {}) : [ + for file_uri_key in file.storage_blob_keys : var.settings.devops_selfhosted_agent.storage_accounts[file.storage_account_key].containers[file.container_key].blobs[file_uri_key].url + ] + ] + ) + + storage_account_blobs_urls = try(var.settings.devops_selfhosted_agent.storage_account_blobs_urls, []) + } +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/extensions/variables.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/extensions/variables.tf new file mode 100644 index 00000000..88453a14 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/extensions/variables.tf @@ -0,0 +1,3 @@ +variable virtual_machine_id {} +variable extensions {} +variable settings {} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/locals.current_tfstates.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/locals.current_tfstates.tf new file mode 100644 index 00000000..1d22c002 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/locals.current_tfstates.tf @@ -0,0 +1,73 @@ +locals { + landingzone = { + current = { + storage_account_name = var.tfstate_storage_account_name + container_name = var.tfstate_container_name + resource_group_name = var.tfstate_resource_group_name + } + lower = { + storage_account_name = var.lower_storage_account_name + container_name = var.lower_container_name + resource_group_name = var.lower_resource_group_name + } + } +} + +data "terraform_remote_state" "remote" { + for_each = try(var.landingzone.tfstates, {}) + + backend = var.landingzone.backend_type + config = { + storage_account_name = local.landingzone[try(each.value.level, "current")].storage_account_name + container_name = local.landingzone[try(each.value.level, "current")].container_name + resource_group_name = local.landingzone[try(each.value.level, "current")].resource_group_name + key = each.value.tfstate + } +} + +locals { + landingzone_tag = { + "landingzone" = var.landingzone.key + } + + tags = merge(var.tags, local.landingzone_tag, { "level" = var.landingzone.level }, { "environment" = local.global_settings.environment }, { "rover_version" = var.rover_version }) + + global_settings = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings + + diagnostics = { + diagnostics_definition = merge(data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.diagnostics_definition, var.diagnostics_definition) + diagnostics_destinations = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.diagnostics_destinations + storage_accounts = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.storage_accounts + log_analytics = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.log_analytics + } + + + combined = { + aad_apps = merge(local.remote.aad_apps, map(var.landingzone.key, module.caf.aad_apps)) + azuread_groups = merge(local.remote.azuread_groups, map(var.landingzone.key, module.caf.azuread_groups)) + keyvaults = merge(local.remote.keyvaults, map(var.landingzone.key, module.caf.keyvaults)) + managed_identities = merge(local.remote.managed_identities, map(var.landingzone.key, module.caf.managed_identities)) + } + + remote = { + aad_apps = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.aad_apps[key], {})) + } + + azuread_groups = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.azuread_groups[key], {})) + } + + keyvaults = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.keyvaults[key], {})) + } + + managed_identities = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.managed_identities[key], {})) + } + + vnets = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.vnets[key], {})) + } + } +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/main.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/main.tf new file mode 100644 index 00000000..b9972c50 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/main.tf @@ -0,0 +1,69 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 2.32.0" + } + azuread = { + source = "hashicorp/azuread" + version = "~> 1.0.0" + } + random = { + source = "hashicorp/random" + version = "~> 2.2.1" + } + null = { + source = "hashicorp/null" + version = "~> 2.1.0" + } + external = { + source = "hashicorp/external" + version = "~> 1.2.0" + } + azuredevops = { + source = "terraform-providers/azuredevops" + version = "~> 0.0.1" + } + tls = { + source = "hashicorp/tls" + version = "~> 2.2.0" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~>1.1.0" + } + } + required_version = ">= 0.13" +} + +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + } + } +} + +data "azurerm_client_config" "current" {} + + +locals { + + + tfstates = merge( + map(var.landingzone.key, + map( + "storage_account_name", var.tfstate_storage_account_name, + "container_name", var.tfstate_container_name, + "resource_group_name", var.tfstate_resource_group_name, + "key", var.tfstate_key, + "level", var.landingzone.level, + "tenant_id", var.tenant_id, + "subscription_id", data.azurerm_client_config.current.subscription_id + ) + ) + , + data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.tfstates + ) + +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/output.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/output.tf new file mode 100644 index 00000000..816e2458 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/output.tf @@ -0,0 +1,34 @@ +output managed_identities { + value = local.combined.managed_identities + sensitive = false +} + +output azuread_groups { + value = local.combined.azuread_groups + sensitive = true +} + +output keyvaults { + value = local.combined.keyvaults + sensitive = false +} + +output vnets { + value = local.remote.vnets + sensitive = false +} + +output global_settings { + value = local.global_settings + sensitive = true +} + +output diagnostics { + value = local.diagnostics + sensitive = true +} + +output tfstates { + value = local.tfstates + sensitive = true +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/readme.md b/landingzones/caf_launchpad/add-ons/azure_devops_agent/readme.md new file mode 100644 index 00000000..4309d4e0 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/readme.md @@ -0,0 +1,42 @@ +# Cloud Adoption Framework for Azure - Landing zones on Terraform - Azure Devops Agent add-on + +The Azure Devops Agent add-ons is the continuation of Self Hosted Agent implementation for Azure Devops environment that deployed in Azure Devops add on LZ. This will set up the underlying resources required for Agent in Azure. + +* Azure Virtual Machine to host the Agent +* Azure VM Extension to connect the VM to Azure Devops self hosted agent +* Storage account to put the script for VM Extension +* Key Vault to store the SSH key of the VM + +Azure Devops (Self Hosted Agent) add-on landing zone operates base on agent level for example for agent level0 will operates at **level 0** and agent level1 will operates at **level 1** + +For a review of the hierarchy approach of Cloud Adoption Framework for Azure landing zones on Terraform, you can refer to [the following documentation](../../documentation/code_architecture/hierarchy.md). + +## Dependencies + +Landing zone: +* CAF Launchpad +* Azure DevOps add on (example: scenario 200-contoso_demo) + +## Deployment + +### Deploy the Azure Devops agent for level0 +```bash +rover -lz /tf/caf/landingzones/caf_launchpad/add-ons/azure_devops_agent \ + -tfstate level0_azure_devops_agents.tfstate \ + -var-folder /tf/caf/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0 \ + -parallelism 30 \ + -level level0 \ + -env sandpit \ + -a apply +``` + +### Deploy the Azure Devops agent for level1 +```bash +rover -lz /tf/caf/landingzones/caf_launchpad/add-ons/azure_devops_agent \ + -tfstate azdo-agent-level1.tfstate \ + -var-folder /tf/caf/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1 \ + -parallelism 30 \ + -level level1 \ + -env sandpit \ + -a apply +``` \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/configuration.tfvars b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/configuration.tfvars new file mode 100644 index 00000000..0141decf --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/configuration.tfvars @@ -0,0 +1,64 @@ +landingzone = { + backend_type = "azurerm" + global_settings_key = "launchpad" + level = "level0" + key = "azdo-agent-level0" + tfstates = { + launchpad = { + level = "current" + tfstate = "caf_launchpad.tfstate" + } + azdo-contoso_demo = { + level = "current" + tfstate = "azure_devops-contoso_demo" + } + } +} + +resource_groups = { + rg1 = { + name = "devops-agents-level0" + } +} + +azure_devops = { + + # Rover version to apply to the devops self-hosted agents during the setup. + rover_version = "aztfmod/rover:2010.2808" + url = "https://dev.azure.com/azure-terraform/" + + pats = { + agent = { + secret_name = "azdo-pat-agent" + keyvault_key = "secrets" + lz_key = "launchpad" + } + } + + agent_pool = { + name = "caf-sandpit-level0" + auto_provision = true + num_agents = 4 + agent_name_prefix = "agent" + } + +} + +role_mapping = { + built_in_role_mapping = { + storage_accounts = { + scripts_region1 = { + "Storage Blob Data Contributor" = { + azuread_groups = { + lz_key = "launchpad" + keys = ["keyvault_level0_rw"] + } + managed_identities = { + lz_key = "launchpad" + keys = ["level0"] + } + } + } + } + } +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/keyvaults.tfvars b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/keyvaults.tfvars new file mode 100644 index 00000000..35f188ba --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/keyvaults.tfvars @@ -0,0 +1,28 @@ + +keyvaults = { + ssh = { + name = "sshl0" + resource_group_key = "rg1" + sku_name = "premium" + soft_delete_enabled = true + + creation_policies = { + keyvault_level0_rw = { + # Reference a key to an azure ad group + lz_key = "launchpad" + azuread_group_key = "keyvault_level0_rw" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "default_all" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + } + +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/storage_accounts.tfvars b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/storage_accounts.tfvars new file mode 100644 index 00000000..c19457ce --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/storage_accounts.tfvars @@ -0,0 +1,42 @@ + +storage_accounts = { + # Is used to store the azure devops deployment script to setup the Azure Devops Selfhosted agents + scripts_region1 = { + name = "scriptsl0" + resource_group_key = "rg1" + account_kind = "StorageV2" + account_tier = "Standard" + account_replication_type = "LRS" + allow_blob_public_access = true + + containers = { + scripts = { + name = "deployment-scripts" + container_access_type = "blob" + } + } + } +} + +# Attributes available https://www.terraform.io/docs/providers/azurerm/r/storage_blob.html +storage_account_blobs = { + devops_runtime_baremetal = { + storage_account_key = "scripts_region1" + storage_container_name = "deployment-scripts" + name = "devops_runtime_baremetal.sh" + source = "scripts/devops_runtime_baremetal.sh" + } +} + +diagnostic_storage_accounts = { + # Stores boot diagnostic for region1 + bootdiag_region1 = { + name = "bootl4" + resource_group_key = "rg1" + account_kind = "StorageV2" + account_tier = "Standard" + account_replication_type = "LRS" + access_tier = "Cool" + } +} + diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/virtual_machines.tfvars b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/virtual_machines.tfvars new file mode 100644 index 00000000..3140b94e --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level0/virtual_machines.tfvars @@ -0,0 +1,79 @@ + +# Virtual machines +virtual_machines = { + + # Configuration to deploy a bastion host linux virtual machine + level0 = { + resource_group_key = "rg1" + provision_vm_agent = true + boot_diagnostics_storage_account_key = "bootdiag_region1" + + os_type = "linux" + + keyvault_key = "ssh" + + # Define the number of networking cards to attach the virtual machine + networking_interfaces = { + nic0 = { + # Value of the keys from networking.tfvars + lz_key = "launchpad" + vnet_key = "devops_region1" + subnet_key = "release_agent_level0" + name = "0-release-agent-level0" + enable_ip_forwarding = false + internal_dns_name_label = "release-agent-level0" + } + } + + virtual_machine_settings = { + linux = { + name = "release-agent-level0" + size = "Standard_F2s_v2" + admin_username = "adminuser" + disable_password_authentication = true + + # Value of the nic keys to attach the VM. The first one in the list is the default nic + network_interface_keys = ["nic0"] + + os_disk = { + name = "release-agent-level0-os" + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference = { + publisher = "canonical" + offer = "0001-com-ubuntu-server-focal" + sku = "20_04-lts" + version = "latest" + } + + identity = { + type = "UserAssigned" + + remote = { + launchpad = { + managed_identity_keys = [ + "level0", + ] + } + } + } + + + } + } + + virtual_machine_extensions = { + devops_selfhosted_agent = { + version = 1 + virtual_machine_key = "vm_devops_level0" + agent_init_script = "devops_runtime_baremetal.sh" + storage_account_blobs = [ + "devops_runtime_baremetal" + ] + } + } + + } +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/configuration.tfvars b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/configuration.tfvars new file mode 100644 index 00000000..7197d9c7 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/configuration.tfvars @@ -0,0 +1,68 @@ +landingzone = { + backend_type = "azurerm" + global_settings_key = "azdo-agent-level0" + level = "level1" + key = "azdo-agent-level1" + tfstates = { + azdo-agent-level0 = { + level = "lower" + tfstate = "level0_azure_devops_agents.tfstate" + } + launchpad = { + level = "lower" + tfstate = "caf_launchpad.tfstate" + } + azdo-contoso_demo = { + level = "lower" + tfstate = "azure_devops-contoso_demo" + } + } +} + +resource_groups = { + rg1 = { + name = "devops-agents-level0" + } +} + +azure_devops = { + + # Rover version to apply to the devops self-hosted agents during the setup. + rover_version = "aztfmod/rover:2010.2808" + url = "https://dev.azure.com/azure-terraform/" + + pats = { + agent = { + secret_name = "azdo-pat-agent" + keyvault_key = "secrets" + lz_key = "launchpad" + } + } + + agent_pool = { + name = "caf-sandpit-level1" + auto_provision = true + num_agents = 4 + agent_name_prefix = "agent" + } + +} + +role_mapping = { + built_in_role_mapping = { + storage_accounts = { + scripts_region1 = { + "Storage Blob Data Contributor" = { + azuread_groups = { + lz_key = "launchpad" + keys = ["keyvault_level0_rw"] + } + managed_identities = { + lz_key = "launchpad" + keys = ["level0", "level1"] + } + } + } + } + } +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/keyvaults.tfvars b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/keyvaults.tfvars new file mode 100644 index 00000000..f2588150 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/keyvaults.tfvars @@ -0,0 +1,32 @@ + +keyvaults = { + ssh = { + name = "sshl1" + resource_group_key = "rg1" + sku_name = "premium" + soft_delete_enabled = true + + creation_policies = { + keyvault_level0_rw = { + # Reference a key to an azure ad group + lz_key = "launchpad" + azuread_group_key = "keyvault_level0_rw" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + msi_level0 = { + lz_key = "launchpad" + managed_identity_key = "level0" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "default_all" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + } +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/storage_accounts.tfvars b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/storage_accounts.tfvars new file mode 100644 index 00000000..d053ed36 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/storage_accounts.tfvars @@ -0,0 +1,42 @@ + +storage_accounts = { + # Is used to store the azure devops deployment script to setup the Azure Devops Selfhosted agents + scripts_region1 = { + name = "scriptsl1" + resource_group_key = "rg1" + account_kind = "StorageV2" + account_tier = "Standard" + account_replication_type = "LRS" + allow_blob_public_access = true + + containers = { + scripts = { + name = "deployment-scripts" + container_access_type = "blob" + } + } + } +} + +# Attributes available https://www.terraform.io/docs/providers/azurerm/r/storage_blob.html +storage_account_blobs = { + devops_runtime_baremetal = { + storage_account_key = "scripts_region1" + storage_container_name = "deployment-scripts" + name = "devops_runtime_baremetal.sh" + source = "scripts/devops_runtime_baremetal.sh" + } +} + +diagnostic_storage_accounts = { + # Stores boot diagnostic for region1 + bootdiag_region1 = { + name = "bootl1" + resource_group_key = "rg1" + account_kind = "StorageV2" + account_tier = "Standard" + account_replication_type = "LRS" + access_tier = "Cool" + } +} + diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/virtual_machines.tfvars b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/virtual_machines.tfvars new file mode 100644 index 00000000..41a40da8 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scenario/200-contoso_demo/level1/virtual_machines.tfvars @@ -0,0 +1,77 @@ + +# Virtual machines +virtual_machines = { + + # Configuration to deploy a bastion host linux virtual machine + level1 = { + resource_group_key = "rg1" + provision_vm_agent = true + boot_diagnostics_storage_account_key = "bootdiag_region1" + + os_type = "linux" + + keyvault_key = "ssh" + + # Define the number of networking cards to attach the virtual machine + networking_interfaces = { + nic0 = { + # Value of the keys from networking.tfvars + lz_key = "launchpad" + vnet_key = "devops_region1" + subnet_key = "release_agent_level1" + name = "0-release-agent-level1" + enable_ip_forwarding = false + internal_dns_name_label = "release-agent-level1" + } + } + + virtual_machine_settings = { + linux = { + name = "release-agent-level1" + size = "Standard_F2s_v2" + admin_username = "adminuser" + disable_password_authentication = true + + # Value of the nic keys to attach the VM. The first one in the list is the default nic + network_interface_keys = ["nic0"] + + os_disk = { + name = "release-agent-level1-os" + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference = { + publisher = "canonical" + offer = "0001-com-ubuntu-server-focal" + sku = "20_04-lts" + version = "latest" + } + + identity = { + type = "UserAssigned" + + remote = { + lz_key = "launchpad" + managed_identity_keys = [ + "level1", + ] + } + } + + + } + } + + virtual_machine_extensions = { + devops_selfhosted_agent = { + version = 1 + agent_init_script = "devops_runtime_baremetal.sh" + storage_account_blobs = [ + "devops_runtime_baremetal" + ] + } + } + + } +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/scripts/cloud-init-install-rover-tools.config b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scripts/cloud-init-install-rover-tools.config new file mode 100644 index 00000000..5bed7c47 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scripts/cloud-init-install-rover-tools.config @@ -0,0 +1,117 @@ +#cloud-config +apt: + preserve_sources_list: true + sources: + azure-cli.list: + source: "deb https://packages.microsoft.com/repos/azure-cli/ bionic main" + key: | + -----BEGIN PGP PUBLIC KEY BLOCK----- + Version: GnuPG v1.4.7 (GNU/Linux) + + mQENBFYxWIwBCADAKoZhZlJxGNGWzqV+1OG1xiQeoowKhssGAKvd+buXCGISZJwT + LXZqIcIiLP7pqdcZWtE9bSc7yBY2MalDp9Liu0KekywQ6VVX1T72NPf5Ev6x6DLV + 7aVWsCzUAF+eb7DC9fPuFLEdxmOEYoPjzrQ7cCnSV4JQxAqhU4T6OjbvRazGl3ag + OeizPXmRljMtUUttHQZnRhtlzkmwIrUivbfFPD+fEoHJ1+uIdfOzZX8/oKHKLe2j + H632kvsNzJFlROVvGLYAk2WRcLu+RjjggixhwiB+Mu/A8Tf4V6b+YppS44q8EvVr + M+QvY7LNSOffSO6Slsy9oisGTdfE39nC7pVRABEBAAG0N01pY3Jvc29mdCAoUmVs + ZWFzZSBzaWduaW5nKSA8Z3Bnc2VjdXJpdHlAbWljcm9zb2Z0LmNvbT6JATUEEwEC + AB8FAlYxWIwCGwMGCwkIBwMCBBUCCAMDFgIBAh4BAheAAAoJEOs+lK2+EinPGpsH + /32vKy29Hg51H9dfFJMx0/a/F+5vKeCeVqimvyTM04C+XENNuSbYZ3eRPHGHFLqe + MNGxsfb7C7ZxEeW7J/vSzRgHxm7ZvESisUYRFq2sgkJ+HFERNrqfci45bdhmrUsy + 7SWw9ybxdFOkuQoyKD3tBmiGfONQMlBaOMWdAsic965rvJsd5zYaZZFI1UwTkFXV + KJt3bp3Ngn1vEYXwijGTa+FXz6GLHueJwF0I7ug34DgUkAFvAs8Hacr2DRYxL5RJ + XdNgj4Jd2/g6T9InmWT0hASljur+dJnzNiNCkbn9KbX7J/qK1IbR8y560yRmFsU+ + NdCFTW7wY0Fb1fWJ+/KTsC4= + =J6gs + -----END PGP PUBLIC KEY BLOCK----- + docker.list: + source: "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" + key: | + -----BEGIN PGP PUBLIC KEY BLOCK----- + + mQINBFit2ioBEADhWpZ8/wvZ6hUTiXOwQHXMAlaFHcPH9hAtr4F1y2+OYdbtMuth + lqqwp028AqyY+PRfVMtSYMbjuQuu5byyKR01BbqYhuS3jtqQmljZ/bJvXqnmiVXh + 38UuLa+z077PxyxQhu5BbqntTPQMfiyqEiU+BKbq2WmANUKQf+1AmZY/IruOXbnq + L4C1+gJ8vfmXQt99npCaxEjaNRVYfOS8QcixNzHUYnb6emjlANyEVlZzeqo7XKl7 + UrwV5inawTSzWNvtjEjj4nJL8NsLwscpLPQUhTQ+7BbQXAwAmeHCUTQIvvWXqw0N + cmhh4HgeQscQHYgOJjjDVfoY5MucvglbIgCqfzAHW9jxmRL4qbMZj+b1XoePEtht + ku4bIQN1X5P07fNWzlgaRL5Z4POXDDZTlIQ/El58j9kp4bnWRCJW0lya+f8ocodo + vZZ+Doi+fy4D5ZGrL4XEcIQP/Lv5uFyf+kQtl/94VFYVJOleAv8W92KdgDkhTcTD + G7c0tIkVEKNUq48b3aQ64NOZQW7fVjfoKwEZdOqPE72Pa45jrZzvUFxSpdiNk2tZ + XYukHjlxxEgBdC/J3cMMNRE1F4NCA3ApfV1Y7/hTeOnmDuDYwr9/obA8t016Yljj + q5rdkywPf4JF8mXUW5eCN1vAFHxeg9ZWemhBtQmGxXnw9M+z6hWwc6ahmwARAQAB + tCtEb2NrZXIgUmVsZWFzZSAoQ0UgZGViKSA8ZG9ja2VyQGRvY2tlci5jb20+iQI3 + BBMBCgAhBQJYrefAAhsvBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEI2BgDwO + v82IsskP/iQZo68flDQmNvn8X5XTd6RRaUH33kXYXquT6NkHJciS7E2gTJmqvMqd + tI4mNYHCSEYxI5qrcYV5YqX9P6+Ko+vozo4nseUQLPH/ATQ4qL0Zok+1jkag3Lgk + jonyUf9bwtWxFp05HC3GMHPhhcUSexCxQLQvnFWXD2sWLKivHp2fT8QbRGeZ+d3m + 6fqcd5Fu7pxsqm0EUDK5NL+nPIgYhN+auTrhgzhK1CShfGccM/wfRlei9Utz6p9P + XRKIlWnXtT4qNGZNTN0tR+NLG/6Bqd8OYBaFAUcue/w1VW6JQ2VGYZHnZu9S8LMc + FYBa5Ig9PxwGQOgq6RDKDbV+PqTQT5EFMeR1mrjckk4DQJjbxeMZbiNMG5kGECA8 + g383P3elhn03WGbEEa4MNc3Z4+7c236QI3xWJfNPdUbXRaAwhy/6rTSFbzwKB0Jm + ebwzQfwjQY6f55MiI/RqDCyuPj3r3jyVRkK86pQKBAJwFHyqj9KaKXMZjfVnowLh + 9svIGfNbGHpucATqREvUHuQbNnqkCx8VVhtYkhDb9fEP2xBu5VvHbR+3nfVhMut5 + G34Ct5RS7Jt6LIfFdtcn8CaSas/l1HbiGeRgc70X/9aYx/V/CEJv0lIe8gP6uDoW + FPIZ7d6vH+Vro6xuWEGiuMaiznap2KhZmpkgfupyFmplh0s6knymuQINBFit2ioB + EADneL9S9m4vhU3blaRjVUUyJ7b/qTjcSylvCH5XUE6R2k+ckEZjfAMZPLpO+/tF + M2JIJMD4SifKuS3xck9KtZGCufGmcwiLQRzeHF7vJUKrLD5RTkNi23ydvWZgPjtx + Q+DTT1Zcn7BrQFY6FgnRoUVIxwtdw1bMY/89rsFgS5wwuMESd3Q2RYgb7EOFOpnu + w6da7WakWf4IhnF5nsNYGDVaIHzpiqCl+uTbf1epCjrOlIzkZ3Z3Yk5CM/TiFzPk + z2lLz89cpD8U+NtCsfagWWfjd2U3jDapgH+7nQnCEWpROtzaKHG6lA3pXdix5zG8 + eRc6/0IbUSWvfjKxLLPfNeCS2pCL3IeEI5nothEEYdQH6szpLog79xB9dVnJyKJb + VfxXnseoYqVrRz2VVbUI5Blwm6B40E3eGVfUQWiux54DspyVMMk41Mx7QJ3iynIa + 1N4ZAqVMAEruyXTRTxc9XW0tYhDMA/1GYvz0EmFpm8LzTHA6sFVtPm/ZlNCX6P1X + zJwrv7DSQKD6GGlBQUX+OeEJ8tTkkf8QTJSPUdh8P8YxDFS5EOGAvhhpMBYD42kQ + pqXjEC+XcycTvGI7impgv9PDY1RCC1zkBjKPa120rNhv/hkVk/YhuGoajoHyy4h7 + ZQopdcMtpN2dgmhEegny9JCSwxfQmQ0zK0g7m6SHiKMwjwARAQABiQQ+BBgBCAAJ + BQJYrdoqAhsCAikJEI2BgDwOv82IwV0gBBkBCAAGBQJYrdoqAAoJEH6gqcPyc/zY + 1WAP/2wJ+R0gE6qsce3rjaIz58PJmc8goKrir5hnElWhPgbq7cYIsW5qiFyLhkdp + YcMmhD9mRiPpQn6Ya2w3e3B8zfIVKipbMBnke/ytZ9M7qHmDCcjoiSmwEXN3wKYI + mD9VHONsl/CG1rU9Isw1jtB5g1YxuBA7M/m36XN6x2u+NtNMDB9P56yc4gfsZVES + KA9v+yY2/l45L8d/WUkUi0YXomn6hyBGI7JrBLq0CX37GEYP6O9rrKipfz73XfO7 + JIGzOKZlljb/D9RX/g7nRbCn+3EtH7xnk+TK/50euEKw8SMUg147sJTcpQmv6UzZ + cM4JgL0HbHVCojV4C/plELwMddALOFeYQzTif6sMRPf+3DSj8frbInjChC3yOLy0 + 6br92KFom17EIj2CAcoeq7UPhi2oouYBwPxh5ytdehJkoo+sN7RIWua6P2WSmon5 + U888cSylXC0+ADFdgLX9K2zrDVYUG1vo8CX0vzxFBaHwN6Px26fhIT1/hYUHQR1z + VfNDcyQmXqkOnZvvoMfz/Q0s9BhFJ/zU6AgQbIZE/hm1spsfgvtsD1frZfygXJ9f + irP+MSAI80xHSf91qSRZOj4Pl3ZJNbq4yYxv0b1pkMqeGdjdCYhLU+LZ4wbQmpCk + SVe2prlLureigXtmZfkqevRz7FrIZiu9ky8wnCAPwC7/zmS18rgP/17bOtL4/iIz + QhxAAoAMWVrGyJivSkjhSGx1uCojsWfsTAm11P7jsruIL61ZzMUVE2aM3Pmj5G+W + 9AcZ58Em+1WsVnAXdUR//bMmhyr8wL/G1YO1V3JEJTRdxsSxdYa4deGBBY/Adpsw + 24jxhOJR+lsJpqIUeb999+R8euDhRHG9eFO7DRu6weatUJ6suupoDTRWtr/4yGqe + dKxV3qQhNLSnaAzqW/1nA3iUB4k7kCaKZxhdhDbClf9P37qaRW467BLCVO/coL3y + Vm50dwdrNtKpMBh3ZpbB1uJvgi9mXtyBOMJ3v8RZeDzFiG8HdCtg9RvIt/AIFoHR + H3S+U79NT6i0KPzLImDfs8T7RlpyuMc4Ufs8ggyg9v3Ae6cN3eQyxcK3w0cbBwsh + /nQNfsA6uu+9H7NhbehBMhYnpNZyrHzCmzyXkauwRAqoCbGCNykTRwsur9gS41TQ + M8ssD1jFheOJf3hODnkKU+HKjvMROl1DK7zdmLdNzA1cvtZH/nCC9KPj1z8QC47S + xx+dTZSx4ONAhwbS/LN3PoKtn8LPjY9NP9uDWI+TWYquS2U+KHDrBDlsgozDbs/O + jCxcpDzNmXpWQHEtHU7649OXHP7UeNST1mCUCH5qdank0V1iejF6/CfTFU4MfcrG + YT90qFF93M3v01BbxP+EIY2/9tiIPbrd + =0YYh + -----END PGP PUBLIC KEY BLOCK----- +package_update: true + +packages: + - docker-ce + - azure-cli + - ca-certificates + - curl + - apt-transport-https + - lsb-release + - jq + +snap: + commands: + - snap install kubectl --classic + +apt_upgrade: true + + # Install docker-compose +runcmd: + - [ sh, -c, 'curl -L https://github.com/docker/compose/releases/download/$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep "tag_name" | cut -d \" -f4)/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose' ] + - [ sh, -c, 'sudo chmod +x /usr/local/bin/docker-compose' ] + +# Add default auto created user to docker group +system_info: + default_user: + groups: [docker] \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/scripts/devops_runtime_baremetal.sh b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scripts/devops_runtime_baremetal.sh similarity index 64% rename from landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/scripts/devops_runtime_baremetal.sh rename to landingzones/caf_launchpad/add-ons/azure_devops_agent/scripts/devops_runtime_baremetal.sh index 061d2f93..0300c854 100644 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/scripts/devops_runtime_baremetal.sh +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scripts/devops_runtime_baremetal.sh @@ -8,9 +8,35 @@ num_agent=${5} admin_user=${6} rover_version="${7}" +error() { + local parent_lineno="$1" + local message="$2" + local code="${3:-1}" + if [[ -n "$message" ]] ; then + >&2 echo -e "\e[41mError on or near line ${parent_lineno}: ${message}; exiting with status ${code}\e[0m" + else + >&2 echo -e "\e[41mError on or near line ${parent_lineno}; exiting with status ${code}\e[0m" + fi + echo "" + exit "${code}" +} + +function cleanup { + echo "calling cleanup" + + echo "stopping the service" + sudo ./svc.sh stop || true + echo "uninstall the service" + sudo ./svc.sh uninstall || true + echo "un-register from AZDO" + sudo -u ${admin_user} ./config.sh remove --unattended --auth pat --token ${pat_token} || true +} + +set -ETe +trap 'error ${LINENO}' ERR 1 2 3 6 #strict mode, fail on error -set -euo pipefail +# set -euo pipefail echo "start" @@ -26,7 +52,8 @@ apt-get install -y --no-install-recommends \ ca-certificates \ jq \ apt-transport-https \ - docker.io + docker.io \ + sudo echo "Allowing agent to run docker" @@ -38,7 +65,7 @@ docker --version # Pull rover base image echo "Rover docker image ${rover_version}" -docker pull "${rover_version}" +docker pull "${rover_version}" 2>/dev/null echo "Installing Azure CLI" @@ -52,22 +79,24 @@ cd agent AGENTRELEASE="$(curl -s https://api.github.com/repos/Microsoft/azure-pipelines-agent/releases/latest | grep -oP '"tag_name": "v\K(.*)(?=")')" AGENTURL="https://vstsagentpackage.azureedge.net/agent/${AGENTRELEASE}/vsts-agent-linux-x64-${AGENTRELEASE}.tar.gz" -echo "Release "${AGENTRELEASE}" appears to be latest" +echo "Release "${AGENTRELEASE}" appears to be latest" echo "Downloading..." -wget -O agent_package.tar.gz ${AGENTURL} - -az login --identity +curl -s ${AGENTURL} -o agent_package.tar.gz for agent_num in $(seq 1 ${num_agent}); do agent_dir="agent-$agent_num" mkdir -p "$agent_dir" cd "$agent_dir" - name="${agent_prefix}-${agent_num}" + echo "moving to $agent_dir" + + cleanup + + name="${agent_prefix}-${agent_num}" echo "installing agent $name" tar zxvf ../agent_package.tar.gz chmod -R 777 . echo "extracted" - ./bin/installdependencies.sh + ./bin/installdependencies.sh || true echo "dependencies installed" sudo -u ${admin_user} ./config.sh --unattended --url "${url}" --auth pat --token "${pat_token}" --pool "${agent_pool}" --agent "${name}" --acceptTeeEula --replace --work ./_work --runAsService echo "configuration done" @@ -78,4 +107,3 @@ for agent_num in $(seq 1 ${num_agent}); do echo "config done" cd .. done - diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/scripts/devops_runtime_docker.sh b/landingzones/caf_launchpad/add-ons/azure_devops_agent/scripts/devops_runtime_docker.sh similarity index 100% rename from landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/scripts/devops_runtime_docker.sh rename to landingzones/caf_launchpad/add-ons/azure_devops_agent/scripts/devops_runtime_docker.sh diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/solution.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/solution.tf new file mode 100644 index 00000000..a95214ad --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/solution.tf @@ -0,0 +1,37 @@ +module "caf" { + source = "aztfmod/caf/azurerm" + version = "~> 0.4" + + current_landingzone_key = var.landingzone.key + tenant_id = var.tenant_id + tfstates = local.tfstates + tags = local.tags + global_settings = local.global_settings + diagnostics = local.diagnostics + diagnostic_storage_accounts = var.diagnostic_storage_accounts + logged_user_objectId = var.logged_user_objectId + logged_aad_app_objectId = var.logged_aad_app_objectId + resource_groups = var.resource_groups + storage_accounts = var.storage_accounts + azuread_groups = var.azuread_groups + keyvaults = var.keyvaults + keyvault_access_policies = var.keyvault_access_policies + managed_identities = var.managed_identities + role_mapping = var.role_mapping + custom_role_definitions = var.custom_role_definitions + azuread_apps = var.azuread_apps + compute = { + virtual_machines = var.virtual_machines + } + storage = { + storage_account_blobs = var.storage_account_blobs + } + + # Pass the remote objects you need to connect to. + remote_objects = { + keyvaults = local.remote.keyvaults + vnets = local.remote.vnets + managed_identities = local.remote.managed_identities + azuread_groups = local.remote.azuread_groups + } +} diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/variables.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/variables.tf new file mode 100644 index 00000000..ac8ec74b --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/variables.tf @@ -0,0 +1,98 @@ +# Map of the remote data state for lower level +variable lower_storage_account_name {} +variable lower_container_name {} +variable lower_resource_group_name {} + +variable tfstate_storage_account_name {} +variable tfstate_container_name {} +variable tfstate_key {} +variable tfstate_resource_group_name {} + +variable global_settings { + default = {} +} +variable tenant_id {} +variable landingzone { +} +variable rover_version { + default = null +} + +variable logged_user_objectId { + default = null +} +variable logged_aad_app_objectId { + default = null +} +variable tags { + default = null +} +variable app_service_environments { + default = {} +} +variable app_service_plans { + default = {} +} +variable app_services { + default = {} +} +variable diagnostics_definition { + default = {} +} +variable resource_groups { + default = {} +} +variable network_security_group_definition { + default = {} +} +variable vnets { + default = {} +} +variable azurerm_redis_caches { + default = {} +} +variable mssql_servers { + default = {} +} +variable storage_accounts { + default = {} +} +variable storage_account_blobs { + default = {} +} +variable azuread_groups { + default = {} +} +variable keyvaults { + default = {} +} +variable keyvault_access_policies { + default = {} +} +variable virtual_machines { + default = {} +} +variable diagnostic_storage_accounts { + default = {} +} +variable virtual_machine_extension_scripts { + default = {} +} +variable azure_devops { + default = {} +} +variable role_mapping { + default = {} +} +variable custom_role_definitions { + default = {} +} +variable azuread_apps { + default = {} +} +variable dynamic_keyvault_secrets { + default = {} +} +variable managed_identities { + default = {} +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/azure_devops_agent/vm_extention_devops_agent.tf b/landingzones/caf_launchpad/add-ons/azure_devops_agent/vm_extention_devops_agent.tf new file mode 100644 index 00000000..fa9a9771 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/azure_devops_agent/vm_extention_devops_agent.tf @@ -0,0 +1,37 @@ + + +# Get PAT token from keyvault +data "azurerm_key_vault_secret" "agent_pat" { + depends_on = [module.caf] + for_each = { + for key, value in try(var.virtual_machines, {}) : key => value + if try(value.virtual_machine_extensions, null) != null + } + + name = var.azure_devops.pats.agent.secret_name + key_vault_id = try(var.azure_devops.pats["agent"].lz_key, null) == null ? local.combined.keyvaults[var.landingzone.key][var.azure_devops.pats["agent"].keyvault_key].id : local.combined.keyvaults[var.azure_devops.pats["agent"].lz_key][var.azure_devops.pats["agent"].keyvault_key].id +} + + +module vm_extensions { + source = "./extensions" + depends_on = [module.caf] + for_each = { + for key, value in try(var.virtual_machines, {}) : key => value + if try(value.virtual_machine_extensions, null) != null + } + + virtual_machine_id = module.caf.virtual_machines[each.key].id + extensions = each.value.virtual_machine_extensions + settings = { + devops_selfhosted_agent = { + storage_accounts = module.caf.storage_accounts + agent_pat = data.azurerm_key_vault_secret.agent_pat[each.key].value + admin_username = each.value.virtual_machine_settings[each.value.os_type].admin_username + azure_devops = var.azure_devops + storage_account_blobs_urls = [ + for key, value in try(var.storage_account_blobs, []) : module.caf.storage_account_blobs[key].url + ] + } + } +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/terraform_cloud/example/tfc.tfvars b/landingzones/caf_launchpad/add-ons/terraform_cloud/example/tfc.tfvars new file mode 100644 index 00000000..1ce04bf0 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/terraform_cloud/example/tfc.tfvars @@ -0,0 +1,25 @@ +landingzone = { + backend_type = "remote" + level = "level0" + key = "launchpad" +} + +# Create the TFC organization +tfe_organizations = { + caf_lz = { + name = "caf-landingzones-test3" + email = "admin@your-company.com" + + } +} + +# Create the required TFE workspaces +tfe_workspaces = { + caf_launchpad = { + # specifies the object key for the organization where to create the workspace + organization_key = "caf_lz" + name = "caf_launchpad" + # path to place the backend file for the corresponding landing zone + backend_file = "/backend.hcl" + } +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/terraform_cloud/main.tf b/landingzones/caf_launchpad/add-ons/terraform_cloud/main.tf new file mode 100644 index 00000000..cc0345aa --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/terraform_cloud/main.tf @@ -0,0 +1,51 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 2.32.0" + } + azuread = { + source = "hashicorp/azuread" + version = "~> 1.0.0" + } + random = { + source = "hashicorp/random" + version = "~> 2.2.1" + } + null = { + source = "hashicorp/null" + version = "~> 2.1.0" + } + external = { + source = "hashicorp/external" + version = "~> 1.2.0" + } + tfe = { + source = "hashicorp/tfe" + version = "~> 0.22.0" + } + } + required_version = ">= 0.13" +} + +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + } + } +} + +data "azurerm_client_config" "current" {} + +locals { + tfstates = merge( + map(var.landingzone.backend_type, + map( + "level", var.landingzone.level, + "tenant_id", data.azurerm_client_config.current.tenant_id, + "subscription_id", data.azurerm_client_config.current.subscription_id + ) + ) + ) +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/terraform_cloud/readme.md b/landingzones/caf_launchpad/add-ons/terraform_cloud/readme.md new file mode 100644 index 00000000..3fe71306 --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/terraform_cloud/readme.md @@ -0,0 +1,44 @@ +# Add-on to deploy a Terraform Cloud / Terraform Enterprise configuration for Azure CAF landing zones + +Supported scenario in this release: + +1. Create the TFE/TFC environment (organization, variables, workspaces) + +Future scenarios: + +1. Use TFE/TFC as remote backend (local execution, backend in TFC) +2. Deploy Terraform Enterprise Server and remote agents +3. Use TFE/TFC in online mode (execution in TFE with remote agents) + +## Authenticating to Terraform Cloud + +First step is to authenticate to TFC using the following commands: + +```bash +terraform login +export TERRAFORM_CONFIG="$HOME/.terraform.d/credentials.tfrc.json" +``` + +## Creating the TFC environment + +This will setup TFC organization, workspaces and variables to host landing zones. + +```bash +# Deploy +rover -lz /tf/caf/landingzones/caf_launchpad/add-ons/tfc/ \ +-var-folder /tf/caf/landingzones/caf_launchpad/add-ons/tfc/example/ \ +-a plan -launchpad + +or +cd /tf/caf/landingzones/caf_launchpad/add-ons/terraform_cloud/ +terraform init +terraform plan \ +-var-file /tf/caf/landingzones/caf_launchpad/add-ons/terraform_cloud/example/tfc.tfvars +``` + +Once ready, you can create your configuration: + +```bash +terraform apply \ +-var-file /tf/caf/landingzones/caf_launchpad/add-ons/terraform_cloud/example/tfc.tfvars +``` \ No newline at end of file diff --git a/landingzones/caf_launchpad/add-ons/terraform_cloud/terraform_cloud.tf b/landingzones/caf_launchpad/add-ons/terraform_cloud/terraform_cloud.tf new file mode 100644 index 00000000..db9218fc --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/terraform_cloud/terraform_cloud.tf @@ -0,0 +1,83 @@ + +resource "tfe_organization" "tfe_org" { + for_each = try(var.tfe_organizations, {}) + + name = each.value.name + email = each.value.email + session_timeout_minutes = try(each.value.session_timeout_minutes, 20160) + session_remember_minutes = try(each.value.session_remember_minutes, 20160) + collaborator_auth_policy = try(each.value.collaborator_auth_policy, "password") + owners_team_saml_role_id = try(each.value.owners_team_saml_role_id, null) +} + +resource "tfe_workspace" "tfe_wks" { + for_each = try(var.tfe_workspaces, {}) + + name = each.value.name + organization = tfe_organization.tfe_org[each.value.organization_key].name + auto_apply = try(each.value.auto_apply, false) + file_triggers_enabled = try(each.value.file_triggers_enabled, true) + operations = try(each.value.operations, true) + queue_all_runs = try(each.value.queue_all_runs, true) + speculative_enabled = try(each.value.speculative_enabled, true) + ssh_key_id = try(each.value.ssh_key_id, null) + terraform_version = try(each.value.terraform_version, null) + trigger_prefixes = try(each.value.trigger_prefixes, null) + working_directory = try(each.value.working_directory, null) + + dynamic "vcs_repo" { + for_each = lookup(each.value, "vcs_repo", null) == null ? [] : [1] + + content { + identifier = each.value.vcs_repo.identifier + branch = try(each.value.vcs_repo.branch, null) + ingress_submodules = try(each.value.vcs_repo.ingress_submodules, false) + oauth_token_id = each.value.vcs_repo.oauth_token_id + } + } +} + +resource "tfe_variable" "variable" { + for_each = try(var.tfe_variables, {}) + + key = each.value.key_name + value = each.value.value + category = each.value.category + workspace_id = tfe_workspace.tfe_wks[each.value.workspace_key].id + description = each.value.description + hcl = try(each.value.hcl, false) + sensitive = try(each.value.sensitive, false) +} + +resource "null_resource" "backend_file" { + depends_on = [tfe_workspace.tfe_wks] + for_each = try(var.tfe_workspaces, {}) + + provisioner "local-exec" { + working_dir = "./" + command = "echo workspaces '{' name = \\\"${each.value.name}\\\" '}' >> ${path.cwd}${each.value.backend_file}" + } + provisioner "local-exec" { + working_dir = "./" + command = "echo hostname = \\\"app.terraform.io\\\" >> ${path.cwd}${each.value.backend_file}" + } + provisioner "local-exec" { + working_dir = "./" + command = "echo organization = \\\"${tfe_organization.tfe_org[each.value.organization_key].name}\\\" >> ${path.cwd}${each.value.backend_file}" + } +} + +resource "null_resource" "backend_file_destroy" { + depends_on = [tfe_workspace.tfe_wks] + for_each = try(var.tfe_workspaces, {}) + + triggers = { + backend_file = lookup(each.value, "backend_file") + } + + provisioner "local-exec" { + command = format("rm %s%s", path.cwd, self.triggers.backend_file) + when = destroy + on_failure = fail + } +} diff --git a/landingzones/caf_launchpad/add-ons/terraform_cloud/variables.tf b/landingzones/caf_launchpad/add-ons/terraform_cloud/variables.tf new file mode 100644 index 00000000..e84068bb --- /dev/null +++ b/landingzones/caf_launchpad/add-ons/terraform_cloud/variables.tf @@ -0,0 +1,85 @@ +# Map of the remote data state for lower level +variable lower_storage_account_name { + default = {} +} +variable lower_container_name { + default = {} +} +variable lower_resource_group_name { + default = {} +} + +variable tfstate_storage_account_name { + default = {} +} +variable tfstate_container_name { + default = {} +} +variable tfstate_key { + default = {} +} +variable tfstate_resource_group_name { + default = {} +} + +variable global_settings { + default = {} +} +variable tenant_id { + default = {} +} +variable landingzone { + default = {} +} + +variable rover_version { + default = null +} + +variable logged_user_objectId { + default = null +} +variable logged_aad_app_objectId { + default = null +} +variable tags { + default = null +} +variable keyvaults { + default = {} +} +variable keyvault_access_policies { + default = {} +} +variable role_mapping { + default = {} +} +variable secrets_from_keys { + default = {} +} +variable custom_role_definitions { + default = {} +} +variable azuread_apps { + default = {} +} + +variable tfe_organizations { + default = {} +} + +variable tfe_workspaces { + default = {} +} + +variable tfe_variables { + default = {} +} + +variable tfe_servers { + default = {} +} + +variable tfe_agents { + default = {} +} \ No newline at end of file diff --git a/landingzones/launchpad/backend.azurerm b/landingzones/caf_launchpad/backend.azurerm similarity index 100% rename from landingzones/launchpad/backend.azurerm rename to landingzones/caf_launchpad/backend.azurerm diff --git a/landingzones/caf_launchpad/documentation/img/launchpad-100.PNG b/landingzones/caf_launchpad/documentation/img/launchpad-100.PNG new file mode 100644 index 00000000..c93a36c4 Binary files /dev/null and b/landingzones/caf_launchpad/documentation/img/launchpad-100.PNG differ diff --git a/landingzones/caf_launchpad/documentation/img/launchpad-200.png b/landingzones/caf_launchpad/documentation/img/launchpad-200.png new file mode 100644 index 00000000..025e4382 Binary files /dev/null and b/landingzones/caf_launchpad/documentation/img/launchpad-200.png differ diff --git a/landingzones/launchpad/documentation/img/launchpad_workflow.png b/landingzones/caf_launchpad/documentation/img/launchpad_workflow.png similarity index 100% rename from landingzones/launchpad/documentation/img/launchpad_workflow.png rename to landingzones/caf_launchpad/documentation/img/launchpad_workflow.png diff --git a/landingzones/launchpad/documentation/variables.md b/landingzones/caf_launchpad/documentation/variables.md similarity index 97% rename from landingzones/launchpad/documentation/variables.md rename to landingzones/caf_launchpad/documentation/variables.md index 34e073f3..ce3e5b19 100644 --- a/landingzones/launchpad/documentation/variables.md +++ b/landingzones/caf_launchpad/documentation/variables.md @@ -25,12 +25,11 @@ There are two launchpad versions that can be deployed in an Azure subscription. |---|---| | global_settings | The global_settings is an object containing the default settings the landing zones from a higher level can hinerit. | -| Default | +| Default | |---| ```hcl default = { default_location = "southeastasia" - convention = "cafrandom" prefix = null } ``` diff --git a/landingzones/caf_launchpad/dynamic_keyvault_secrets/keyvault.tf b/landingzones/caf_launchpad/dynamic_keyvault_secrets/keyvault.tf new file mode 100644 index 00000000..bd324dfc --- /dev/null +++ b/landingzones/caf_launchpad/dynamic_keyvault_secrets/keyvault.tf @@ -0,0 +1,23 @@ +module secret { + source = "./secret" + for_each = { + for key, value in var.settings : key => value + if try(value.value, null) == null + } + + name = each.value.secret_name + value = try(each.value.value, null) == null ? try(var.objects[each.value.output_key][each.value.resource_key][each.value.attribute_key], var.objects[each.value.output_key][each.value.attribute_key]) : each.value.value + keyvault_id = var.keyvault_id +} + +module secret_immutable { + source = "./secret_immutable" + for_each = { + for key, value in var.settings : key => value + if try(value.value, null) == "" + } + + name = each.value.secret_name + value = try(each.value.value, null) == null ? try(var.objects[each.value.output_key][each.value.resource_key][each.value.attribute_key], var.objects[each.value.output_key][each.value.attribute_key]) : each.value.value + keyvault_id = var.keyvault_id +} diff --git a/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret/keyvault_secret.tf b/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret/keyvault_secret.tf new file mode 100644 index 00000000..0eca69eb --- /dev/null +++ b/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret/keyvault_secret.tf @@ -0,0 +1,5 @@ +resource "azurerm_key_vault_secret" "secret" { + name = var.name + value = var.value + key_vault_id = var.keyvault_id +} diff --git a/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret/variables.tf b/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret/variables.tf new file mode 100644 index 00000000..8b97a9f9 --- /dev/null +++ b/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret/variables.tf @@ -0,0 +1,3 @@ +variable name {} +variable value {} +variable keyvault_id {} \ No newline at end of file diff --git a/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret_immutable/keyvault_secret.tf b/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret_immutable/keyvault_secret.tf new file mode 100644 index 00000000..98b32c97 --- /dev/null +++ b/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret_immutable/keyvault_secret.tf @@ -0,0 +1,12 @@ +resource "azurerm_key_vault_secret" "secret" { + count = var.value == "" ? 1 : 0 + name = var.name + value = var.value + key_vault_id = var.keyvault_id + + lifecycle { + ignore_changes = [ + value + ] + } +} diff --git a/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret_immutable/variables.tf b/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret_immutable/variables.tf new file mode 100644 index 00000000..8b97a9f9 --- /dev/null +++ b/landingzones/caf_launchpad/dynamic_keyvault_secrets/secret_immutable/variables.tf @@ -0,0 +1,3 @@ +variable name {} +variable value {} +variable keyvault_id {} \ No newline at end of file diff --git a/landingzones/caf_launchpad/dynamic_keyvault_secrets/variables.tf b/landingzones/caf_launchpad/dynamic_keyvault_secrets/variables.tf new file mode 100644 index 00000000..543e89b4 --- /dev/null +++ b/landingzones/caf_launchpad/dynamic_keyvault_secrets/variables.tf @@ -0,0 +1,3 @@ +variable settings {} +variable objects {} +variable keyvault_id {} \ No newline at end of file diff --git a/landingzones/caf_launchpad/dynamic_secrets.tf b/landingzones/caf_launchpad/dynamic_secrets.tf new file mode 100644 index 00000000..49f1672c --- /dev/null +++ b/landingzones/caf_launchpad/dynamic_secrets.tf @@ -0,0 +1,9 @@ + +module dynamic_keyvault_secrets { + source = "./dynamic_keyvault_secrets" + for_each = try(var.dynamic_keyvault_secrets, {}) + + settings = each.value + keyvault_id = module.launchpad.keyvaults[each.key].id + objects = module.launchpad +} diff --git a/landingzones/caf_launchpad/landingzone.tf b/landingzones/caf_launchpad/landingzone.tf new file mode 100644 index 00000000..c8a64c6a --- /dev/null +++ b/landingzones/caf_launchpad/landingzone.tf @@ -0,0 +1,43 @@ +module "launchpad" { + source = "aztfmod/caf/azurerm" + version = "~> 0.4" + + current_landingzone_key = var.landingzone.key + tenant_id = var.tenant_id + tags = local.tags + global_settings = local.global_settings + enable = var.enable + logged_user_objectId = var.logged_user_objectId + logged_aad_app_objectId = var.logged_aad_app_objectId + user_type = var.user_type + log_analytics = var.log_analytics + event_hub_namespaces = var.event_hub_namespaces + diagnostics_definition = var.diagnostics_definition + diagnostics_destinations = var.diagnostics_destinations + resource_groups = var.resource_groups + keyvaults = var.keyvaults + keyvault_access_policies = var.keyvault_access_policies + keyvault_access_policies_azuread_apps = var.keyvault_access_policies_azuread_apps + subscriptions = var.subscriptions + compute = { + virtual_machines = var.virtual_machines + bastion_hosts = var.bastion_hosts + } + networking = { + vnets = var.vnets + network_security_group_definition = var.network_security_group_definition + public_ip_addresses = var.public_ip_addresses + azurerm_routes = var.azurerm_routes + route_tables = var.route_tables + } + storage_accounts = var.storage_accounts + diagnostic_storage_accounts = var.diagnostic_storage_accounts + azuread_apps = var.azuread_apps + azuread_api_permissions = var.azuread_api_permissions + azuread_groups = var.azuread_groups + azuread_roles = var.azuread_roles + azuread_users = var.azuread_users + managed_identities = var.managed_identities + custom_role_definitions = var.custom_role_definitions + role_mapping = var.role_mapping +} diff --git a/landingzones/caf_launchpad/main.tf b/landingzones/caf_launchpad/main.tf new file mode 100644 index 00000000..89785b37 --- /dev/null +++ b/landingzones/caf_launchpad/main.tf @@ -0,0 +1,100 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 2.33.0" + } + azuread = { + source = "hashicorp/azuread" + version = "~> 1.0.0" + } + random = { + source = "hashicorp/random" + version = "~> 2.2.1" + } + external = { + source = "hashicorp/external" + version = "~> 1.2.0" + } + null = { + source = "hashicorp/null" + version = "~> 2.1.0" + } + tls = { + source = "hashicorp/tls" + version = "~> 2.2.0" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~> 1.1.0" + } + } + required_version = ">= 0.13" +} + + +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + } + } +} + + +resource "random_string" "prefix" { + length = 4 + special = false + upper = false + number = false +} + +resource "random_string" "alpha1" { + length = 1 + special = false + upper = false + number = false +} + +locals { + landingzone_tag = { + landingzone = var.landingzone.key + } + tags = merge(local.landingzone_tag, { "level" = var.landingzone.level }, { "environment" = var.environment }, { "rover_version" = var.rover_version }, var.tags) + + prefix = var.prefix == null ? random_string.prefix.result : var.prefix + + global_settings = { + prefix = local.prefix + prefix_with_hyphen = local.prefix == "" ? "" : "${local.prefix}-" + prefix_start_alpha = local.prefix == "" ? "" : "${random_string.alpha1.result}${local.prefix}" + default_region = var.default_region + environment = var.environment + regions = var.regions + passthrough = var.passthrough + random_length = var.random_length + inherit_tags = var.inherit_tags + } + + tfstates = map(var.landingzone.key, + map( + var.landingzone.key, + local.backend[var.landingzone.backend_type] + ) + ) + + backend = { + azurerm = { + storage_account_name = module.launchpad.storage_accounts[var.launchpad_key_names.tfstates[0]].name + container_name = module.launchpad.storage_accounts[var.launchpad_key_names.tfstates[0]].containers["tfstate"].name + resource_group_name = module.launchpad.storage_accounts[var.launchpad_key_names.tfstates[0]].resource_group_name + key = var.tf_name + level = var.landingzone.level + tenant_id = data.azurerm_client_config.current.tenant_id + subscription_id = data.azurerm_client_config.current.subscription_id + } + } + +} + +data "azurerm_client_config" "current" {} \ No newline at end of file diff --git a/landingzones/caf_launchpad/output.tf b/landingzones/caf_launchpad/output.tf new file mode 100644 index 00000000..8d276d39 --- /dev/null +++ b/landingzones/caf_launchpad/output.tf @@ -0,0 +1,63 @@ +output global_settings { + value = local.global_settings + sensitive = true +} + +output diagnostics { + value = module.launchpad.diagnostics + sensitive = true +} + +output networking { + value = map( + var.landingzone.key, + map( + "vnets", module.launchpad.vnets + ) + ) + sensitive = true + description = "[WARNING] deprecated. Use vnets from 0.4" +} + +output vnets { + value = map(var.landingzone.key, module.launchpad.vnets) + sensitive = true +} + +output tfstates { + value = local.tfstates + sensitive = true +} + +output backend_type { + value = var.landingzone.backend_type + sensitive = true +} + +output keyvaults { + value = map( + var.landingzone.key, module.launchpad.keyvaults + ) + sensitive = true +} + +output managed_identities { + value = map( + var.landingzone.key, module.launchpad.managed_identities + ) + sensitive = true +} + +output aad_apps { + value = map( + var.landingzone.key, module.launchpad.aad_apps + ) + sensitive = true +} + +output azuread_groups { + value = map( + var.landingzone.key, module.launchpad.azuread_groups + ) + sensitive = true +} \ No newline at end of file diff --git a/landingzones/launchpad/readme.md b/landingzones/caf_launchpad/readme.md similarity index 69% rename from landingzones/launchpad/readme.md rename to landingzones/caf_launchpad/readme.md index bdaabbc8..476d81e2 100644 --- a/landingzones/launchpad/readme.md +++ b/landingzones/caf_launchpad/readme.md @@ -1,153 +1,194 @@ -# Azure Cloud Adoption Framework - Launchpad - -The launchpads allow you to manage the foundations of landing zone environments by: - -Securing remote Terraform state storage for multiple subscriptions. -Managing the transition from manual to automated environments. - -## Launchpad initialization process - -The launchpad components are deployed by a set of Terraform files using the Rover - -``` -rover -lz /tf/caf/landingzones/launchpad -a apply -launchpad -``` - -![Launchpad Worklow](./documentation/img/launchpad_workflow.png) - -The rover executed in launchpad mode performs the following option to bootstrap your environment: - -1. **Initialize a terraform state**: - * The launchpad tries to retrieve an existing terraform state on Azure using the name of the tfstate file and the name of the workspace (level0 by default) - * Creates a tfstates folder if no remote state have been retrieved, this happens when your environment does not contain a storage account containing a tfstate matching the input parameters - - The Launchpad deployment relies on the following providers: - - * hashicorp/azurerm - * hashicorp/azuread - * hashicorp/random - * aztfmod/azurecaf - * hashicorp/null - - The latest version of the Launchpad relies on the new capabilities of **Terraform 0.13** - -2. **Call Terraform init**: - - * The launchpad then call terraform init to retrieve the provides and modules associated with the deployment - -3. **Call terraform apply**: - * deploy the resources as specified in the launchpad configuration files (see description below) - -``` -Outputs: - -aad_apps = -azure_subscriptions = -diagnostics_map = -github_token_keyvault = -global_settings = -keyvaults = -log_analytics = -networking = -resource_groups = -``` - -4. **Create a workspace to host the local tfsate** - the launchpad will create two containers in the newly created storage account (in step 3): - * "sandpit" workspace - * "level0" (by default) workspace - -5. **Upload the launchpad state (tfstate) to the storage level0 workspace** - the state contains the default settings, keyvault id, and service principal id created during the launchpad deployment - -``` -Moving launchpad to the cloud - - storage_account_name: storageaccname - - resource_group: hrjx-rg-launchpad-tfstates-rVb7GtKPXxHMa - - storage_key: retrieved -{ - "etag": "\"0x8D833A974C32C5F\"", - "lastModified": "2020-07-29T10:23:37+00:00" -} -``` - -## Launchpad architecture - -Each resource deployed with the launchpad is leveraging the azurecaf provider to enforce naming convention - -![Launchpad Worklow](./documentation/img/Launchpad_deployment.png) - -The launchpad light deploys the following Azure components: - -1. Resource groups - By default the launchpad light auto variables will create three resources groups : launchpad-tfstates to host a the tfstate storage account, launchpad-security to host a keyvault, launchpad-devops-agents to host deployment agents should you choose to deploy VMs to automate subsequent deployemnt using Azure DevOps or GitHub - -2. Storage Accounts - a storage account in the launchpad-tfstates reosource group. The storage account contains the tfstate of the launchpad deployment and will be automatically configured as the Terraform remote backend when deploying landing zones with the rover - -3. KeyVaults - a keyvault resource to store with Get,List,Set,Delete access to for the logged in user (using the Azure CLI) - the keyvault will contain secrets of service principal accounts and managed identities - -4. A Log Analytics workspace and a KeyVault analytics solution deployed in the launchpad-devops-agent resource group. The Log Analytics workspace will gather the monitoring information and logs of both the DevOps agents and of the Keyvault - -5. Diagnostic settings - Creates Storage Account and Event Hubs (optional) to be used for diagnostics and operations logs. The resources are created in the launchpad-devops-agent resource group - -6. Virtual Network: The Launchpad can create Virtual Networks and subnets to deploy additional workloads during the bootstrap process - typically CI/CD agents - -7. Azure Active Directory Applications and role assignment - - This a critical aspect of the launchpad bootstrap process. The deployment creates an Azure AD Application named "caf_launchpad_level0" by default. The launchpad can be configured to creatd additional Azure AD Applications - - * The user deploying the launchpad is set to be the application owner - * A Service Principal + random password is created for each Application - the data is then stored in the referenced keyvault as multiple secrets - * Resource Access is assigned based on the aad_api_permissions object - * Each application can be assigned one or multiple Azure AD roles through the aad_roles object - empty by default - - By default the underlying service principal will be granted **owner** access to the subscription targeted by the launchpad deployment. This Azure AD Application + Service Principal will be used in subsequent deployments using the Rover. - - API permissions and admin consent are also granted during the bootstrap process. The grant_consent.sh scripts is called for to enable API access for a given Application - * The variable `aad_api_permissions` object can contains multiple entries - * each key references one of the Application defined in the `aad_apps` variable. The content of each entry is an api permission definition. - - The objectId, ApplicationId, ServicePrincipalID, client_secret are each stored in a keyvault using the secret_prefix value as defined in the code example - - The example below shows an App Definition, a role assignment and an API permission assignment. using three terraform variables with define an app called "caf_launchpad_github_terraformdev_github-integration-landingzones", we assign the Application Developer role to this application, finally we grand admin consent to the Active Directory Graph APIs. - - ``` terraform - aad_apps = { - azure_caf-terraform-landingzones = { - application_name = "caf_launchpad_github_terraformdev_github-integration-landingzones" - password_expire_in_days = 60 - tenant_name = "terraformdev.onmicrosoft.com" - keyvault = { - keyvault_key = "launchpad" - secret_prefix = "caf-launchpad-github-terraformdev-github-integration-landingzones" - } - } - } - aad_roles = { - azure_caf-terraform-landingzones = { - roles = [ - "Application Developer" - ] - } - } - - aad_api_permissions = { - azure_caf-terraform-landingzones = { - active_directory_graph = { - resource_app_id = "00000002-0000-0000-c000-000000000000" - resource_access = { - active_directory_graph_resource_access_id_Application_ReadWrite_OwnedBy = { - id = "824c81eb-e3f8-4ee6-8f6d-de7f50d565b7" - type = "Role" - } - active_directory_graph_resource_access_id_Directory_ReadWrite_All = { - id = "78c8a3c8-a07e-4b9e-af1b-b5ccab50a175" - type = "Role" - } - } - } - } - } - ``` - - The Azure Active Directory Application creation, Role assignment and Admin Consent delegation plays a critical role in the launchpad bootstrapping process. Make sure to work with your Tenant administrators to define the scope and the roles assigned the Application created by the launchpad. - -8. Release Agents (Optional): - * Deploys Virtual machines in the targeted Virtual Network. You may choose to leverage an existing Azure DevOps organization and deploy CI/CD agents and pipelines. The Agents will then be in charge of subsequent rover deployments to automate the IaC provisioning with Terraform +# Cloud Adoption Framework for Azure - Landing zones on Terraform - Launchpad + +The launchpad allows you to manage the foundations of landing zone environments by: + +* Securing remote Terraform state storage for multiple subscriptions. +* Managing the transition from manual to automated environments. +* Bring up the DevOps foundations using Azure DevOps, Terraform Cloud and GitHub actions (more to come). + +Launchpad operates at **level 0**. + +For a review of the hierarchy approach of Cloud Adoption Framework for Azure landing zones on Terraform, you can refer to [the following documentation](../../documentation/code_architecture/hierarchy.md). + +
+ +## Getting started with launchpad + +Depending on what you are trying to achieve, we provide you with different levels of launchpads to cover different scenario: + +| level | scenario | supported environments | +|-----------------------|------------------------------------------------------------------------------------------------------------------|--------------------------------------------| +| [100](./scenario/100) | Start with this one! basic functionalities and features, no RBAC or security hardening - for demo and simple POC | working on AIRS subscriptions | +| [200](./scenario/200) | intermediate functionalities includes diagnostics features | may not work in AIRS, need AAD permissions | +| [300](./scenario/300) | advanced functionalities, includes RBAC features | not working in AIRS, need AAD permissions | +| [400](./scenario/400) | advanced functionalities, includes RBAC features and security hardening | not working in AIRS, need AAD permissions | + +You can pick your scenario and use one of the following commands: + +```bash +# Simple scenario for learning and demonstration +rover -lz /tf/caf/landingzones/caf_launchpad \ + -launchpad \ + -var-folder /tf/caf/landingzones/caf_launchpad/scenario/100 \ + -parallelism=30 \ + -a apply + +# Advanced scenario - Requires Azure AD privileges +rover -lz /tf/caf/landingzones/caf_launchpad -launchpad -var-folder /tf/caf/landingzones/caf_launchpad/scenario/200/configuration.tfvars -parallelism=30 -a apply +``` + +
+ +## Overview of launchpad initialization + +![Launchpad Worklow](./documentation/img/launchpad_workflow.png) + +The rover executed in launchpad mode performs the following option to bootstrap your environment: + +1. **Initialize a terraform state**: + * The launchpad tries to retrieve an existing terraform state on Azure using the name of the tfstate file and the name of the workspace (level0 by default) + * Creates a tfstates folder if no remote state have been retrieved, this happens when your environment does not contain a storage account containing a tfstate matching the input parameters + + The Launchpad deployment relies on the following providers: + + * hashicorp/azurerm + * hashicorp/azuread + * hashicorp/random + * aztfmod/azurecaf + * hashicorp/null + + The latest version of the Launchpad relies on the new capabilities of **Terraform 0.13** + +2. **Call Terraform init**: + + * The launchpad then call terraform init to retrieve the provides and modules associated with the deployment + +3. **Call terraform apply**: + * deploy the resources as specified in the launchpad configuration files (see description below) + +```bash +Outputs: + +aad_apps = +azure_subscriptions = +diagnostics_map = +github_token_keyvault = +global_settings = +keyvaults = +log_analytics = +networking = +resource_groups = +``` + +4. **Create a workspace to host the local tfsate** - the launchpad will create two containers in the newly created storage account (in step 3): + * "sandpit" workspace + * "level0" (by default) workspace + +5. **Upload the launchpad state (tfstate) to the storage level0 workspace** - the state contains the default settings, keyvault id, and service principal id created during the launchpad deployment + +```bash +Moving launchpad to the cloud + - storage_account_name: storageaccname + - resource_group: hrjx-rg-launchpad-tfstates-rVb7GtKPXxHMa + - storage_key: retrieved +{ + "etag": "\"0x8D833A974C32C5F\"", + "lastModified": "2020-07-29T10:23:37+00:00" +} +``` + +
+ +## Launchpad architecture + +Each resource deployed with the launchpad is leveraging the [azurecaf provider](https://github.com/aztfmod/terraform-provider-azurecaf) to enforce naming convention. + +The launchpad deploys the following Azure components: + +1. Resource groups - By default the launchpad light auto variables will create three resources groups : launchpad-tfstates to host a the tfstate storage account, launchpad-security to host a keyvault, launchpad-devops-agents to host deployment agents should you choose to deploy VMs to automate subsequent deployment using Azure DevOps or GitHub + +2. Storage Accounts - a storage account in the launchpad-tfstates reosource group. The storage account contains the tfstate of the launchpad deployment and will be automatically configured as the Terraform remote backend when deploying landing zones with the rover + +3. KeyVaults - a keyvault resource to store with Get,List,Set,Delete access to for the logged in user (using the Azure CLI) - the keyvault will contain secrets of service principal accounts and managed identities + +4. A Log Analytics workspace and a KeyVault analytics solution deployed in the launchpad-devops-agent resource group. The Log Analytics workspace will gather the monitoring information and logs of both the DevOps agents and of the Keyvault + +5. Diagnostic settings - Creates Storage Account and Event Hubs (optional) to be used for diagnostics and operations logs. The resources are created in the launchpad-devops-agent resource group + +6. Virtual Network: The Launchpad can create Virtual Networks and subnets to deploy additional workloads during the bootstrap process - typically CI/CD agents + +7. Azure Active Directory Applications and role assignment + + This a critical aspect of the launchpad bootstrap process. The deployment creates an Azure AD Application named "caf_launchpad_level0" by default. The launchpad can be configured to create additional Azure AD Applications + + * The user deploying the launchpad is set to be the application owner + * A Service Principal + random password is created for each Application - the data is then stored in the referenced keyvault as multiple secrets + * Resource Access is assigned based on the aad_api_permissions object + * Each application can be assigned one or multiple Azure AD roles through the aad_roles object - empty by default + + By default the underlying service principal will be granted **owner** access to the subscription targeted by the launchpad deployment. This Azure AD Application + Service Principal will be used in subsequent deployments using the Rover. + + API permissions and admin consent are also granted during the bootstrap process. The grant_consent.sh scripts is called for to enable API access for a given Application + * The variable `aad_api_permissions` object can contains multiple entries + * each key references one of the Application defined in the `aad_apps` variable. The content of each entry is an api permission definition. + + The objectId, ApplicationId, ServicePrincipalID, client_secret are each stored in a keyvault using the secret_prefix value as defined in the code example + + The example below shows an App Definition, a role assignment and an API permission assignment. using three terraform variables with define an app called "caf_launchpad_github_terraformdev_github-integration-landingzones", we assign the Application Developer role to this application, finally we grand admin consent to the Active Directory Graph APIs. + + ```terraform + aad_apps = { + azure_caf-terraform-landingzones = { + application_name = "caf_launchpad_github_terraformdev_github-integration-landingzones" + password_expire_in_days = 60 + tenant_name = "terraformdev.onmicrosoft.com" + keyvault = { + keyvault_key = "launchpad" + secret_prefix = "caf-launchpad-github-terraformdev-github-integration-landingzones" + } + } + } + aad_roles = { + azure_caf-terraform-landingzones = { + roles = [ + "Application Developer" + ] + } + } + + aad_api_permissions = { + azure_caf-terraform-landingzones = { + active_directory_graph = { + resource_app_id = "00000002-0000-0000-c000-000000000000" + resource_access = { + active_directory_graph_resource_access_id_Application_ReadWrite_OwnedBy = { + id = "824c81eb-e3f8-4ee6-8f6d-de7f50d565b7" + type = "Role" + } + active_directory_graph_resource_access_id_Directory_ReadWrite_All = { + id = "78c8a3c8-a07e-4b9e-af1b-b5ccab50a175" + type = "Role" + } + } + } + } + } + ``` + + The Azure Active Directory Application creation, Role assignment and Admin Consent delegation plays a critical role in the launchpad bootstrapping process. Make sure to work with your Tenant administrators to define the scope and the roles assigned the Application created by the launchpad. + +8. Release Agents (Optional): + * Deploys Virtual machines in the targeted Virtual Network. You may choose to leverage an existing Azure DevOps organization and deploy CI/CD agents and pipelines. The Agents will then be in charge of subsequent rover deployments to automate the IaC provisioning with Terraform + +## Launchpad add-ons + +Add-ons are additional capabilities to enhance the launchpad, that are deployed separately and managed by a different state. + +Current add-ons: + +* Azure DevOps Self Hosted Agents and Pipeline + +In-development add-ons: + +* Terrform Cloud Enterprise +* GitHub Actions \ No newline at end of file diff --git a/landingzones/caf_launchpad/scenario/100/README.md b/landingzones/caf_launchpad/scenario/100/README.md new file mode 100644 index 00000000..dfa8197a --- /dev/null +++ b/landingzones/caf_launchpad/scenario/100/README.md @@ -0,0 +1,44 @@ +# Launchpad - scenario 100 + +The 100 scenario is designed to demonstrate a basic functional foundations to store Terraform state on Azure storage and use it centrally. +The focus of this scenario is to be able to deploy a basic launchpad from a remote machine and use the portal to review the settings in a non-constrained environment. +For example in this scenario you can go to the Key Vaults and view the secrets from the portal, a feature that is disabled in the 300+ scenarios. +We recommend using the 100 scenario for demonstration purposes. + +An estimated time of 5 minutes is required to deploy this scenario. + +## Pre-requisites + +This scenario require the following privileges: + +| Component | Privileges | +|--------------------|--------------------| +| Active Directory | None | +| Azure subscription | Subscription owner | + +## Deployment + +```bash +rover -lz /tf/caf/landingzones/caf_launchpad \ + -launchpad -var-folder \ + /tf/caf/landingzones/caf_launchpad/scenario/100 \ + -a apply + +rover -lz /tf/caf/landingzones/caf_launchpad \ + -launchpad \ + -var-folder /tf/caf/landingzones/caf_launchpad/scenario/100 \ + -a destroy +``` + +## Architecture diagram +![Launchpad 100](../../documentation/img/launchpad-100.PNG) + +## Services deployed in this scenario + +| Component | Purpose | +|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Resource group | Multiple resource groups are created to isolate the services. | +| Storage account | A storage account for remote tfstate management is provided for each level of the framework. Additional storage accounts are created for diagnostic logs. | +| Key Vault | The launchpad Key Vault hosts all secrets required by the rover to access the remote states, the Key Vault policies are created allowing the logged-in user to see secrets created and stored. | +| Virtual network | To secure the communication between the services a dedicated virtual network is deployed with a gateway subnet, bastion service, jumpbox and azure devops release agents. Service endpoints is enabled but not configured. | +| Azure AD Applications | An Azure AD application is created. This account is mainly use to bootstrap the services during the initialization. It is also considered as a breakglass account for the launchpad landing zones | diff --git a/landingzones/caf_launchpad/scenario/100/configuration.tfvars b/landingzones/caf_launchpad/scenario/100/configuration.tfvars new file mode 100644 index 00000000..ad53a6ba --- /dev/null +++ b/landingzones/caf_launchpad/scenario/100/configuration.tfvars @@ -0,0 +1,68 @@ +landingzone = { + backend_type = "azurerm" + level = "level0" + key = "launchpad" +} + + +# Default region. When not set to a resource it will use that value +default_region = "region1" + +# naming convention settings +# for more settings on naming convention, please refer to the provider documentation: https://github.com/aztfmod/terraform-provider-azurecaf +# +# passthrough means the default CAF naming convention is not applied and you are responsible +# of the unicity of the names you are giving. the CAF provider will clear out +# passthrough = false +# adds random chars at the end of the names produced by the provider +# random_length = 3 + +# Inherit_tags defines if a resource will inherit it's resource group tags +inherit_tags = true + +regions = { + region1 = "southeastasia" + region2 = "eastasia" +} + +launchpad_key_names = { + azuread_app = "caf_launchpad_level0" + keyvault_client_secret = "aadapp-caf-launchpad-level0" + tfstates = [ + "level0", + ] +} + +resource_groups = { + level0 = { + name = "launchpad-level0" + tags = { + level = "level0" + } + } + level1 = { + name = "launchpad-level1" + tags = { + level = "level1" + } + } + level2 = { + name = "launchpad-level2" + tags = { + level = "level2" + } + } + level3 = { + name = "launchpad-level3" + tags = { + level = "level3" + } + } + level4 = { + name = "launchpad-level4" + tags = { + level = "level4" + } + } +} + diff --git a/landingzones/caf_launchpad/scenario/100/dynamic_secrets.tfvars b/landingzones/caf_launchpad/scenario/100/dynamic_secrets.tfvars new file mode 100644 index 00000000..096bc80b --- /dev/null +++ b/landingzones/caf_launchpad/scenario/100/dynamic_secrets.tfvars @@ -0,0 +1,114 @@ + +# Store output attributes into keyvault secret +# Those values are used by the rover to connect the current remote state and +# identity the lower level +dynamic_keyvault_secrets = { + level0 = { + subscription_id = { + output_key = "client_config" + attribute_key = "subscription_id" + secret_name = "subscription-id" + } + tenant_id = { + output_key = "client_config" + attribute_key = "tenant_id" + secret_name = "tenant-id" + } + } + level1 = { + lower_stg = { + output_key = "storage_accounts" + resource_key = "level0" + attribute_key = "name" + secret_name = "lower-storage-account-name" + } + lower_rg = { + output_key = "resource_groups" + resource_key = "level0" + attribute_key = "name" + secret_name = "lower-resource-group-name" + } + subscription_id = { + output_key = "client_config" + attribute_key = "subscription_id" + secret_name = "subscription-id" + } + tenant_id = { + output_key = "client_config" + attribute_key = "tenant_id" + secret_name = "tenant-id" + } + } + level2 = { + lower_stg = { + output_key = "storage_accounts" + resource_key = "level1" + attribute_key = "name" + secret_name = "lower-storage-account-name" + } + lower_rg = { + output_key = "resource_groups" + resource_key = "level1" + attribute_key = "name" + secret_name = "lower-resource-group-name" + } + subscription_id = { + output_key = "client_config" + attribute_key = "subscription_id" + secret_name = "subscription-id" + } + tenant_id = { + output_key = "client_config" + attribute_key = "tenant_id" + secret_name = "tenant-id" + } + } + level3 = { + lower_stg = { + output_key = "storage_accounts" + resource_key = "level2" + attribute_key = "name" + secret_name = "lower-storage-account-name" + } + lower_rg = { + output_key = "resource_groups" + resource_key = "level2" + attribute_key = "name" + secret_name = "lower-resource-group-name" + } + subscription_id = { + output_key = "client_config" + attribute_key = "subscription_id" + secret_name = "subscription-id" + } + tenant_id = { + output_key = "client_config" + attribute_key = "tenant_id" + secret_name = "tenant-id" + } + } + level4 = { + lower_stg = { + output_key = "storage_accounts" + resource_key = "level3" + attribute_key = "name" + secret_name = "lower-storage-account-name" + } + lower_rg = { + output_key = "resource_groups" + resource_key = "level3" + attribute_key = "name" + secret_name = "lower-resource-group-name" + } + subscription_id = { + output_key = "client_config" + attribute_key = "subscription_id" + secret_name = "subscription-id" + } + tenant_id = { + output_key = "client_config" + attribute_key = "tenant_id" + secret_name = "tenant-id" + } + } +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/scenario/100/iam_role_mapping.tfvars b/landingzones/caf_launchpad/scenario/100/iam_role_mapping.tfvars new file mode 100644 index 00000000..87a218b8 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/100/iam_role_mapping.tfvars @@ -0,0 +1,47 @@ + +# +# Services supported: subscriptions, storage accounts and resource groups +# Can assign roles to: AD groups, AD object ID, AD applications, Managed identities +# +role_mapping = { + built_in_role_mapping = { + storage_accounts = { + level0 = { + "Storage Blob Data Contributor" = { + logged_in = { + keys = ["user"] + } + } + } + level1 = { + "Storage Blob Data Contributor" = { + logged_in = { + keys = ["user"] + } + } + } + level2 = { + "Storage Blob Data Contributor" = { + logged_in = { + keys = ["user"] + } + } + } + level3 = { + "Storage Blob Data Contributor" = { + logged_in = { + keys = ["user"] + } + } + } + level4 = { + "Storage Blob Data Contributor" = { + logged_in = { + keys = ["user"] + } + } + } + } + } + +} diff --git a/landingzones/caf_launchpad/scenario/100/keyvaults.tfvars b/landingzones/caf_launchpad/scenario/100/keyvaults.tfvars new file mode 100644 index 00000000..00de22b4 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/100/keyvaults.tfvars @@ -0,0 +1,99 @@ + +keyvaults = { + level0 = { + name = "level0" + resource_group_key = "level0" + sku_name = "standard" + soft_delete_enabled = true + tags = { + tfstate = "level0" + environment = "sandpit" + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + } + + level1 = { + name = "level1" + resource_group_key = "level1" + sku_name = "standard" + soft_delete_enabled = true + tags = { + tfstate = "level1" + environment = "sandpit" + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + } + + level2 = { + name = "level2" + resource_group_key = "level2" + sku_name = "standard" + soft_delete_enabled = true + tags = { + tfstate = "level2" + environment = "sandpit" + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + } + + level3 = { + name = "level3" + resource_group_key = "level3" + sku_name = "standard" + soft_delete_enabled = true + tags = { + tfstate = "level3" + environment = "sandpit" + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + } + + level4 = { + name = "level4" + resource_group_key = "level4" + sku_name = "standard" + soft_delete_enabled = true + tags = { + tfstate = "level4" + environment = "sandpit" + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + } +} diff --git a/landingzones/caf_launchpad/scenario/100/storage_accounts.tfvars b/landingzones/caf_launchpad/scenario/100/storage_accounts.tfvars new file mode 100644 index 00000000..bb2834b9 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/100/storage_accounts.tfvars @@ -0,0 +1,102 @@ + +storage_accounts = { + level0 = { + name = "level0" + resource_group_key = "level0" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "RAGRS" + tags = { + ## Those tags must never be changed after being set as they are used by the rover to locate the launchpad and the tfstates. + # Only adjust the environment value at creation time + tfstate = "level0" + environment = "sandpit" + launchpad = "launchpad" + ## + } + containers = { + tfstate = { + name = "tfstate" + } + } + } + + + level1 = { + name = "level1" + resource_group_key = "level1" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "RAGRS" + tags = { + # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates. + tfstate = "level1" + environment = "sandpit" + launchpad = "launchpad" + } + containers = { + tfstate = { + name = "tfstate" + } + } + } + + level2 = { + name = "level2" + resource_group_key = "level2" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "RAGRS" + tags = { + # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates. + tfstate = "level2" + environment = "sandpit" + launchpad = "launchpad" + } + containers = { + tfstate = { + name = "tfstate" + } + } + } + + level3 = { + name = "level3" + resource_group_key = "level3" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "RAGRS" + tags = { + # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates. + tfstate = "level3" + environment = "sandpit" + launchpad = "launchpad" + } + containers = { + tfstate = { + name = "tfstate" + } + } + } + + level4 = { + name = "level4" + resource_group_key = "level4" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "RAGRS" + tags = { + # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates. + tfstate = "level4" + environment = "sandpit" + launchpad = "launchpad" + } + containers = { + tfstate = { + name = "tfstate" + } + } + + } + +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/scenario/200/compute.tfvars b/landingzones/caf_launchpad/scenario/200/compute.tfvars new file mode 100644 index 00000000..88164c5a --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/compute.tfvars @@ -0,0 +1,100 @@ +################################################## +# +# Compute resources +# +################################################## + +bastion_hosts = { + launchpad_host = { + name = "bastion" + resource_group_key = "bastion_launchpad" + vnet_key = "devops_region1" + subnet_key = "AzureBastionSubnet" + public_ip_key = "bastion_host_rg1" + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "bastion_host" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + + } +} + +# Virtual machines +virtual_machines = { + + # Configuration to deploy a bastion host linux virtual machine + bastion_host = { + resource_group_key = "bastion_launchpad" + region = "region1" + boot_diagnostics_storage_account_key = "bootdiag_region1" + provision_vm_agent = true + + os_type = "linux" + + # the auto-generated ssh key in keyvault secret. Secret name being {VM name}-ssh-public and {VM name}-ssh-private + keyvault_key = "secrets" + + # Define the number of networking cards to attach the virtual machine + networking_interfaces = { + nic0 = { + # Value of the keys from networking.tfvars + vnet_key = "devops_region1" + subnet_key = "jumpbox" + name = "0" + enable_ip_forwarding = false + internal_dns_name_label = "nic0" + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "network_interface_card" + destination_type = "storage" + destination_key = "all_regions" + } + } + + } + } + + virtual_machine_settings = { + linux = { + name = "bastion" + size = "Standard_F2" + admin_username = "adminuser" + disable_password_authentication = true + custom_data = "scripts/cloud-init-install-rover-tools.config" + + # Value of the nic keys to attach the VM. The first one in the list is the default nic + network_interface_keys = ["nic0"] + + os_disk = { + name = "bastion-os" + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference = { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "18.04-LTS" + version = "latest" + } + + identity = { + type = "UserAssigned" + managed_identity_keys = [ + "level0", "level1", "level2", "level3", "level4" + ] + } + + } + } + + } +} + diff --git a/landingzones/caf_launchpad/scenario/200/configuration.tfvars b/landingzones/caf_launchpad/scenario/200/configuration.tfvars new file mode 100644 index 00000000..36645019 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/configuration.tfvars @@ -0,0 +1,100 @@ +landingzone = { + backend_type = "azurerm" + level = "level0" + key = "launchpad" +} + +enable = { + bastion_hosts = false + virtual_machines = false +} + +# Default region. When not set to a resource it will use that value +default_region = "region1" + +regions = { + region1 = "southeastasia" + region2 = "eastasia" +} + +# core tags to be applied accross this landing zone +tags = { + owner = "CAF" + deploymentType = "Terraform" + costCenter = "0" + BusinessUnit = "SHARED" + DR = "NON-DR-ENABLED" +} + +# naming convention settings +# for more settings on naming convention, please refer to the provider documentation: https://github.com/aztfmod/terraform-provider-azurecaf +# +# passthrough means the default CAF naming convention is not applied and you are responsible +# of the unicity of the names you are giving. the CAF provider will clear out +# passthrough = false +# adds random chars at the end of the names produced by the provider +# random_length = 3 + +# all resources deployed will inherit tags from the parent resource group +inherit_tags = true + +launchpad_key_names = { + azuread_app = "caf_launchpad_level0" + keyvault_client_secret = "aadapp-caf-launchpad-level0" + tfstates = [ + "level0", + "level1", + "level2", + "level3", + "level4" + ] +} + +resource_groups = { + level0 = { + name = "launchpad-level0" + tags = { + level = "level0" + } + } + level1 = { + name = "launchpad-level1" + tags = { + level = "level1" + } + } + level2 = { + name = "launchpad-level2" + tags = { + level = "level2" + } + } + level3 = { + name = "launchpad-level3" + tags = { + level = "level3" + } + } + level4 = { + name = "launchpad-level4" + tags = { + level = "level4" + } + } + security = { + name = "launchpad-security" + } + networking = { + name = "launchpad-networking" + } + ops = { + name = "operations" + } + siem = { + name = "siem-logs" + } + bastion_launchpad = { + name = "launchpad-bastion" + } +} + diff --git a/landingzones/caf_launchpad/scenario/200/diagnostics_definition.tfvars b/landingzones/caf_launchpad/scenario/200/diagnostics_definition.tfvars new file mode 100644 index 00000000..10a20c4d --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/diagnostics_definition.tfvars @@ -0,0 +1,274 @@ + +# +# Define a set of settings for the various type of Azure resources +# + +diagnostics_definition = { + log_analytics = { + name = "operational_logs_and_metrics" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["Audit", true, false, 7], + ] + metric = [ + #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", true, false, 7], + ] + } + + } + + default_all = { + name = "operational_logs_and_metrics" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AuditEvent", true, false, 7], + ] + metric = [ + #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", true, false, 7], + ] + } + + } + + bastion_host = { + name = "operational_logs_and_metrics" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["BastionAuditLogs", true, false, 7], + ] + } + + } + + networking_all = { + name = "operational_logs_and_metrics" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["VMProtectionAlerts", true, false, 7], + ] + metric = [ + #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", true, false, 7], + ] + } + + } + + public_ip_address = { + name = "operational_logs_and_metrics" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["DDoSProtectionNotifications", true, false, 7], + ["DDoSMitigationFlowLogs", true, false, 7], + ["DDoSMitigationReports", true, false, 7], + ] + metric = [ + #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", true, false, 7], + ] + } + + } + + network_security_group = { + name = "operational_logs_and_metrics" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["NetworkSecurityGroupEvent", true, false, 7], + ["NetworkSecurityGroupRuleCounter", true, false, 7], + ] + } + + } + + network_interface_card = { + name = "operational_logs_and_metrics" + categories = { + # log = [ + # # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + # ["AuditEvent", true, false, 7], + # ] + metric = [ + #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", true, false, 7], + ] + } + + } + + azure_container_registry = { + name = "operational_logs_and_metrics" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["ContainerRegistryRepositoryEvents", true, false, 7], + ["ContainerRegistryLoginEvents", true, false, 7], + ] + metric = [ + #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", true, false, 7], + ] + } + } + + azure_kubernetes_cluster = { + name = "operational_logs_and_metrics" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["kube-apiserver", true, false, 7], + ["kube-audit", true, false, 7], + ["kube-audit-admin", true, false, 7], + ["kube-controller-manager", true, false, 7], + ["kube-scheduler", true, false, 7], + ["cluster-autoscaler", true, false, 7], + ["guard", true, false, 7], + ] + metric = [ + #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", true, false, 7], + ] + } + } + + azure_site_recovery = { + name = "operational_logs_and_metrics" + log_analytics_destination_type = "Dedicated" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AzureBackupReport", true, true, 7], + ["CoreAzureBackup", true, true, 7], + ["AddonAzureBackupAlerts", true, true, 7], + ["AddonAzureBackupJobs", true, true, 7], + ["AddonAzureBackupPolicy", true, true, 7], + ["AddonAzureBackupProtectedInstance", true, true, 7], + ["AddonAzureBackupStorage", true, true, 7], + ["AzureSiteRecoveryJobs", true, true, 7], + ["AzureSiteRecoveryEvents", true, true, 7], + ["AzureSiteRecoveryReplicatedItems", true, true, 7], + ["AzureSiteRecoveryReplicationStats", true, true, 7], + ["AzureSiteRecoveryRecoveryPoints", true, true, 7], + ["AzureSiteRecoveryReplicationDataUploadRate", true, true, 7], + ["AzureSiteRecoveryProtectedDiskDataChurn", true, true, 30], + ] + metric = [ + #["AllMetrics", 60, True], + ] + } + + } + + azure_automation = { + name = "operational_logs_and_metrics" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["JobLogs", true, true, 30], + ["JobStreams", true, true, 30], + ["DscNodeStatus", true, true, 30], + ] + metric = [ + # ["Category name", "Metric Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", true, true, 30], + ] + } + + } + + event_hub_namespace = { + name = "operational_logs_and_metrics" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["ArchiveLogs", true, false, 7], + ["OperationalLogs", true, false, 7], + ["AutoScaleLogs", true, false, 7], + ["KafkaCoordinatorLogs", true, false, 7], + ["KafkaUserErrorLogs", true, false, 7], + ["EventHubVNetConnectionEvent", true, false, 7], + ["CustomerManagedKeyUserLogs", true, false, 7], + ] + metric = [ + #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", true, false, 7], + ] + } + + } + + compliance_all = { + name = "compliance_logs" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AuditEvent", true, true, 365], + ] + metric = [ + #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", false, false, 7], + ] + } + + } + + siem_all = { + name = "siem" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AuditEvent", true, true, 0], + ] + + metric = [ + #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] + ["AllMetrics", false, false, 0], + ] + } + + } + + subscription_operations = { + name = "subscription_operations" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)"] + ["Administrative", true], + ["Security", true], + ["ServiceHealth", true], + ["Alert", true], + ["Policy", true], + ["Autoscale", true], + ["ResourceHealth", true], + ["Recommendation", true], + ] + } + } + + subscription_siem = { + name = "activity_logs_for_siem" + categories = { + log = [ + # ["Category name", "Diagnostics Enabled(true/false)"] + ["Administrative", false], + ["Security", true], + ["ServiceHealth", false], + ["Alert", false], + ["Policy", true], + ["Autoscale", false], + ["ResourceHealth", false], + ["Recommendation", false], + ] + } + + } + +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/scenario/200/diagnostics_destinations.tfvars b/landingzones/caf_launchpad/scenario/200/diagnostics_destinations.tfvars new file mode 100644 index 00000000..95ede1c2 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/diagnostics_destinations.tfvars @@ -0,0 +1,31 @@ +# Defines the different destination for the different log profiles +# Different profiles to target different operational teams + +diagnostics_destinations = { + # Storage keys must reference the azure region name + # For storage, reference "all_regions" and we will send the logs to the storage account + # in the region of the deployment + storage = { + all_regions = { + southeastasia = { + storage_account_key = "diagsiem_region1" + } + eastasia = { + storage_account_key = "diagsiem_region2" + } + } + } + + log_analytics = { + central_logs = { + log_analytics_key = "central_logs_region1" + log_analytics_destination_type = "Dedicated" + } + } + + event_hub_namespaces = { + central_logs = { + event_hub_namespace_key = "central_logs_region1" + } + } +} diff --git a/landingzones/caf_launchpad/scenario/200/diagnostics_repositories.tfvars b/landingzones/caf_launchpad/scenario/200/diagnostics_repositories.tfvars new file mode 100644 index 00000000..9b47a009 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/diagnostics_repositories.tfvars @@ -0,0 +1,133 @@ +# Defines different repositories for the diagnostics logs +# Storage accounts, log analytics, event hubs + +diagnostic_storage_accounts = { + # Stores diagnostic logging for region1 + diaglogs_region1 = { + name = "diaglogsrg1" + region = "region1" + resource_group_key = "ops" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "LRS" + access_tier = "Cool" + } + # Stores diagnostic logging for region2 + diaglogs_region2 = { + name = "diaglogrg2" + region = "region2" + resource_group_key = "ops" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "LRS" + access_tier = "Cool" + } + # Stores security logs for siem default region" + diagsiem_region1 = { + name = "siemsg1" + resource_group_key = "siem" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "LRS" + access_tier = "Cool" + } + # Stores diagnostic logging for region2 + diagsiem_region2 = { + name = "siemrg2" + region = "region2" + resource_group_key = "siem" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "LRS" + access_tier = "Cool" + } + # Stores boot diagnostic for region1 + bootdiag_region1 = { + name = "bootrg1" + region = "region1" + resource_group_key = "ops" + account_kind = "StorageV2" + account_tier = "Standard" + account_replication_type = "LRS" + access_tier = "Cool" + } + # Stores boot diagnostic for region2 + bootdiag_region2 = { + name = "bootrg2" + region = "region2" + resource_group_key = "ops" + account_kind = "StorageV2" + account_tier = "Standard" + account_replication_type = "LRS" + access_tier = "Cool" + } +} + +# +# Define the settings for log analytics workspace and solution map +# +log_analytics = { + central_logs_region1 = { + region = "region1" + name = "logs" + resource_group_key = "ops" + # you can setup up to 5 key + diagnostic_profiles = { + central_logs_region1 = { + definition_key = "log_analytics" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + solutions_maps = { + NetworkMonitoring = { + "publisher" = "Microsoft" + "product" = "OMSGallery/NetworkMonitoring" + }, + ADAssessment = { + "publisher" = "Microsoft" + "product" = "OMSGallery/ADAssessment" + }, + ADReplication = { + "publisher" = "Microsoft" + "product" = "OMSGallery/ADReplication" + }, + AgentHealthAssessment = { + "publisher" = "Microsoft" + "product" = "OMSGallery/AgentHealthAssessment" + }, + DnsAnalytics = { + "publisher" = "Microsoft" + "product" = "OMSGallery/DnsAnalytics" + }, + ContainerInsights = { + "publisher" = "Microsoft" + "product" = "OMSGallery/ContainerInsights" + }, + KeyVaultAnalytics = { + "publisher" = "Microsoft" + "product" = "OMSGallery/KeyVaultAnalytics" + } + } + } +} + +# Event hub diagnostics +event_hub_namespaces = { + central_logs_region1 = { + name = "logs" + resource_group_key = "ops" + sku = "Standard" + region = "region1" + + diagnostic_profiles = { + central_logs_region1 = { + definition_key = "event_hub_namespace" + destination_type = "storage" + destination_key = "all_regions" + } + } + } +} + + diff --git a/landingzones/caf_launchpad/scenario/200/dynamic_secrets.tfvars b/landingzones/caf_launchpad/scenario/200/dynamic_secrets.tfvars new file mode 100644 index 00000000..1a965999 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/dynamic_secrets.tfvars @@ -0,0 +1,152 @@ + +# Store output attributes into keyvault secret +# Those values are used by the rover to connect the current remote state and +# identity the lower level +dynamic_keyvault_secrets = { + level0 = { + msi = { + output_key = "managed_identities" + resource_key = "level0" + attribute_key = "id" + secret_name = "msi-resource-id" + } + subscription_id = { + output_key = "client_config" + attribute_key = "subscription_id" + secret_name = "subscription-id" + } + tenant_id = { + output_key = "client_config" + attribute_key = "tenant_id" + secret_name = "tenant-id" + } + admin = { + secret_name = "azdo-pat-admin" + value = "" + } + agent = { + secret_name = "azdo-pat-agent" + value = "" + } + } + level1 = { + msi = { + output_key = "managed_identities" + resource_key = "level1" + attribute_key = "id" + secret_name = "msi-resource-id" + } + lower_stg = { + output_key = "storage_accounts" + resource_key = "level0" + attribute_key = "name" + secret_name = "lower-storage-account-name" + } + lower_rg = { + output_key = "resource_groups" + resource_key = "level0" + attribute_key = "name" + secret_name = "lower-resource-group-name" + } + subscription_id = { + output_key = "client_config" + attribute_key = "subscription_id" + secret_name = "subscription-id" + } + tenant_id = { + output_key = "client_config" + attribute_key = "tenant_id" + secret_name = "tenant-id" + } + } + level2 = { + msi = { + output_key = "managed_identities" + resource_key = "level2" + attribute_key = "id" + secret_name = "msi-resource-id" + } + lower_stg = { + output_key = "storage_accounts" + resource_key = "level1" + attribute_key = "name" + secret_name = "lower-storage-account-name" + } + lower_rg = { + output_key = "resource_groups" + resource_key = "level1" + attribute_key = "name" + secret_name = "lower-resource-group-name" + } + subscription_id = { + output_key = "client_config" + attribute_key = "subscription_id" + secret_name = "subscription-id" + } + tenant_id = { + output_key = "client_config" + attribute_key = "tenant_id" + secret_name = "tenant-id" + } + } + level3 = { + msi = { + output_key = "managed_identities" + resource_key = "level3" + attribute_key = "id" + secret_name = "msi-resource-id" + } + lower_stg = { + output_key = "storage_accounts" + resource_key = "level2" + attribute_key = "name" + secret_name = "lower-storage-account-name" + } + lower_rg = { + output_key = "resource_groups" + resource_key = "level2" + attribute_key = "name" + secret_name = "lower-resource-group-name" + } + subscription_id = { + output_key = "client_config" + attribute_key = "subscription_id" + secret_name = "subscription-id" + } + tenant_id = { + output_key = "client_config" + attribute_key = "tenant_id" + secret_name = "tenant-id" + } + } + level4 = { + msi = { + output_key = "managed_identities" + resource_key = "level4" + attribute_key = "id" + secret_name = "msi-resource-id" + } + lower_stg = { + output_key = "storage_accounts" + resource_key = "level3" + attribute_key = "name" + secret_name = "lower-storage-account-name" + } + lower_rg = { + output_key = "resource_groups" + resource_key = "level3" + attribute_key = "name" + secret_name = "lower-resource-group-name" + } + subscription_id = { + output_key = "client_config" + attribute_key = "subscription_id" + secret_name = "subscription-id" + } + tenant_id = { + output_key = "client_config" + attribute_key = "tenant_id" + secret_name = "tenant-id" + } + } +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/scenario/200/iam_azuread.tfvars b/landingzones/caf_launchpad/scenario/200/iam_azuread.tfvars new file mode 100644 index 00000000..d777b710 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/iam_azuread.tfvars @@ -0,0 +1,182 @@ + +azuread_groups = { + keyvault_level0_rw = { + name = "caf-level0-keyvault-rw" + description = "Provide read and write access to the keyvault secrets / level0." + members = { + user_principal_names = [ + ] + group_names = [] + object_ids = [] + group_keys = [] + + service_principal_keys = [ + "caf_launchpad_level0" + ] + + } + owners = { + user_principal_names = [ + ] + service_principal_keys = [ + "caf_launchpad_level0" + ] + } + prevent_duplicate_name = false + } + + keyvault_level1_rw = { + name = "caf-level1-landingzones-rw" + description = "Provide read and write access to manage landingzones / level1." + members = { + } + owners = { + + } + prevent_duplicate_name = false + } + + keyvault_level2_rw = { + name = "caf-level2-landingzones-rw" + description = "Provide read and write access to manage landingzones / level2." + members = { + } + owners = { + + } + prevent_duplicate_name = false + } + + keyvault_level3_rw = { + name = "caf-level3-landingzones-rw" + description = "Provide read and write access to manage landingzones / level3." + members = { + } + owners = { + + } + prevent_duplicate_name = false + } + + keyvault_level4_rw = { + name = "caf-level4-applications" + description = "Provide read access to the applications who need to deploy on the level4." + members = { + } + owners = { + + } + prevent_duplicate_name = false + } + + caf_launchpad_Reader = { + name = "caf-launchpad-Reader" + description = "Provide Reader role to the caf launchpad landing zone resource groups." + members = { + } + owners = { + + } + prevent_duplicate_name = false + } + + keyvault_password_rotation = { + name = "caf-level0-password-rotation-rw" + description = "Provide read and write access to the keyvault secrets / level0." + members = { + user_principal_names = [ + ] + group_names = [] + object_ids = [] + group_keys = [] + + service_principal_keys = [ + "caf_launchpad_level0" + ] + + } + owners = { + user_principal_names = [ + ] + service_principal_keys = [ + "caf_launchpad_level0" + ] + } + prevent_duplicate_name = false + } +} + +azuread_users = { + + # don't change that key + aad-user-devops-user-admin = { + useprefix = true + user_name = "caf-level0-security-devops-pat-rotation" + password_expire_in_days = 180 + + # Value must match with var.keyvaults[keyname] to store username and password for password rotation + keyvault_key = "secrets" + } + +} + +azuread_apps = { + # Do not rename the key "launchpad" to be able to upgrade to the standard launchpad + caf_launchpad_level0 = { + useprefix = true + application_name = "caf_launchpad_level0" + password_expire_in_days = 180 + + # Store the ${secret_prefix}-client-id, ${secret_prefix}-client-secret... + # Set the policy during the creation process of the launchpad + keyvaults = { + level0 = { + secret_prefix = "aadapp-caf-launchpad-level0" + } + } + } + +} + +# +# Available roles: +# az rest --method Get --uri https://graph.microsoft.com/v1.0/directoryRoleTemplates -o json | jq -r .value[].displayName +# +azuread_roles = { + caf_launchpad_level0 = { + roles = [ + "Application Administrator", + "Application Developer", + "User Account Administrator" + ] + } + managed_identities = { + level0 = { + roles = [ + "Directory Readers", + "Application Developer", + "User Account Administrator" + ] + } + level1 = { + roles = [ + "Directory Readers" + ] + } + level2 = { + roles = [ + "Directory Readers" + ] + } + level3 = { + roles = [ + "Directory Readers" + ] + } + level4 = { + roles = [ + "Directory Readers" + ] + } + } +} diff --git a/landingzones/caf_launchpad/scenario/200/iam_azuread_api_permissions.tfvars b/landingzones/caf_launchpad/scenario/200/iam_azuread_api_permissions.tfvars new file mode 100644 index 00000000..f73f3b73 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/iam_azuread_api_permissions.tfvars @@ -0,0 +1,43 @@ + + +azuread_api_permissions = { + + caf_launchpad_level0 = { + active_directory_graph = { + resource_app_id = "00000002-0000-0000-c000-000000000000" + resource_access = { + Application_ReadWrite_OwnedBy = { + id = "824c81eb-e3f8-4ee6-8f6d-de7f50d565b7" + type = "Role" + } + Directory_ReadWrite_All = { + id = "78c8a3c8-a07e-4b9e-af1b-b5ccab50a175" + type = "Role" + } + } + } + + microsoft_graph = { + resource_app_id = "00000003-0000-0000-c000-000000000000" + resource_access = { + AppRoleAssignment_ReadWrite_All = { + id = "06b708a9-e830-4db3-a914-8e69da51d44f" + type = "Role" + } + DelegatedPermissionGrant_ReadWrite_All = { + id = "8e8e4742-1d95-4f68-9d56-6ee75648c72a" + type = "Role" + } + GroupReadWriteAll = { + id = "62a82d76-70ea-41e2-9197-370581804d09" + type = "Role" + } + RoleManagement_ReadWrite_Directory = { + id = "9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8" + type = "Role" + } + } + } + } + +} diff --git a/landingzones/caf_launchpad/scenario/200/iam_custom_roles.tfvars b/landingzones/caf_launchpad/scenario/200/iam_custom_roles.tfvars new file mode 100644 index 00000000..f314abf3 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/iam_custom_roles.tfvars @@ -0,0 +1,76 @@ + +custom_role_definitions = { + caf-launchpad = { + name = "caf-launchpad" + useprefix = true + description = "Provide addition permissions on top of built-in Contributor role to manage landing zones deployment" + permissions = { + actions = [ + "Microsoft.Authorization/roleAssignments/delete", + "Microsoft.Authorization/roleAssignments/read", + "Microsoft.Authorization/roleAssignments/write", + "Microsoft.Authorization/roleDefinitions/delete", + "Microsoft.Authorization/roleDefinitions/read", + "Microsoft.Authorization/roleDefinitions/write", + "microsoft.insights/diagnosticSettings/delete", + "microsoft.insights/diagnosticSettings/read", + "microsoft.insights/diagnosticSettings/write", + "Microsoft.KeyVault/vaults/delete", + "Microsoft.KeyVault/vaults/read", + "Microsoft.KeyVault/vaults/write", + "Microsoft.KeyVault/vaults/accessPolicies/write", + "Microsoft.Network/networkSecurityGroups/delete", + "Microsoft.Network/networkSecurityGroups/read", + "Microsoft.Network/networkSecurityGroups/write", + "Microsoft.Network/networkSecurityGroups/join/action", + "Microsoft.Network/virtualNetworks/subnets/delete", + "Microsoft.Network/virtualNetworks/subnets/read", + "Microsoft.Network/virtualNetworks/subnets/write", + "Microsoft.OperationalInsights/workspaces/delete", + "Microsoft.OperationalInsights/workspaces/read", + "Microsoft.OperationalInsights/workspaces/write", + "Microsoft.OperationalInsights/workspaces/sharedKeys/action", + "Microsoft.OperationsManagement/solutions/delete", + "Microsoft.OperationsManagement/solutions/read", + "Microsoft.OperationsManagement/solutions/write", + "Microsoft.Storage/storageAccounts/delete", + "Microsoft.Storage/storageAccounts/read", + "Microsoft.Storage/storageAccounts/write", + "Microsoft.Storage/storageAccounts/blobServices/containers/delete", + "Microsoft.Storage/storageAccounts/blobServices/containers/read", + "Microsoft.Storage/storageAccounts/blobServices/containers/write", + "Microsoft.Storage/storageAccounts/blobServices/containers/lease/action", + "Microsoft.Storage/storageAccounts/blobServices/read", + "Microsoft.Storage/storageAccounts/listKeys/action", + "Microsoft.Resources/subscriptions/providers/read", + "Microsoft.Resources/subscriptions/read", + "Microsoft.Resources/subscriptions/resourcegroups/delete", + "Microsoft.Resources/subscriptions/resourcegroups/read", + "Microsoft.Resources/subscriptions/resourcegroups/write", + "Microsoft.Network/virtualNetworks/delete", + "Microsoft.Network/virtualNetworks/read", + "Microsoft.Network/virtualNetworks/write", + ] + } + + } + + caf-launchpad-contributor = { + name = "caf-launchpad-contributor" + useprefix = true + description = "Provide addition permissions on top of built-in Contributor role to manage landing zones deployment" + permissions = { + actions = [ + "Microsoft.Authorization/roleAssignments/delete", + "Microsoft.Authorization/roleAssignments/read", + "Microsoft.Authorization/roleAssignments/write", + "Microsoft.Authorization/roleDefinitions/delete", + "Microsoft.Authorization/roleDefinitions/read", + "Microsoft.Authorization/roleDefinitions/write", + "Microsoft.Resources/subscriptions/providers/read" + ] + } + } + +} + diff --git a/landingzones/caf_launchpad/scenario/200/iam_keyvault_policies.tfvars b/landingzones/caf_launchpad/scenario/200/iam_keyvault_policies.tfvars new file mode 100644 index 00000000..e755b1eb --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/iam_keyvault_policies.tfvars @@ -0,0 +1,114 @@ +keyvault_access_policies_azuread_apps = { + level0 = { + caf_launchpad_level0 = { + # Reference a key to an azure ad applications + azuread_app_key = "caf_launchpad_level0" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + # A maximum of 16 access policies per keyvault + level1 = { + caf_launchpad_level0 = { + # Reference a key to an azure ad applications + azuread_app_key = "caf_launchpad_level0" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + # A maximum of 16 access policies per keyvault + level2 = { + caf_launchpad_level0 = { + # Reference a key to an azure ad applications + azuread_app_key = "caf_launchpad_level0" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + + # A maximum of 16 access policies per keyvault + level3 = { + caf_launchpad_level0 = { + # Reference a key to an azure ad applications + azuread_app_key = "caf_launchpad_level0" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + + # A maximum of 16 access policies per keyvault + level4 = { + caf_launchpad_level1 = { + # Reference a key to an azure ad applications + azuread_app_key = "caf_launchpad_level0" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + + secrets = { + caf_launchpad_level0 = { + azuread_app_key = "caf_launchpad_level0" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } +} + +keyvault_access_policies = { + # A maximum of 16 access policies per keyvault + level0 = { + keyvault_level0_rw = { + # Reference a key to an azure ad group + azuread_group_key = "keyvault_level0_rw" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + # A maximum of 16 access policies per keyvault + level1 = { + keyvault_level1_rw = { + # Reference a key to an azure ad group + azuread_group_key = "keyvault_level1_rw" + secret_permissions = ["Get", "List"] + } + } + + # A maximum of 16 access policies per keyvault + level2 = { + keyvault_level2_rw = { + # Reference a key to an azure ad group + azuread_group_key = "keyvault_level2_rw" + secret_permissions = ["Get", "List"] + } + } + + + # A maximum of 16 access policies per keyvault + level3 = { + keyvault_level3_rw = { + # Reference a key to an azure ad group + azuread_group_key = "keyvault_level3_rw" + secret_permissions = ["Get", "List"] + } + } + + + # A maximum of 16 access policies per keyvault + level4 = { + keyvault_level4_rw = { + # Reference a key to an azure ad group + azuread_group_key = "keyvault_level4_rw" + secret_permissions = ["Get", "List"] + } + } + + + secrets = { + keyvault_level0_rw = { + azuread_group_key = "keyvault_level0_rw" + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + keyvault_password_rotation = { + azuread_group_key = "keyvault_password_rotation" + secret_permissions = ["Set", "Get", "List", "Delete", ] + } + } +} diff --git a/landingzones/caf_launchpad/scenario/200/iam_managed_identities.tfvars b/landingzones/caf_launchpad/scenario/200/iam_managed_identities.tfvars new file mode 100644 index 00000000..a5e76137 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/iam_managed_identities.tfvars @@ -0,0 +1,32 @@ + +managed_identities = { + level0 = { + # Used by the release agent to access the level0 keyvault and storage account with the tfstates in read / write + name = "landingzone-level0-msi" + resource_group_key = "security" + } + level1 = { + # Used by the release agent to access the level1 keyvault and storage account with the tfstates in read / write + # Has read access to level0 + name = "landingzone-level1-msi" + resource_group_key = "security" + } + level2 = { + # Used by the release agent to access the level2 keyvault and storage account with the tfstates in read / write + # Has read access to level1 + name = "landingzone-level2-msi" + resource_group_key = "security" + } + level3 = { + # Used by the release agent to access the level3 keyvault and storage account with the tfstates in read / write + # Has read access to level2 + name = "landingzone-level3-msi" + resource_group_key = "security" + } + level4 = { + # Used by the release agent to access the level4 keyvault and storage account with the tfstates in read / write + # Has read access to level3 + name = "landingzone-level4-msi" + resource_group_key = "security" + } +} diff --git a/landingzones/caf_launchpad/scenario/200/iam_role_mapping.tfvars b/landingzones/caf_launchpad/scenario/200/iam_role_mapping.tfvars new file mode 100644 index 00000000..23a919f2 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/iam_role_mapping.tfvars @@ -0,0 +1,154 @@ + +# +# Services supported: subscriptions, storage accounts and resource groups +# Can assign roles to: AD groups, AD object ID, AD applications, Managed identities +# +role_mapping = { + custom_role_mapping = { + subscriptions = { + logged_in_subscription = { + "caf-launchpad-contributor" = { + azuread_groups = { + keys = ["keyvault_level0_rw", "keyvault_level1_rw", "keyvault_level2_rw", "keyvault_level3_rw", "keyvault_level4_rw", ] + } + managed_identities = { + keys = ["level0", "level1", "level2", "level3", "level4"] + } + azuread_apps = { + keys = ["caf_launchpad_level0"] + } + } + } + } + } + + built_in_role_mapping = { + subscriptions = { + logged_in_subscription = { + "Contributor" = { + azuread_apps = { + keys = ["caf_launchpad_level0"] + } + managed_identities = { + keys = ["level0", "level1", "level2", "level3", "level4"] + } + } + } + } + resource_groups = { + level0 = { + "Reader" = { + azuread_groups = { + keys = ["caf_launchpad_Reader"] + } + } + } + security = { + "Reader" = { + azuread_groups = { + keys = ["caf_launchpad_Reader"] + } + } + } + networking = { + "Reader" = { + azuread_groups = { + keys = ["caf_launchpad_Reader"] + } + } + } + ops = { + "Reader" = { + azuread_groups = { + keys = ["caf_launchpad_Reader"] + } + } + } + siem = { + "Reader" = { + azuread_groups = { + keys = ["caf_launchpad_Reader"] + } + } + } + } + storage_accounts = { + level0 = { + "Storage Blob Data Contributor" = { + logged_in = { + keys = ["user"] + } + azuread_groups = { + keys = ["keyvault_level0_rw"] + } + azuread_apps = { + keys = ["caf_launchpad_level0"] + } + managed_identities = { + keys = ["level0"] + } + } + "Storage Blob Data Reader" = { + azuread_groups = { + keys = ["keyvault_level1_rw"] + } + } + } + level1 = { + "Storage Blob Data Contributor" = { + logged_in = { + keys = ["user"] + } + azuread_groups = { + keys = ["keyvault_level1_rw"] + } + managed_identities = { + keys = ["level1"] + } + } + "Storage Blob Data Reader" = { + azuread_groups = { + keys = ["keyvault_level2_rw"] + } + } + } + level2 = { + "Storage Blob Data Contributor" = { + logged_in = { + keys = ["user"] + } + azuread_groups = { + keys = ["keyvault_level2_rw"] + } + managed_identities = { + keys = ["level2"] + } + } + "Storage Blob Data Reader" = { + azuread_groups = { + keys = ["keyvault_level3_rw"] + } + } + } + level3 = { + "Storage Blob Data Contributor" = { + logged_in = { + keys = ["user"] + } + azuread_groups = { + keys = ["keyvault_level3_rw"] + } + managed_identities = { + keys = ["level3"] + } + } + "Storage Blob Data Reader" = { + azuread_groups = { + keys = ["keyvault_level4_rw"] + } + } + } + } + } + +} diff --git a/landingzones/caf_launchpad/scenario/200/keyvaults.tfvars b/landingzones/caf_launchpad/scenario/200/keyvaults.tfvars new file mode 100644 index 00000000..9b407a31 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/keyvaults.tfvars @@ -0,0 +1,204 @@ + +keyvaults = { + level0 = { + name = "level0" + resource_group_key = "level0" + sku_name = "standard" + soft_delete_enabled = true + tags = { + tfstate = "level0" + environment = "sandpit" + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "default_all" + destination_type = "log_analytics" + destination_key = "central_logs" + } + siem = { + definition_key = "siem_all" + destination_type = "storage" + destination_key = "all_regions" + } + } + + } + + level1 = { + name = "level1" + resource_group_key = "level1" + sku_name = "standard" + soft_delete_enabled = true + tags = { + tfstate = "level1" + environment = "sandpit" + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "default_all" + destination_type = "log_analytics" + destination_key = "central_logs" + } + siem = { + definition_key = "siem_all" + destination_type = "storage" + destination_key = "all_regions" + } + } + + } + + level2 = { + name = "level2" + resource_group_key = "level2" + sku_name = "standard" + soft_delete_enabled = true + tags = { + tfstate = "level2" + environment = "sandpit" + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "default_all" + destination_type = "log_analytics" + destination_key = "central_logs" + } + siem = { + definition_key = "siem_all" + destination_type = "storage" + destination_key = "all_regions" + } + } + + } + + level3 = { + name = "level3" + resource_group_key = "level3" + sku_name = "standard" + soft_delete_enabled = true + tags = { + tfstate = "level3" + environment = "sandpit" + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "default_all" + destination_type = "log_analytics" + destination_key = "central_logs" + } + siem = { + definition_key = "siem_all" + destination_type = "storage" + destination_key = "all_regions" + } + } + + } + + level4 = { + name = "level4" + resource_group_key = "level4" + sku_name = "standard" + soft_delete_enabled = true + tags = { + tfstate = "level4" + environment = "sandpit" + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "default_all" + destination_type = "log_analytics" + destination_key = "central_logs" + } + siem = { + definition_key = "siem_all" + destination_type = "storage" + destination_key = "all_regions" + } + } + + } + + secrets = { + name = "secrets" + resource_group_key = "security" + region = "region1" + sku_name = "premium" + soft_delete_enabled = true + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "default_all" + destination_type = "log_analytics" + destination_key = "central_logs" + } + siem = { + definition_key = "siem_all" + destination_type = "storage" + destination_key = "all_regions" + } + } + + creation_policies = { + logged_in_user = { + # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy + # More examples in /examples/keyvault + secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"] + } + } + + + } +} diff --git a/landingzones/caf_launchpad/scenario/200/networking.tfvars b/landingzones/caf_launchpad/scenario/200/networking.tfvars new file mode 100644 index 00000000..e21c316f --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/networking.tfvars @@ -0,0 +1,110 @@ + +################################################## +# +# Networking resources +# +################################################## + + +public_ip_addresses = { + bastion_host_rg1 = { + name = "pip1" + resource_group_key = "networking" + sku = "Standard" + allocation_method = "Static" + ip_version = "IPv4" + idle_timeout_in_minutes = "4" + + # you can setup up to 5 key + diagnostic_profiles = { + bastion_host_rg1 = { + definition_key = "public_ip_address" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + + } +} + +vnets = { + devops_region1 = { + resource_group_key = "networking" + region = "region1" + vnet = { + name = "devops" + address_space = ["10.100.100.0/24"] + } + specialsubnets = {} + subnets = { + AzureBastionSubnet = { + name = "AzureBastionSubnet" #Must be called AzureBastionSubnet + cidr = ["10.100.100.24/29"] + nsg_key = "azure_bastion_nsg" + } + jumpbox = { + name = "jumpbox" + cidr = ["10.100.100.32/29"] + service_endpoints = ["Microsoft.KeyVault"] + } + release_agent_level0 = { + name = "level0" + cidr = ["10.100.100.40/29"] + service_endpoints = ["Microsoft.KeyVault"] + } + release_agent_level1 = { + name = "level1" + cidr = ["10.100.100.48/29"] + service_endpoints = ["Microsoft.KeyVault"] + } + release_agent_level2 = { + name = "level2" + cidr = ["10.100.100.56/29"] + service_endpoints = ["Microsoft.KeyVault"] + } + release_agent_level3 = { + name = "level3" + cidr = ["10.100.100.64/29"] + service_endpoints = ["Microsoft.KeyVault"] + } + release_agent_level4 = { + name = "level4" + cidr = ["10.100.100.72/29"] + service_endpoints = ["Microsoft.KeyVault"] + } + private_endpoints = { + name = "private_endpoints" + cidr = ["10.100.100.128/25"] + enforce_private_link_endpoint_network_policies = true + } + } + + # you can setup up to 5 keys - vnet diganostic + diagnostic_profiles = { + vnet = { + definition_key = "networking_all" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + + } +} + + +route_tables = { + default_no_internet = { + name = "default_no_internet" + resource_group_key = "networking" + } +} + +azurerm_routes = { + no_internet = { + name = "no_internet" + resource_group_key = "networking" + route_table_key = "default_no_internet" + address_prefix = "0.0.0.0/0" + next_hop_type = "None" + } +} diff --git a/landingzones/caf_launchpad/scenario/200/networking_nsg_definition.tfvars b/landingzones/caf_launchpad/scenario/200/networking_nsg_definition.tfvars new file mode 100644 index 00000000..8b558b10 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/networking_nsg_definition.tfvars @@ -0,0 +1,141 @@ + +# +# Definition of the networking security groups +# +network_security_group_definition = { + # This entry is applied to all subnets with no NSG defined + empty_nsg = { + + diagnostic_profiles = { + nsg = { + definition_key = "network_security_group" + destination_type = "storage" + destination_key = "all_regions" + } + operations = { + name = "operations" + definition_key = "network_security_group" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + } + + azure_bastion_nsg = { + + diagnostic_profiles = { + nsg = { + definition_key = "network_security_group" + destination_type = "storage" + destination_key = "all_regions" + } + operations = { + name = "operations" + definition_key = "network_security_group" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + + nsg = [ + { + name = "bastion-in-allow", + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "bastion-control-in-allow-443", + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "135" + source_address_prefix = "GatewayManager" + destination_address_prefix = "*" + }, + { + name = "Kerberos-password-change", + priority = "121" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "4443" + source_address_prefix = "GatewayManager" + destination_address_prefix = "*" + }, + { + name = "bastion-vnet-out-allow-22", + priority = "103" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "bastion-vnet-out-allow-3389", + priority = "101" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "3389" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "bastion-azure-out-allow", + priority = "120" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "AzureCloud" + } + ] + } + + jumphost = { + + diagnostic_profiles = { + nsg = { + definition_key = "network_security_group" + destination_type = "storage" + destination_key = "all_regions" + } + operations = { + name = "operations" + definition_key = "network_security_group" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + + nsg = [ + { + name = "ssh-inbound-22", + priority = "200" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + ] + } + +} diff --git a/landingzones/caf_launchpad/scenario/200/readme.md b/landingzones/caf_launchpad/scenario/200/readme.md new file mode 100644 index 00000000..82f7b444 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/readme.md @@ -0,0 +1,56 @@ +# Launchpad - scenario 200 + +The 200 scenario is an extension of the 100 scenario, meaning you can upgrade a 100 scenario to a 200. +The 200 scenario is designed to demonstrate a more secure environment but is not recommended for production use. +The focus of this scenario is to be able to deploy a more advanced launchpad from a remote machine and use the portal to review the settings in a non-constrained environment. +For example in this scenario you can go to the Key Vaults and view the secrets from the portal. A feature that is disabled in the 300+ scenarios. We recommend using the 200 scenario for demonstration or building new capabilities. + +An estimated time of 20 minutes is required to deploy this scenario. + +## Pre-requisites + +This scenario require the following privileges: + +| Component | Privileges | +|--------------------|--------------------------------| +| Active Directory | Application Administrator role | +| Azure subscription | Subscription owner | + +## Deployment + +```bash +rover -lz /tf/caf/landingzones/caf_launchpad \ + -launchpad \ + -var-folder /tf/caf/landingzones/caf_launchpad/scenario/200 \ + -level level0 \ + -a apply + +rover -lz /tf/caf/landingzones/caf_launchpad \ + -launchpad \ + -var-folder /tf/caf/landingzones/caf_launchpad/scenario/200 \ + -level level0 \ + -a destroy +``` + +## Architecture diagram + +![Launchpad 200](../../documentation/img/launchpad-200.png) + +## Services deployed in this scenario + +| Component | Purpose | +|--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Resource group | Multiple resource groups are created to isolate the services | +| Storage account | A storage account for remote tfstate management is provided for each level of the framework. Additional storage accounts are created for diagnostic logs. | +| Keyvault | The launchpad keyvault hosts all secrets required by the rover to access the remote states. The secret keyvault is used to host all Azure AD users, applications and virtual machines's ssh key. | +| Virtual network | To secure the communication between the services a dedicated virtual network is deployed with a gateway subnet, bastion service, jumpbox and azure DevOps release agents. Service endpoints is enabled but not configured. | +| Bastion host service | Is use to support the access to the rover in scenario 300 and 400. | +| Jumpbox | A Linux server with the docker engine to run the rover and perform the deployment of the scenario 300 and 400. | +| Log analytics | A central log analytics workspace is created to collect all diagnostics and metrics information. Solutions are also deployed. | +| Diagnostic profiles | Default settings with 7 days retention of diagnostic profile is provided for all services. | +| Diagnostic destination | Operation sends the logs to a log analytics workspace and SIEM send all security logs to a storage account. | +| Diagnostic | Is enabled by default on all services. | +| Azure AD Users | An Azure AD user is created. This user is used in scenario 300 and 400 to own the Azure DevOps Personal Access Token (PAT) rotation. | +| Azure AD Applications | An Azure AD application is created. This account is mainly use to bootstrap the services during the initialization. It is also considered as a breakglass account for the launchpad landing zones. | +| Azure AD API permissions | A set of API permissions assigned to the Azure AD application to support management of the landing zones in a pipeline. | +| Managed Identities | A user managed Identity account is created for each Azure DevOps agent. This account is configured to get access to the keyvaults and Azure storage accounts | \ No newline at end of file diff --git a/landingzones/caf_launchpad/scenario/200/storage_accounts.tfvars b/landingzones/caf_launchpad/scenario/200/storage_accounts.tfvars new file mode 100644 index 00000000..bd60a50f --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/storage_accounts.tfvars @@ -0,0 +1,101 @@ + +storage_accounts = { + level0 = { + name = "level0" + resource_group_key = "level0" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "RAGRS" + tags = { + ## Those tags must never be changed after being set as they are used by the rover to locate the launchpad and the tfstates. + # Only adjust the environment value at creation time + tfstate = "level0" + environment = "sandpit" + launchpad = "launchpad" + ## + } + containers = { + tfstate = { + name = "tfstate" + } + } + } + + level1 = { + name = "level1" + resource_group_key = "level1" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "RAGRS" + tags = { + # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates. + tfstate = "level1" + environment = "sandpit" + launchpad = "launchpad" + } + containers = { + tfstate = { + name = "tfstate" + } + } + } + + level2 = { + name = "level2" + resource_group_key = "level2" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "RAGRS" + tags = { + # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates. + tfstate = "level2" + environment = "sandpit" + launchpad = "launchpad" + } + containers = { + tfstate = { + name = "tfstate" + } + } + } + + level3 = { + name = "level3" + resource_group_key = "level3" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "RAGRS" + tags = { + # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates. + tfstate = "level3" + environment = "sandpit" + launchpad = "launchpad" + } + containers = { + tfstate = { + name = "tfstate" + } + } + } + + level4 = { + name = "level4" + resource_group_key = "level4" + account_kind = "BlobStorage" + account_tier = "Standard" + account_replication_type = "RAGRS" + tags = { + # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates. + tfstate = "level4" + environment = "sandpit" + launchpad = "launchpad" + } + containers = { + tfstate = { + name = "tfstate" + } + } + + } + +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/scenario/200/subscriptions.tfvars b/landingzones/caf_launchpad/scenario/200/subscriptions.tfvars new file mode 100644 index 00000000..9e98ae77 --- /dev/null +++ b/landingzones/caf_launchpad/scenario/200/subscriptions.tfvars @@ -0,0 +1,20 @@ + +subscriptions = { + logged_in_subscription = { + + # you can setup up to 5 profiles + diagnostic_profiles = { + operations = { + definition_key = "subscription_operations" + destination_type = "log_analytics" + destination_key = "central_logs" + } + siem = { + definition_key = "subscription_siem" + destination_type = "storage" + destination_key = "all_regions" + } + } + + } +} \ No newline at end of file diff --git a/landingzones/caf_launchpad/scripts/cloud-init-install-rover-tools.config b/landingzones/caf_launchpad/scripts/cloud-init-install-rover-tools.config new file mode 100644 index 00000000..53cd432e --- /dev/null +++ b/landingzones/caf_launchpad/scripts/cloud-init-install-rover-tools.config @@ -0,0 +1,49 @@ +#cloud-config + +apt: + preserve_sources_list: true + sources: + azure-cli.list: + source: "deb https://packages.microsoft.com/repos/azure-cli/ bionic main" + key: | + -----BEGIN PGP PUBLIC KEY BLOCK----- + Version: GnuPG v1.4.7 (GNU/Linux) + + mQENBFYxWIwBCADAKoZhZlJxGNGWzqV+1OG1xiQeoowKhssGAKvd+buXCGISZJwT + LXZqIcIiLP7pqdcZWtE9bSc7yBY2MalDp9Liu0KekywQ6VVX1T72NPf5Ev6x6DLV + 7aVWsCzUAF+eb7DC9fPuFLEdxmOEYoPjzrQ7cCnSV4JQxAqhU4T6OjbvRazGl3ag + OeizPXmRljMtUUttHQZnRhtlzkmwIrUivbfFPD+fEoHJ1+uIdfOzZX8/oKHKLe2j + H632kvsNzJFlROVvGLYAk2WRcLu+RjjggixhwiB+Mu/A8Tf4V6b+YppS44q8EvVr + M+QvY7LNSOffSO6Slsy9oisGTdfE39nC7pVRABEBAAG0N01pY3Jvc29mdCAoUmVs + ZWFzZSBzaWduaW5nKSA8Z3Bnc2VjdXJpdHlAbWljcm9zb2Z0LmNvbT6JATUEEwEC + AB8FAlYxWIwCGwMGCwkIBwMCBBUCCAMDFgIBAh4BAheAAAoJEOs+lK2+EinPGpsH + /32vKy29Hg51H9dfFJMx0/a/F+5vKeCeVqimvyTM04C+XENNuSbYZ3eRPHGHFLqe + MNGxsfb7C7ZxEeW7J/vSzRgHxm7ZvESisUYRFq2sgkJ+HFERNrqfci45bdhmrUsy + 7SWw9ybxdFOkuQoyKD3tBmiGfONQMlBaOMWdAsic965rvJsd5zYaZZFI1UwTkFXV + KJt3bp3Ngn1vEYXwijGTa+FXz6GLHueJwF0I7ug34DgUkAFvAs8Hacr2DRYxL5RJ + XdNgj4Jd2/g6T9InmWT0hASljur+dJnzNiNCkbn9KbX7J/qK1IbR8y560yRmFsU+ + NdCFTW7wY0Fb1fWJ+/KTsC4= + =J6gs + -----END PGP PUBLIC KEY BLOCK----- +package_update: true + +packages: + - ca-certificates + - curl + - apt-transport-https + - lsb-release + - azure-cli + +snap: + commands: + - snap install kubectl --classic +# Install docker and docker-compose +runcmd: + - [ sh, -c, 'curl -sSL https://get.docker.com/ | sh' ] + - [ sh, -c, 'curl -L https://github.com/docker/compose/releases/download/$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep "tag_name" | cut -d \" -f4)/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose' ] + - [ sh, -c, 'sudo chmod +x /usr/local/bin/docker-compose' ] + +# Add default auto created user to docker group +system_info: + default_user: + groups: [docker] \ No newline at end of file diff --git a/landingzones/launchpad/scripts/grant_consent.sh b/landingzones/caf_launchpad/scripts/grant_consent.sh similarity index 95% rename from landingzones/launchpad/scripts/grant_consent.sh rename to landingzones/caf_launchpad/scripts/grant_consent.sh index 29266d98..620e1848 100644 --- a/landingzones/launchpad/scripts/grant_consent.sh +++ b/landingzones/caf_launchpad/scripts/grant_consent.sh @@ -12,7 +12,7 @@ if [ ${user_type} == "user" ]; then else resourceId=$(az ad sp show --id "${resourceAppId}" --query "objectId" -o tsv) - echo " -resourceId: ${resourceId}" + echo " -resourceId: ${resourceId}" URI=$(echo "https://graph.microsoft.com/beta/servicePrincipals/${resourceId}/appRoleAssignments") && echo " - uri: $URI" diff --git a/landingzones/caf_launchpad/variables.tf b/landingzones/caf_launchpad/variables.tf new file mode 100644 index 00000000..b2440c01 --- /dev/null +++ b/landingzones/caf_launchpad/variables.tf @@ -0,0 +1,182 @@ +# Map of the current tfstate +variable tfstate_storage_account_name { + default = null +} +variable tfstate_container_name { + default = null +} +variable tfstate_key { + default = null +} +variable tfstate_resource_group_name { + default = null +} + +variable tenant_id {} +variable landingzone { + description = "The landing zone name is used to reference the tfstate in configuration files. Therefore while set it is recommended not to change" +} + +variable passthrough { + default = false +} +variable random_length { + default = null +} + +variable inherit_tags { + default = false +} + +variable default_region { + description = "Define the default region where services are deployed if the location is not set at the resource level" + default = "region1" +} + +variable regions { + type = map + description = "List of the regions where services can be deployed. This impact the diagnostics logs settings" + default = { + region1 = "southeastasia" + } +} + +variable enable { + description = "Map of services defined in the configuration file you want to disable during a deployment" + default = {} +} + +variable prefix { + default = null +} + +variable log_analytics { + default = {} +} + +variable event_hub_namespaces { + default = {} +} + +# Do not change the default value to be able to upgrade to the standard launchpad +variable tf_name { + description = "Name of the terraform state in the blob storage (Does not include the extension .tfstate). Setup by the rover. Leave empty in the configuration file" + default = "" +} + +variable resource_groups {} + +variable storage_accounts {} +variable diagnostic_storage_accounts { + default = {} +} + +variable keyvaults {} +variable keyvault_access_policies { + default = {} +} +variable dynamic_keyvault_secrets {} + +variable subscriptions { + default = {} +} + +## Azure Active Directory +variable azuread_apps { + default = {} +} +variable azuread_groups { + default = {} +} +variable azuread_users { + default = {} +} +variable azuread_roles { + default = {} +} +variable managed_identities { + default = {} +} + +variable virtual_machines { + description = "Virtual machine object" + default = {} +} + +variable bastion_hosts { + default = {} +} + +variable launchpad_key_names {} + +variable custom_role_definitions { + default = {} +} +variable role_mapping { + default = { + built_in_role_mapping = {} + custom_role_mapping = {} + } +} + +variable tags { + type = map + default = {} +} + +variable rover_version {} + +variable user_type {} + +variable logged_user_objectId { + default = null +} +variable logged_aad_app_objectId { + default = null +} + +variable aad_users { + default = {} +} + +variable aad_roles { + default = {} +} + +variable azuread_api_permissions { + default = {} +} + +variable environment { + type = string + description = "This variable is set by the rover during the deployment based on the -env or -environment flags. Default to sandpit" +} + +variable diagnostics_definition { + default = {} +} +variable diagnostics_destinations { + default = {} +} + +variable vnets { + default = {} +} + +variable network_security_group_definition { + default = {} +} + +variable public_ip_addresses { + default = {} +} +variable route_tables { + default = {} +} +variable azurerm_routes { + default = {} +} + +variable keyvault_access_policies_azuread_apps { + default = {} +} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops/backend.azurerm.tf b/landingzones/caf_networking/backend.azurerm similarity index 91% rename from landingzones/launchpad/add-ons/azure_devops/backend.azurerm.tf rename to landingzones/caf_networking/backend.azurerm index 31805def..5d026b23 100644 --- a/landingzones/launchpad/add-ons/azure_devops/backend.azurerm.tf +++ b/landingzones/caf_networking/backend.azurerm @@ -1,4 +1,4 @@ -terraform { - backend "azurerm" { - } +terraform { + backend "azurerm" { + } } \ No newline at end of file diff --git a/landingzones/caf_networking/documentation/img/100-single-region-hub.png b/landingzones/caf_networking/documentation/img/100-single-region-hub.png new file mode 100644 index 00000000..48aac6a4 Binary files /dev/null and b/landingzones/caf_networking/documentation/img/100-single-region-hub.png differ diff --git a/landingzones/caf_networking/documentation/img/101-multi-region-hub.png b/landingzones/caf_networking/documentation/img/101-multi-region-hub.png new file mode 100644 index 00000000..48f2cd59 Binary files /dev/null and b/landingzones/caf_networking/documentation/img/101-multi-region-hub.png differ diff --git a/landingzones/caf_networking/documentation/img/105-hub-and-spoke.png b/landingzones/caf_networking/documentation/img/105-hub-and-spoke.png new file mode 100644 index 00000000..93a665fd Binary files /dev/null and b/landingzones/caf_networking/documentation/img/105-hub-and-spoke.png differ diff --git a/landingzones/caf_networking/documentation/img/106-hub-virtual-wan-firewall.png b/landingzones/caf_networking/documentation/img/106-hub-virtual-wan-firewall.png new file mode 100644 index 00000000..021a80d9 Binary files /dev/null and b/landingzones/caf_networking/documentation/img/106-hub-virtual-wan-firewall.png differ diff --git a/landingzones/caf_networking/landingzone.tf b/landingzones/caf_networking/landingzone.tf new file mode 100644 index 00000000..5fb725af --- /dev/null +++ b/landingzones/caf_networking/landingzone.tf @@ -0,0 +1,54 @@ +module "networking" { + source = "aztfmod/caf/azurerm" + version = "~> 0.4" + + current_landingzone_key = var.landingzone.key + tags = local.tags + diagnostics = local.diagnostics + global_settings = local.global_settings + tfstates = local.tfstates + tenant_id = var.tenant_id + logged_user_objectId = var.logged_user_objectId + logged_aad_app_objectId = var.logged_aad_app_objectId + resource_groups = var.resource_groups + keyvaults = var.keyvaults + keyvault_access_policies = var.keyvault_access_policies + networking = { + application_gateways = var.application_gateways + application_gateway_applications = var.application_gateway_applications + vnets = var.vnets + vnet_peerings = var.vnet_peerings + vhub_peerings = var.vhub_peerings + network_security_group_definition = var.network_security_group_definition + azurerm_firewall_network_rule_collection_definition = var.azurerm_firewall_network_rule_collection_definition + azurerm_firewall_application_rule_collection_definition = var.azurerm_firewall_application_rule_collection_definition + azurerm_firewall_nat_rule_collection_definition = var.azurerm_firewall_nat_rule_collection_definition + azurerm_firewalls = var.azurerm_firewalls + public_ip_addresses = var.public_ip_addresses + route_tables = var.route_tables + azurerm_routes = var.azurerm_routes + virtual_wans = var.virtual_wans + ddos_services = var.ddos_services + private_dns = var.private_dns + } + compute = { + virtual_machines = var.virtual_machines + bastion_hosts = var.bastion_hosts + azure_container_registries = var.azure_container_registries + } + storage_accounts = var.storage_accounts + managed_identities = var.managed_identities + + remote_objects = { + azuread_groups = local.remote.azuread_groups + managed_identities = local.remote.managed_identities + vnets = local.remote.vnets + azurerm_firewalls = local.remote.azurerm_firewalls + virtual_wans = local.remote.virtual_wans + private_dns = local.remote.private_dns + application_gateways = local.remote.application_gateways + application_gateway_applications = local.remote.application_gateway_applications + public_ip_addresses = local.remote.public_ip_addresses + } + +} diff --git a/landingzones/caf_networking/locals.remote_tfstates.tf b/landingzones/caf_networking/locals.remote_tfstates.tf new file mode 100644 index 00000000..4bb6fb2a --- /dev/null +++ b/landingzones/caf_networking/locals.remote_tfstates.tf @@ -0,0 +1,86 @@ +locals { + landingzone = { + current = { + storage_account_name = var.tfstate_storage_account_name + container_name = var.tfstate_container_name + resource_group_name = var.tfstate_resource_group_name + } + lower = { + storage_account_name = var.lower_storage_account_name + container_name = var.lower_container_name + resource_group_name = var.lower_resource_group_name + } + } +} + +data "terraform_remote_state" "remote" { + for_each = try(var.landingzone.tfstates, {}) + + backend = var.landingzone.backend_type + config = { + storage_account_name = local.landingzone[try(each.value.level, "current")].storage_account_name + container_name = local.landingzone[try(each.value.level, "current")].container_name + resource_group_name = local.landingzone[try(each.value.level, "current")].resource_group_name + key = each.value.tfstate + } +} + +locals { + landingzone_tag = { + "landingzone" = var.landingzone.key + } + + tags = merge(var.tags, local.landingzone_tag, { "level" = var.landingzone.level }, { "environment" = local.global_settings.environment }, { "rover_version" = var.rover_version }) + + global_settings = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.global_settings + + diagnostics = { + diagnostics_definition = merge(data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.diagnostics_definition, var.diagnostics_definition) + diagnostics_destinations = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.diagnostics_destinations + storage_accounts = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.storage_accounts + log_analytics = data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.diagnostics.log_analytics + } + + + remote = { + managed_identities = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.managed_identities[key], {})) + } + azuread_groups = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.azuread_groups[key], {})) + } + vnets = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.vnets[key], {})) + } + azurerm_firewalls = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.azurerm_firewalls[key], {})) + } + virtual_wans = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.virtual_wans[key], {})) + } + private_dns = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.private_dns[key], {})) + } + application_gateways = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.application_gateways[key], {})) + } + application_gateway_applications = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.application_gateway_applications[key], {})) + } + public_ip_addresses = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.public_ip_addresses[key], {})) + } + } + + + combined = { + vnets = merge(local.remote.vnets, map(var.landingzone.key, module.networking.vnets)) + azurerm_firewalls = merge(local.remote.azurerm_firewalls, map(var.landingzone.key, module.networking.azurerm_firewalls)) + public_ip_addresses = merge(local.remote.public_ip_addresses, map(var.landingzone.key, module.networking.public_ip_addresses)) + virtual_wans = merge(local.remote.virtual_wans, map(var.landingzone.key, module.networking.virtual_wans)) + private_dns = merge(local.remote.private_dns, map(var.landingzone.key, module.networking.private_dns)) + application_gateways = merge(local.remote.application_gateways, map(var.landingzone.key, module.networking.application_gateways)) + application_gateway_applications = merge(local.remote.application_gateway_applications, map(var.landingzone.key, module.networking.application_gateway_applications)) + } + +} diff --git a/landingzones/caf_networking/main.tf b/landingzones/caf_networking/main.tf new file mode 100644 index 00000000..101baa5a --- /dev/null +++ b/landingzones/caf_networking/main.tf @@ -0,0 +1,66 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 2.32.0" + } + azuread = { + source = "hashicorp/azuread" + version = "~> 1.0.0" + } + random = { + source = "hashicorp/random" + version = "~> 2.2.1" + } + external = { + source = "hashicorp/external" + version = "~> 1.2.0" + } + null = { + source = "hashicorp/null" + version = "~> 2.1.0" + } + tls = { + source = "hashicorp/tls" + version = "~> 2.2.0" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~>1.1.0" + } + } + required_version = ">= 0.13" +} + + +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + } + } +} + +data "azurerm_client_config" "current" {} + + +locals { + + # Update the tfstates map + tfstates = merge( + map(var.landingzone.key, + map( + "storage_account_name", var.tfstate_storage_account_name, + "container_name", var.tfstate_container_name, + "resource_group_name", var.tfstate_resource_group_name, + "key", var.tfstate_key, + "level", var.landingzone.level, + "tenant_id", var.tenant_id, + "subscription_id", data.azurerm_client_config.current.subscription_id + ) + ) + , + data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.tfstates + ) + +} \ No newline at end of file diff --git a/landingzones/caf_networking/output.tf b/landingzones/caf_networking/output.tf new file mode 100644 index 00000000..8b897ab6 --- /dev/null +++ b/landingzones/caf_networking/output.tf @@ -0,0 +1,49 @@ +output tfstates { + value = local.tfstates + sensitive = false +} + +output vnets { + value = local.combined.vnets + sensitive = false +} + +output azurerm_firewalls { + value = local.combined.azurerm_firewalls + sensitive = true +} + +output virtual_wans { + value = local.combined.virtual_wans + sensitive = true + description = "Virtual WAN output" +} + +output private_dns { + value = local.combined.private_dns + sensitive = true +} + +output application_gateways { + value = local.combined.application_gateways + sensitive = true +} + +output application_gateway_applications { + value = local.combined.application_gateway_applications + sensitive = true +} + +output public_ip_addresses { + value = local.combined.public_ip_addresses + sensitive = true +} + +output managed_identities { + value = local.remote.managed_identities + sensitive = true +} +output azuread_groups { + value = local.remote.azuread_groups + sensitive = true +} \ No newline at end of file diff --git a/landingzones/caf_networking/readme.md b/landingzones/caf_networking/readme.md new file mode 100644 index 00000000..ab213bfc --- /dev/null +++ b/landingzones/caf_networking/readme.md @@ -0,0 +1,38 @@ +# Cloud Adoption Framework for Azure - Landing zones on Terraform - Networking + +The networking landing zone allows you to deploy most networking topologies on Microsoft Azure. The same landing zone used with different parameters should allow you to deploy most network configurations. + +* Hub and spoke +* Virtual WAN +* Application DMZ scenario +* Any custom network topology based on virtual networks or virtual WAN +* Library of network security groups definition + +Networking landing zone operates at **level 2**. + +For a review of the hierarchy approach of Cloud Adoption Framework for Azure landing zones on Terraform, you can refer to [the following documentation](../../documentation/code_architecture/hierarchy.md). + +## Getting started with networking examples + +Depending on the networking scenario and topology, we provide you with different examples ready to use: + +| level | scenario | +|-------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------| +| [100-single-region-hub](./scenario/100-single-region-hub) | Simple hub in one region | +| [101-multi-region-hub](./scenario/101-multi-region-hub) | Two hubs in different regions with peering | +| [105-hub-and-spoke](./scenario/105-hub-and-spoke) | Hub and spoke topology in one region | +| [106-hub-virtual-wan-firewall](./scenario/106-hub-virtual-wan-firewall) | Azure Virtual WAN topology with virtual hub in multiple regions, optional support for Azure Firewall manager | +| [200-single-region-hub](./scenario/200-single-region-hub) | Simple hub in one region, with diagnostics | +| [201-multi-region-hub](./scenario/201-multi-region-hub) | Two hubs in different regions with peering, with diagnostics | +| [210-aks-private](./scenario/210-aks-private) | Hub and spoke topology in one region, with diagnostics | + +## Deploying CAF networking + +Once you have picked a scenario for test, you can deploy it using: + +```bash +rover -lz /tf/caf/landingzones/caf_networking \ +-level level2 \ +-var-folder /tf/caf/landingzones/caf_networking/scenario/100-single-region-hub \ +-a apply +``` diff --git a/landingzones/caf_networking/scenario/100-single-region-hub/configuration.tfvars b/landingzones/caf_networking/scenario/100-single-region-hub/configuration.tfvars new file mode 100644 index 00000000..7269553e --- /dev/null +++ b/landingzones/caf_networking/scenario/100-single-region-hub/configuration.tfvars @@ -0,0 +1,62 @@ +landingzone = { + backend_type = "azurerm" + global_settings_key = "foundations" + level = "level2" + key = "networking_hub" + tfstates = { + foundations = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + launchpad = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + } +} + +resource_groups = { + vnet_hub_re1 = { + name = "vnet-hub-re1" + region = "region1" + } +} + +vnets = { + hub_re1 = { + resource_group_key = "vnet_hub_re1" + region = "region1" + vnet = { + name = "hub-re1" + address_space = ["100.64.100.0/22"] + } + specialsubnets = { + GatewaySubnet = { + name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway + cidr = ["100.64.100.0/27"] + } + AzureFirewallSubnet = { + name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet + cidr = ["100.64.101.0/26"] + } + } + subnets = { + AzureBastionSubnet = { + name = "AzureBastionSubnet" #Must be called AzureBastionSubnet + cidr = ["100.64.101.64/26"] + nsg_key = "azure_bastion_nsg" + } + jumpbox = { + name = "jumpbox" + cidr = ["100.64.102.0/27"] + nsg_key = "jumpbox" + } + private_endpoints = { + name = "private_endpoints" + cidr = ["100.64.103.128/25"] + enforce_private_link_endpoint_network_policies = true + } + } + } + +} diff --git a/landingzones/caf_networking/scenario/100-single-region-hub/network_security_group_definition.tfvars b/landingzones/caf_networking/scenario/100-single-region-hub/network_security_group_definition.tfvars new file mode 100644 index 00000000..232a5432 --- /dev/null +++ b/landingzones/caf_networking/scenario/100-single-region-hub/network_security_group_definition.tfvars @@ -0,0 +1,327 @@ +# +# Definition of the networking security groups +# +network_security_group_definition = { + # This entry is applied to all subnets with no NSG defined + empty_nsg = { + } + + azure_bastion_nsg = { + nsg = [ + { + name = "bastion-in-allow", + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "bastion-control-in-allow-443", + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "135" + source_address_prefix = "GatewayManager" + destination_address_prefix = "*" + }, + { + name = "Kerberos-password-change", + priority = "121" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "4443" + source_address_prefix = "GatewayManager" + destination_address_prefix = "*" + }, + { + name = "bastion-vnet-out-allow-22", + priority = "103" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "bastion-vnet-out-allow-3389", + priority = "101" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "3389" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "bastion-azure-out-allow", + priority = "120" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "AzureCloud" + } + ] + } + + application_gateway = { + nsg = [ + { + name = "Inbound-HTTP", + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "*" + source_port_range = "*" + destination_port_range = "80-82" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "Inbound-HTTPs", + priority = "130" + direction = "Inbound" + access = "Allow" + protocol = "*" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "Inbound-AGW", + priority = "140" + direction = "Inbound" + access = "Allow" + protocol = "*" + source_port_range = "*" + destination_port_range = "65200-65535" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + ] + } + + api_management = { + nsg = [ + { + name = "Inbound-APIM", + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "3443" + source_address_prefix = "ApiManagement" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "Inbound-Redis", + priority = "110" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "6381-6383" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "Inbound-LoadBalancer", + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "*" + source_address_prefix = "AzureLoadBalancer" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "Outbound-StorageHttp", + priority = "100" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "80" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "Storage" + }, + { + name = "Outbound-StorageHttps", + priority = "110" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "Storage" + }, + { + name = "Outbound-AADHttp", + priority = "120" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "80" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "AzureActiveDirectory" + }, + { + name = "Outbound-AADHttps", + priority = "130" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "AzureActiveDirectory" + }, + { + name = "Outbound-SQL", + priority = "140" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "1433" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "SQL" + }, + { + name = "Outbound-EventHub", + priority = "150" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "5671-5672" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "EventHub" + }, + { + name = "Outbound-EventHubHttps", + priority = "160" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "EventHub" + }, + { + name = "Outbound-FileShareGit", + priority = "170" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "445" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "Storage" + }, + { + name = "Outbound-Health", + priority = "180" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "1886" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "INTERNET" + }, + { + name = "Outbound-Monitor", + priority = "190" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "AzureMonitor" + }, + { + name = "Outbound-MoSMTP1itor", + priority = "200" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "25" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "INTERNET" + }, + { + name = "Outbound-SMTP2", + priority = "210" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "587" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "INTERNET" + }, + { + name = "Outbound-SMTP3", + priority = "220" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "25028" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "INTERNET" + }, + { + name = "Outbound-Redis", + priority = "230" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "6381-6383" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "VirtualNetwork" + }, + ] + } + + jumpbox = { + nsg = [ + { + name = "ssh-inbound-22", + priority = "200" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + ] + } + +} + diff --git a/landingzones/caf_networking/scenario/100-single-region-hub/readme.md b/landingzones/caf_networking/scenario/100-single-region-hub/readme.md new file mode 100644 index 00000000..624dfff6 --- /dev/null +++ b/landingzones/caf_networking/scenario/100-single-region-hub/readme.md @@ -0,0 +1,45 @@ +# CAF landing zones for Terraform - Single region hub virtual network + +The networking landing zone allows you to deploy most networking topologies on Microsoft Azure. The same landing zone used with different parameters should allow you to deploy most network configurations. + +* Hub and spoke +* Virtual WAN +* Application DMZ scenario +* Any custom network topology based on virtual networks or virtual WAN +* Library of network security groups definition + +Networking landing zone operates at **level 2**. + +For a review of the hierarchy approach of Cloud Adoption Framework for Azure landing zones on Terraform, you can refer to [the following documentation](../../../../documentation/code_architecture/hierarchy.md). + +## Architecture diagram + +This example allows you to deploy the following topology: + +![100-example](../../documentation/img/100-single-region-hub.png) + + +## Components deployed by this example + +| Component | Type of resource | Purpose | +|----------------------------------------------------------------------------------|-------------------------|------------------------------------------------------------------| +| vnet-hub-re1 | Resource group | resource group to host the virtual network | +| vnet_hub_re1 | Virtual network | virtual network used as a hub | +| GatewaySubnet,AzureFirewallSubnet,AzureBastionSubnet, jumpbox, private_endpoints | Virtual Subnets | virtual subnets | +| azure_bastion_nsg, empty_nsg, application_gateway, api_management, jumpbox | Network security groups | network security groups that can be attached to virtual subnets. | + + +## Customizing this example + +Please review the configuration files and make sure you are deploying in the expected region and with the expected settings. + +## Deploying this example + +Once you have picked a scenario for test, you can deploy it using: + +```bash +rover -lz /tf/caf/landingzones/caf_networking \ +-level level2 \ +-var-folder /tf/caf/landingzones/caf_networking/scenario/100-single-region-hub \ +-a apply +``` diff --git a/landingzones/caf_networking/scenario/101-multi-region-hub/configuration.tfvars b/landingzones/caf_networking/scenario/101-multi-region-hub/configuration.tfvars new file mode 100644 index 00000000..26f86034 --- /dev/null +++ b/landingzones/caf_networking/scenario/101-multi-region-hub/configuration.tfvars @@ -0,0 +1,27 @@ +landingzone = { + backend_type = "azurerm" + global_settings_key = "foundations" + level = "level2" + key = "networking_hub" + tfstates = { + foundations = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + launchpad = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + } +} + +resource_groups = { + vnet_hub_re1 = { + name = "vnet-hub-re1" + region = "region1" + } + vnet_hub_re2 = { + name = "vnet-hub-re2" + region = "region2" + } +} diff --git a/landingzones/caf_networking/scenario/101-multi-region-hub/network_security_group_definition.tfvars b/landingzones/caf_networking/scenario/101-multi-region-hub/network_security_group_definition.tfvars new file mode 100644 index 00000000..6352fec3 --- /dev/null +++ b/landingzones/caf_networking/scenario/101-multi-region-hub/network_security_group_definition.tfvars @@ -0,0 +1,344 @@ +# +# Definition of the networking security groups +# +network_security_group_definition = { + # This entry is applied to all subnets with no NSG defined + empty_nsg = { + } + + azure_bastion_nsg = { + + nsg = [ + { + name = "bastion-in-allow", + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "bastion-control-in-allow-443", + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "135" + source_address_prefix = "GatewayManager" + destination_address_prefix = "*" + }, + { + name = "Kerberos-password-change", + priority = "121" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "4443" + source_address_prefix = "GatewayManager" + destination_address_prefix = "*" + }, + { + name = "bastion-vnet-out-allow-22", + priority = "103" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "bastion-vnet-out-allow-3389", + priority = "101" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "3389" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "bastion-azure-out-allow", + priority = "120" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "AzureCloud" + } + ] + } + + application_gateway = { + + nsg = [ + { + name = "Inbound-HTTP", + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "*" + source_port_range = "*" + destination_port_range = "80-82" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "Inbound-HTTPs", + priority = "130" + direction = "Inbound" + access = "Allow" + protocol = "*" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "Inbound-AGW", + priority = "140" + direction = "Inbound" + access = "Allow" + protocol = "*" + source_port_range = "*" + destination_port_range = "65200-65535" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + ] + } + + api_management = { + + nsg = [ + { + name = "Inbound-APIM", + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "3443" + source_address_prefix = "ApiManagement" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "Inbound-Redis", + priority = "110" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "6381-6383" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "Inbound-LoadBalancer", + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "*" + source_address_prefix = "AzureLoadBalancer" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "Outbound-StorageHttp", + priority = "100" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "80" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "Storage" + }, + { + name = "Outbound-StorageHttps", + priority = "110" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "Storage" + }, + { + name = "Outbound-AADHttp", + priority = "120" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "80" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "AzureActiveDirectory" + }, + { + name = "Outbound-AADHttps", + priority = "130" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "AzureActiveDirectory" + }, + { + name = "Outbound-SQL", + priority = "140" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "1433" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "SQL" + }, + { + name = "Outbound-EventHub", + priority = "150" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "5671-5672" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "EventHub" + }, + { + name = "Outbound-EventHubHttps", + priority = "160" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "EventHub" + }, + { + name = "Outbound-FileShareGit", + priority = "170" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "445" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "Storage" + }, + { + name = "Outbound-Health", + priority = "180" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "1886" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "INTERNET" + }, + { + name = "Outbound-Monitor", + priority = "190" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "AzureMonitor" + }, + { + name = "Outbound-MoSMTP1itor", + priority = "200" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "25" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "INTERNET" + }, + { + name = "Outbound-SMTP2", + priority = "210" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "587" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "INTERNET" + }, + { + name = "Outbound-SMTP3", + priority = "220" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "25028" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "INTERNET" + }, + { + name = "Outbound-Redis", + priority = "230" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "6381-6383" + source_address_prefix = "VirtualNetwork" + destination_address_prefix = "VirtualNetwork" + }, + ] + } + + jumpbox = { + + diagnostic_profiles = { + nsg = { + definition_key = "network_security_group" + destination_type = "storage" + destination_key = "all_regions" + } + operations = { + name = "operations" + definition_key = "network_security_group" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + + nsg = [ + { + name = "ssh-inbound-22", + priority = "200" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + ] + } + +} diff --git a/landingzones/caf_networking/scenario/101-multi-region-hub/peering.tfvars b/landingzones/caf_networking/scenario/101-multi-region-hub/peering.tfvars new file mode 100644 index 00000000..40a1eb49 --- /dev/null +++ b/landingzones/caf_networking/scenario/101-multi-region-hub/peering.tfvars @@ -0,0 +1,31 @@ + +vnet_peerings = { + hub_re1_TO_hub_re2 = { + name = "hub_re1_TO_hub_re2" + from = { + vnet_key = "hub_re1" + } + to = { + vnet_key = "hub_re2" + } + allow_virtual_network_access = true + allow_forwarded_traffic = false + allow_gateway_transit = false + use_remote_gateways = false + } + + hub_re2_TO_hub_re1 = { + name = "hub_re2_TO_hub_re1" + from = { + vnet_key = "hub_re2" + } + to = { + vnet_key = "hub_re1" + } + allow_virtual_network_access = true + allow_forwarded_traffic = false + allow_gateway_transit = false + use_remote_gateways = false + } + +} diff --git a/landingzones/caf_networking/scenario/101-multi-region-hub/readme.md b/landingzones/caf_networking/scenario/101-multi-region-hub/readme.md new file mode 100644 index 00000000..8d7ad2ac --- /dev/null +++ b/landingzones/caf_networking/scenario/101-multi-region-hub/readme.md @@ -0,0 +1,50 @@ +# CAF landing zones for Terraform - Multi-region hub with global peering + +This scenario deploys the networking hub across multiple regions + +The networking landing zone allows you to deploy most networking topologies on Microsoft Azure. The same landing zone used with different parameters should allow you to deploy most network configurations. + +* Hub and spoke +* Virtual WAN +* Application DMZ scenario +* Any custom network topology based on virtual networks or virtual WAN +* Library of network security groups definition + +Networking landing zone operates at **level 2**. + +For a review of the hierarchy approach of Cloud Adoption Framework for Azure landing zones on Terraform, you can refer to [the following documentation](../../../../documentation/code_architecture/hierarchy.md). + +## Architecture diagram + +This example allows you to deploy the following topology: + +![101-example](../../documentation/img/101-multi-region-hub.png) + + +## Components deployed by this example + +| Component | Type of resource | Purpose | +|----------------------------------------------------------------------------------|-------------------------|--------------------------------------------------------------------------------------------| +| vnet-hub-re1, vnet-hub-re2 | Resource group | resource group to host the virtual network | +| vnet_hub_re1, vnet-hub-re2 | Virtual network | virtual network used as a hub | +| GatewaySubnet,AzureFirewallSubnet,AzureBastionSubnet, jumpbox, private_endpoints | Virtual Subnets | virtual subnets | +| azure_bastion_nsg, empty_nsg, application_gateway, api_management, jumpbox | Network security groups | network security groups that can be attached to virtual subnets. | +| hub_re1_TO_hub_re2, and hub_re2_TO_hub_re1 | Virtual network peering | Peering between vnet_hub_re1 and vnet-hub-re2 | +| bastion-re1-pip1, bastion-re2-pip1 | Public IP address | Public IP address to be used in vnet_hub_re1 and vnet-hub-re2, to be used by Azure Bastion | +| bastion-re1, bastion-re2 | Azure Bastion | Azure Bastion host in order to access the virtual network. | + + +## Customizing this example + +Please review the configuration files and make sure you are deploying in the expected region and with the expected settings. + +## Deploying this example + +Once you have picked a scenario for test, you can deploy it using: + +```bash +rover -lz /tf/caf/landingzones/caf_networking \ +-level level2 \ +-var-folder /tf/caf/landingzones/caf_networking/scenario/101-multi-region-hub \ +-a apply +``` diff --git a/landingzones/caf_networking/scenario/101-multi-region-hub/virtual_networks.tfvars b/landingzones/caf_networking/scenario/101-multi-region-hub/virtual_networks.tfvars new file mode 100644 index 00000000..67af8983 --- /dev/null +++ b/landingzones/caf_networking/scenario/101-multi-region-hub/virtual_networks.tfvars @@ -0,0 +1,78 @@ + +vnets = { + hub_re1 = { + resource_group_key = "vnet_hub_re1" + region = "region1" + vnet = { + name = "hub-re1" + address_space = ["100.64.100.0/22"] + } + specialsubnets = { + GatewaySubnet = { + name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway + cidr = ["100.64.100.0/27"] + } + AzureFirewallSubnet = { + name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet + cidr = ["100.64.101.0/26"] + } + } + subnets = { + AzureBastionSubnet = { + name = "AzureBastionSubnet" #Must be called AzureBastionSubnet + cidr = ["100.64.101.64/26"] + nsg_key = "azure_bastion_nsg" + } + jumpbox = { + name = "jumpbox" + cidr = ["100.64.102.0/27"] + nsg_key = "jumpbox" + } + private_endpoints = { + name = "private_endpoints" + cidr = ["100.64.103.128/25"] + enforce_private_link_endpoint_network_policies = true + } + } + + } + + hub_re2 = { + resource_group_key = "vnet_hub_re2" + region = "region2" + vnet = { + name = "hub-re2" + address_space = ["100.65.100.0/22"] + } + specialsubnets = { + GatewaySubnet = { + name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway + cidr = ["100.65.100.0/27"] + } + AzureFirewallSubnet = { + name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet + cidr = ["100.65.101.0/26"] + } + } + subnets = { + AzureBastionSubnet = { + name = "AzureBastionSubnet" #Must be called AzureBastionSubnet + cidr = ["100.65.101.64/26"] + nsg_key = "azure_bastion_nsg" + } + jumpbox = { + name = "jumpbox" + cidr = ["100.65.102.0/27"] + nsg_key = "jumpbox" + } + private_endpoints = { + name = "private_endpoints" + cidr = ["100.65.103.128/25"] + enforce_private_link_endpoint_network_policies = true + } + } + + } + + +} diff --git a/landingzones/caf_networking/scenario/105-hub-and-spoke/configuration.tfvars b/landingzones/caf_networking/scenario/105-hub-and-spoke/configuration.tfvars new file mode 100644 index 00000000..6cc42649 --- /dev/null +++ b/landingzones/caf_networking/scenario/105-hub-and-spoke/configuration.tfvars @@ -0,0 +1,155 @@ +landingzone = { + backend_type = "azurerm" + global_settings_key = "foundations" + level = "level2" + key = "example" + tfstates = { + foundations = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + launchpad = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + } +} + +resource_groups = { + vnet_hub_region1 = { + name = "vnet-hub-re1" + } + vnet_spoke_region1 = { + name = "vnet-spoke-re1" + } +} + +vnets = { + hub_re1 = { + resource_group_key = "vnet_hub_region1" + vnet = { + name = "hub-re1" + address_space = ["10.10.100.0/24"] + } + specialsubnets = { + AzureFirewallSubnet = { + name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet + cidr = ["10.10.100.192/26"] + } + } + subnets = { + jumphost = { + name = "jumphost" + cidr = ["10.10.100.0/25"] + nsg_key = "jumphost" + } + } + } + + spoke_re1 = { + resource_group_key = "vnet_spoke_region1" + vnet = { + name = "spoke-re1" + address_space = ["10.11.100.0/24"] + } + specialsubnets = {} + subnets = { + jumphost = { + name = "jumphost" + cidr = ["10.11.100.0/25"] + nsg_key = "jumphost" + } + webapp1 = { + name = "webapp-presentation-tier" + cidr = ["10.11.100.128/25"] + } + } + } +} + +azurerm_firewalls = { + # Southeastasia firewall (do not change the key when created) + fw_re1 = { + region = "region1" + name = "azfwre1" + resource_group_key = "vnet_hub_region1" + vnet_key = "hub_re1" + public_ip_key = "az_fw_pip" + + } + +} + +public_ip_addresses = { + + az_fw_pip = { + name = "az_fw_re1_pip1" + region = "region1" + resource_group_key = "vnet_hub_region1" + sku = "Standard" + allocation_method = "Static" + ip_version = "IPv4" + idle_timeout_in_minutes = "4" + + } +} + +route_tables = { + default_to_firewall_re1 = { + name = "default_to_firewall_re1" + resource_group_key = "vnet_spoke_region1" + } +} + +azurerm_routes = { + default_to_firewall_rg1 = { + name = "0-0-0-0-through-firewall-re1" + resource_group_key = "vnet_spoke_region1" + route_table_key = "default_to_firewall_re1" + address_prefix = "0.0.0.0/0" + next_hop_type = "VirtualAppliance" + + # To be set when next_hop_type = "VirtualAppliance" + private_ip_keys = { + azurerm_firewall = { + key = "fw_re1" + interface_index = 0 + } + # virtual_machine = { + # key = "" + # nic_key = "" + # } + } + } +} + +vnet_peerings = { + hub-re1_TO_spoke-re1 = { + name = "hub-re1_TO_spoke-re1" + from = { + vnet_key = "hub_re1" + } + to = { + vnet_key = "spoke_re1" + } + allow_virtual_network_access = true + allow_forwarded_traffic = true + allow_gateway_transit = false + use_remote_gateways = false + } + + spoke-re1_TO_hub-re1 = { + name = "hub_re2_TO_hub_re1" + from = { + vnet_key = "spoke_re1" + } + to = { + vnet_key = "hub_re1" + } + allow_virtual_network_access = true + allow_forwarded_traffic = false + allow_gateway_transit = false + use_remote_gateways = false + } + +} diff --git a/landingzones/caf_networking/scenario/105-hub-and-spoke/network_security_group_definition.tfvars b/landingzones/caf_networking/scenario/105-hub-and-spoke/network_security_group_definition.tfvars new file mode 100644 index 00000000..40dfc522 --- /dev/null +++ b/landingzones/caf_networking/scenario/105-hub-and-spoke/network_security_group_definition.tfvars @@ -0,0 +1,122 @@ +# +# Definition of the networking security groups +# +network_security_group_definition = { + azure_bastion_nsg = { + + diagnostic_profiles = { + nsg = { + definition_key = "network_security_group" + destination_type = "storage" + destination_key = "all_regions" + } + operations = { + name = "operations" + definition_key = "network_security_group" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + + nsg = [ + { + name = "bastion-in-allow", + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "bastion-control-in-allow-443", + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "135" + source_address_prefix = "GatewayManager" + destination_address_prefix = "*" + }, + { + name = "Kerberos-password-change", + priority = "121" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "4443" + source_address_prefix = "GatewayManager" + destination_address_prefix = "*" + }, + { + name = "bastion-vnet-out-allow-22", + priority = "103" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "bastion-vnet-out-allow-3389", + priority = "101" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "3389" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "bastion-azure-out-allow", + priority = "120" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "AzureCloud" + } + ] + } + + jumphost = { + + diagnostic_profiles = { + nsg = { + definition_key = "network_security_group" + destination_type = "storage" + destination_key = "all_regions" + } + operations = { + name = "operations" + definition_key = "network_security_group" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + + nsg = [ + { + name = "ssh-inbound-22", + priority = "200" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + ] + } + +} diff --git a/landingzones/caf_networking/scenario/105-hub-and-spoke/readme.md b/landingzones/caf_networking/scenario/105-hub-and-spoke/readme.md new file mode 100644 index 00000000..b2820fb7 --- /dev/null +++ b/landingzones/caf_networking/scenario/105-hub-and-spoke/readme.md @@ -0,0 +1,52 @@ +# CAF landing zones for Terraform - Secure Hub and Spoke with Azure Firewall + +This scenario deploys the networking hub across multiple regions + +The networking landing zone allows you to deploy most networking topologies on Microsoft Azure. The same landing zone used with different parameters should allow you to deploy most network configurations. + +* Hub and spoke +* Virtual WAN +* Application DMZ scenario +* Any custom network topology based on virtual networks or virtual WAN +* Library of network security groups definition + +Networking landing zone operates at **level 2**. + +For a review of the hierarchy approach of Cloud Adoption Framework for Azure landing zones on Terraform, you can refer to [the following documentation](../../../../documentation/code_architecture/hierarchy.md). + +## Architecture diagram + +This example allows you to deploy the following topology: + +![101-example](../../documentation/img/105-hub-and-spoke.png) + + +## Components deployed by this example + +| Component | Type of resource | Purpose | +|--|--|--| +| vnet-hub-re1, vnet-spoke-re2 | Resource group | resource group to host the virtual network | +| hub-re1, spoke-re1 | Virtual network | virtual networks for hub and spokeshub | +| AzureFirewallSubnet,jumphost, webapp-presentation-tier | Virtual Subnets | virtual subnets | +| azure_bastion_nsg, , jumphost_nsg | Network security groups | network security groups that can be attached to virtual subnets. | +| hub_re1_TO_spoke_re1, and spoke_re1_TO_hub_re1 | Virtual network peering | Peering between hub-re1 and spoke-re1 | +| azfwre1 | Azure Firewall | Azure Firewall in Hub network | +| az_fw_re1_pip1 | Public IP address | Public IP address used by Azure Firewall | +| default_to_firewall_re1 | Route table | Route table to host route entries | +| 0-0-0-0-through-firewall-re1 | Route table entry | Route all traffic to Azure Firewall in hub | + + +## Customizing this example + +Please review the configuration files and make sure you are deploying in the expected region and with the expected settings. + +## Deploying this example + +Once you have picked a scenario for test, you can deploy it using: + +```bash +rover -lz /tf/caf/landingzones/caf_networking \ +-level level2 \ +-var-folder /tf/caf/landingzones/caf_networking/scenario/105-hub-and-spoke \ +-a apply +``` diff --git a/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/configuration.tfvars b/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/configuration.tfvars new file mode 100644 index 00000000..bd5fd339 --- /dev/null +++ b/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/configuration.tfvars @@ -0,0 +1,72 @@ +landingzone = { + backend_type = "azurerm" + global_settings_key = "foundations" + level = "level2" + key = "example" + tfstates = { + foundations = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + launchpad = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + } +} + +resource_groups = { + vnet_re1 = { + name = "vnet-spoke-re1" + region = "region1" + } + hub_re1 = { + name = "vnet-hub-re1" + region = "region1" + } +} + +vnets = { + vnet_re1 = { + resource_group_key = "vnet_re1" + region = "region1" + vnet = { + name = "hub-re1" + address_space = ["10.10.100.0/24"] + } + specialsubnets = { + AzureFirewallSubnet = { + name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet + cidr = ["10.10.100.192/26"] + } + } + subnets = { + AzureBastionSubnet = { + name = "AzureBastionSubnet" #Must be called AzureBastionSubnet + cidr = ["10.10.100.160/27"] + nsg_key = "azure_bastion_nsg" + } + } + } +} + +vhub_peerings = { + # Establish the peering with Virtual Hubs + hub_rg1-TO-vnet_rg1 = { + vhub = { + virtual_wan_key = "vwan_re1" + virtual_hub_key = "hub_re1" + } + vnet = { + # If the virtual network is stored in another another landing zone, use the following attributes to refer the state file: + # tfstate_key = "networking" + # lz_key = "networking" + # output_key = "vnets" + vnet_key = "vnet_re1" + } + name = "vhub_peering_hub_sg" + hub_to_vitual_network_traffic_allowed = true + vitual_network_to_hub_gateways_traffic_allowed = true + internet_security_enabled = true + } +} diff --git a/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/network_security_group_definition.tfvars b/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/network_security_group_definition.tfvars new file mode 100644 index 00000000..3d3d06e3 --- /dev/null +++ b/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/network_security_group_definition.tfvars @@ -0,0 +1,104 @@ +network_security_group_definition = { + empty_nsg = { + + nsg = [] + diagnostic_profiles = { + nsg = { + definition_key = "network_security_group" + destination_type = "storage" + destination_key = "all_regions" + } + operations = { + name = "operations" + definition_key = "network_security_group" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + } + + azure_bastion_nsg = { + diagnostic_profiles = { + nsg = { + definition_key = "network_security_group" + destination_type = "storage" + destination_key = "all_regions" + } + operations = { + name = "operations" + definition_key = "network_security_group" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + + nsg = [ + { + name = "bastion-in-allow", + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "bastion-control-in-allow-443", + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "135" + source_address_prefix = "GatewayManager" + destination_address_prefix = "*" + }, + { + name = "Kerberos-password-change", + priority = "121" + direction = "Inbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "4443" + source_address_prefix = "GatewayManager" + destination_address_prefix = "*" + }, + { + name = "bastion-vnet-out-allow-22", + priority = "103" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "bastion-vnet-out-allow-3389", + priority = "101" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "3389" + source_address_prefix = "*" + destination_address_prefix = "VirtualNetwork" + }, + { + name = "bastion-azure-out-allow", + priority = "120" + direction = "Outbound" + access = "Allow" + protocol = "tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "AzureCloud" + } + ] + } +} \ No newline at end of file diff --git a/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/readme.md b/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/readme.md new file mode 100644 index 00000000..7e9c9477 --- /dev/null +++ b/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/readme.md @@ -0,0 +1,47 @@ +# CAF landing zones for Terraform - Azure Virtual WAN with Firewall manager + +The networking landing zone allows you to deploy most networking topologies on Microsoft Azure. The same landing zone used with different parameters should allow you to deploy most network configurations. + +* Hub and spoke +* Virtual WAN +* Application DMZ scenario +* Any custom network topology based on virtual networks or virtual WAN +* Library of network security groups definition + +Networking landing zone operates at **level 2**. + +For a review of the hierarchy approach of Cloud Adoption Framework for Azure landing zones on Terraform, you can refer to [the following documentation](../../../../documentation/code_architecture/hierarchy.md). + +## Architecture diagram + +This example allows you to deploy the following topology: + +![virtual_wan_lz](../../documentation/img/106-hub-virtual-wan-firewall.png) + + +## Components deployed by this example + +| Component | Type of resource | Purpose | +|------------------------------|-------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| vnet-spoke-re1, vnet-hub-re1 | Resource group | resource group to host the virtual network and virtual WAN | +| vnet_re1 | Virtual network with subnets, network security groups | virtual network used as a spoke, attached to the virtual hub from Azure Virtual WAN | +| contosovWAN-re1 | Virtual WAN | virtual WAN infrastructure | +| hub-re1, hub-re2 | Virtual Hubs | virtual hubs to be deployed in region, the hubs can be configured to deploy point-to-site connectivity, site-to-site connectivity or Express Route connectivity. | +| hub_fw_re1, hub_fw_re2 | Azure Firewall | traffic filtering between hubs and outside | +| hub_rg1-TO-vnet_rg1 | Virtual network and Virtual Hubs peering objects | network peering between virtual hubs and virtual network | + + +## Customizing this example + +Please review the configuration files and make sure you are deploying in the expected region and with the expected settings. + +## Deploying this example + +Once you have picked a scenario for test, you can deploy it using: + +```bash +rover -lz /tf/caf/landingzones/caf_networking \ +-level level2 \ +-var-folder /tf/caf/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall \ +-a apply +``` diff --git a/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/virtual_wan.tfvars b/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/virtual_wan.tfvars new file mode 100644 index 00000000..547e6245 --- /dev/null +++ b/landingzones/caf_networking/scenario/106-hub-virtual-wan-firewall/virtual_wan.tfvars @@ -0,0 +1,84 @@ +virtual_wans = { + vwan_re1 = { + resource_group_key = "hub_re1" + name = "contosovWAN-re1" + region = "region1" + + hubs = { + hub_re1 = { + hub_name = "hub-re1" + region = "region1" + hub_address_prefix = "10.0.3.0/24" + deploy_firewall = true + firewall_name = "hub-fw-re1" + firewall_resource_group_key = "hub_re1" + deploy_p2s = false + p2s_config = { + name = "caf-sea-vpn-p2s" + scale_unit = 2 + connection_configuration = { + name = "client-connections" + vpn_client_address_pool = { + address_prefixes = ["192.168.0.0/24"] + } + } + server_config = { + vpn_authentication_types = ["Certificate"] + client_root_certificate = { + name = "DigiCert-Federated-ID-Root-CA" + public_cert_data = < merge(try(data.terraform_remote_state.remote[key].outputs.managed_identities[key], {})) + } + azuread_groups = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.azuread_groups[key], {})) + } + vnets = { + for key, value in try(var.landingzone.tfstates, {}) : key => merge(try(data.terraform_remote_state.remote[key].outputs.vnets[key], {})) + } + } +} diff --git a/landingzones/caf_shared_services/main.tf b/landingzones/caf_shared_services/main.tf new file mode 100644 index 00000000..101baa5a --- /dev/null +++ b/landingzones/caf_shared_services/main.tf @@ -0,0 +1,66 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 2.32.0" + } + azuread = { + source = "hashicorp/azuread" + version = "~> 1.0.0" + } + random = { + source = "hashicorp/random" + version = "~> 2.2.1" + } + external = { + source = "hashicorp/external" + version = "~> 1.2.0" + } + null = { + source = "hashicorp/null" + version = "~> 2.1.0" + } + tls = { + source = "hashicorp/tls" + version = "~> 2.2.0" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~>1.1.0" + } + } + required_version = ">= 0.13" +} + + +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + } + } +} + +data "azurerm_client_config" "current" {} + + +locals { + + # Update the tfstates map + tfstates = merge( + map(var.landingzone.key, + map( + "storage_account_name", var.tfstate_storage_account_name, + "container_name", var.tfstate_container_name, + "resource_group_name", var.tfstate_resource_group_name, + "key", var.tfstate_key, + "level", var.landingzone.level, + "tenant_id", var.tenant_id, + "subscription_id", data.azurerm_client_config.current.subscription_id + ) + ) + , + data.terraform_remote_state.remote[var.landingzone.global_settings_key].outputs.tfstates + ) + +} \ No newline at end of file diff --git a/landingzones/caf_shared_services/output.tf b/landingzones/caf_shared_services/output.tf new file mode 100644 index 00000000..4ab45337 --- /dev/null +++ b/landingzones/caf_shared_services/output.tf @@ -0,0 +1,23 @@ +output global_settings { + value = local.global_settings + sensitive = true +} + +output diagnostics { + value = local.diagnostics + sensitive = true +} + +output tfstates { + value = local.tfstates + sensitive = true +} + +output managed_identities { + value = local.remote.managed_identities + sensitive = true +} +output azuread_groups { + value = local.remote.azuread_groups + sensitive = true +} \ No newline at end of file diff --git a/landingzones/caf_shared_services/readme.md b/landingzones/caf_shared_services/readme.md new file mode 100644 index 00000000..3ae6e809 --- /dev/null +++ b/landingzones/caf_shared_services/readme.md @@ -0,0 +1,33 @@ +# Cloud Adoption Framework for Azure - Landing zones on Terraform - Shared services + +The Shared services landing zone allows you to management components on Microsoft Azure, typically: + +* Monitoring +* Azure Site Recovery +* Azure Backup +* Azure Automation + +Shared services landing zone operates at **level 2**. + +It is **important** to deploy shared services landing zone, even in passthrough mode as it will export some shared parameters and settings from level1 landing zones. + +For a review of the hierarchy approach of Cloud Adoption Framework for Azure landing zones on Terraform, you can refer to [the following documentation](../../documentation/code_architecture/hierarchy.md). + +## Deploying shared services + +By default, the content of this landing zone is empty unless you specify a configuration file to enable it. + +```bash +rover -lz /tf/caf/landingzones/caf_shared_services \ +-level level2 \ +-a apply +``` + +You can deploy an example with Azure Site Recovery configuration and Automation: + +```bash +rover -lz /tf/caf/landingzones/caf_shared_services \ +-level level2 \ +-var-folder /tf/caf/landingzones/caf_shared_services/scenario/100 \ +-a apply +``` diff --git a/landingzones/caf_shared_services/scenario/100/configuration.tfvars b/landingzones/caf_shared_services/scenario/100/configuration.tfvars new file mode 100644 index 00000000..25489ff1 --- /dev/null +++ b/landingzones/caf_shared_services/scenario/100/configuration.tfvars @@ -0,0 +1,140 @@ +landingzone = { + backend_type = "azurerm" + global_settings_key = "foundations" + level = "level2" + key = "shared_services" + tfstates = { + foundations = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + launchpad = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + } +} + +resource_groups = { + primary = { + name = "sharedsvc_re1" + } +} + +recovery_vaults = { + asr1 = { + name = "vault_re1" + resource_group_key = "primary" + + region = "region1" + + # replication_policies = { + # repl1 = { + # name = "policy1" + # resource_group_key = "primary" + + # recovery_point_retention_in_minutes = 24 * 60 + # application_consistent_snapshot_frequency_in_minutes = 4 * 60 + # } + # } + + # recovery_fabrics = { + # fabric1 = { + # name = "fabric-primary" + # resource_group_key = "primary" + # region = "region1" + # } + # fabric2 = { + # name = "fabric-secondary" + # resource_group_key = "secondary" + # region = "region2" + # } + # } + + # protection_containers = { + # container1 = { + # name = "protection_container1" + # resource_group_key = "primary" + # recovery_fabric_key = "fabric1" + # } + # container2 = { + # name = "protection_container2" + # resource_group_key = "secondary" + # recovery_fabric_key = "fabric2" + # } + # } + + # protection_container_mapping = { + # hk-sg = { + # name = "hk-sg-container-mapping" + # vault_key = "asr1" + # resource_group_key = "secondary" + # fabric_key = "fabric1" + # source_protection_container_key = "container1" + # target_protection_container_key = "container2" + # policy_key = "repl1" + # } + #} + backup_policies = { + vms = { + policy1 = { + name = "VMBackupPolicy1" + vault_key = "asr1" + rg_key = "primary" + timezone = "UTC" + backup = { + frequency = "Daily" + time = "23:00" + #if not desired daily, can pick weekdays as below: + #weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] + } + retention_daily = { + count = 10 + } + retention_weekly = { + count = 42 + weekdays = ["Sunday", "Wednesday", "Friday", "Saturday"] + } + retention_monthly = { + count = 7 + weekdays = ["Sunday", "Wednesday"] + weeks = ["First", "Last"] + } + retention_yearly = { + count = 77 + weekdays = ["Sunday"] + weeks = ["Last"] + months = ["January"] + } + } + } + + fs = { + policy1 = { + name = "FSBackupPolicy1" + vault_key = "asr1" + rg_key = "primary" + timezone = "UTC" + backup = { + frequency = "Daily" + time = "23:00" + } + retention_daily = { + count = 10 + } + } + } + } + } + +} + +automations = { + auto1 = { + name = "autore1" + resource_group_key = "primary" + + region = "region1" + } + +} \ No newline at end of file diff --git a/landingzones/caf_shared_services/scenario/200/configuration.tfvars b/landingzones/caf_shared_services/scenario/200/configuration.tfvars new file mode 100644 index 00000000..0f8c8559 --- /dev/null +++ b/landingzones/caf_shared_services/scenario/200/configuration.tfvars @@ -0,0 +1,156 @@ +landingzone = { + backend_type = "azurerm" + global_settings_key = "foundations" + level = "level2" + key = "shared_services" + tfstates = { + foundations = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + launchpad = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + } +} + +resource_groups = { + primary = { + name = "sharedsvc_re1" + } +} + +recovery_vaults = { + asr1 = { + name = "vault_re1" + resource_group_key = "primary" + + region = "region1" + + diagnostic_profiles = { + asr1 = { + definition_key = "azure_site_recovery" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + + # replication_policies = { + # repl1 = { + # name = "policy1" + # resource_group_key = "primary" + + # recovery_point_retention_in_minutes = 24 * 60 + # application_consistent_snapshot_frequency_in_minutes = 4 * 60 + # } + # } + + # recovery_fabrics = { + # fabric1 = { + # name = "fabric-primary" + # resource_group_key = "primary" + # region = "region1" + # } + # fabric2 = { + # name = "fabric-secondary" + # resource_group_key = "secondary" + # region = "region2" + # } + # } + + # protection_containers = { + # container1 = { + # name = "protection_container1" + # resource_group_key = "primary" + # recovery_fabric_key = "fabric1" + # } + # container2 = { + # name = "protection_container2" + # resource_group_key = "secondary" + # recovery_fabric_key = "fabric2" + # } + # } + + # protection_container_mapping = { + # hk-sg = { + # name = "hk-sg-container-mapping" + # vault_key = "asr1" + # resource_group_key = "secondary" + # fabric_key = "fabric1" + # source_protection_container_key = "container1" + # target_protection_container_key = "container2" + # policy_key = "repl1" + # } + #} + backup_policies = { + vms = { + policy1 = { + name = "VMBackupPolicy1" + vault_key = "asr1" + rg_key = "primary" + timezone = "UTC" + backup = { + frequency = "Daily" + time = "23:00" + #if not desired daily, can pick weekdays as below: + #weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] + } + retention_daily = { + count = 10 + } + retention_weekly = { + count = 42 + weekdays = ["Sunday", "Wednesday", "Friday", "Saturday"] + } + retention_monthly = { + count = 7 + weekdays = ["Sunday", "Wednesday"] + weeks = ["First", "Last"] + } + retention_yearly = { + count = 77 + weekdays = ["Sunday"] + weeks = ["Last"] + months = ["January"] + } + } + } + + fs = { + policy1 = { + name = "FSBackupPolicy1" + vault_key = "asr1" + rg_key = "primary" + timezone = "UTC" + backup = { + frequency = "Daily" + time = "23:00" + } + retention_daily = { + count = 10 + } + } + } + } + } + +} + +automations = { + auto1 = { + name = "autore1" + resource_group_key = "primary" + + region = "region1" + + diagnostic_profiles = { + asr1 = { + definition_key = "azure_automation" + destination_type = "log_analytics" + destination_key = "central_logs" + } + } + } + +} \ No newline at end of file diff --git a/landingzones/caf_shared_services/variables.tf b/landingzones/caf_shared_services/variables.tf new file mode 100644 index 00000000..4c18715f --- /dev/null +++ b/landingzones/caf_shared_services/variables.tf @@ -0,0 +1,61 @@ +# Map of the remote data state for lower level +variable lower_storage_account_name {} +variable lower_container_name {} +variable lower_resource_group_name {} + +variable tfstate_storage_account_name {} +variable tfstate_container_name {} +variable tfstate_key {} +variable tfstate_resource_group_name {} + +variable landingzone { + default = { + backend_type = "azurerm" + level = "level2" + global_settings_key = "foundations" + key = "shared_services" + tfstates = { + foundations = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + foundations = { + level = "lower" + tfstate = "caf_foundations.tfstate" + } + } + } +} +variable tenant_id {} +variable global_settings { + default = {} +} +variable rover_version {} +variable logged_user_objectId { + default = null +} +variable logged_aad_app_objectId { + default = null +} +variable tags { + type = map + default = {} +} +variable diagnostics_definition { + default = {} +} +variable resource_groups { + default = {} +} +variable automations { + default = {} +} +variable recovery_vaults { + default = {} +} +variable replicated_vms { + default = {} +} +variable network_mappings { + default = {} +} diff --git a/landingzones/landingzone_caf_foundations/foundations.sandpit.auto.tfvars b/landingzones/landingzone_caf_foundations/foundations.sandpit.auto.tfvars deleted file mode 100644 index e2bcaaf9..00000000 --- a/landingzones/landingzone_caf_foundations/foundations.sandpit.auto.tfvars +++ /dev/null @@ -1,225 +0,0 @@ -# Sample Cloud Adoption Framework foundations landing zone - -## globalsettings -global_settings = { - #specifies the set of locations you are going to use in this landing zone - location_map = { - southeastasia = "southeastasia" - eastasia = "eastasia" - } - - #naming convention to be used as defined in naming convention module, accepted values are cafclassic, cafrandom, random, passthrough - convention = "cafrandom" - - #Set of tags for core operations - tags_hub = { - owner = "CAF" - deploymentType = "Terraform" - costCenter = "1664" - BusinessUnit = "SHARED" - DR = "NON-DR-ENABLED" - } - - # Set of resource groups to land the foundations - resource_groups_hub = { - southeastasia = { - HUB-CORE-SEC = { - name = "hub-core-sec-sea" - location = "southeastasia" - } - HUB-OPERATIONS = { - name = "hub-operations-sea" - location = "southeastasia" - } - } - eastasia = { - HUB-CORE-SEC = { - name = "hub-core-sec-hk" - location = "eastasia" - } - HUB-OPERATIONS = { - name = "hub-operations-hk" - location = "eastasia" - } - } - } -} - -## accounting settings -accounting_settings = { - - # Azure diagnostics logs retention period - southeastasia = { - # Azure Subscription activity logs retention period - azure_activity_log_enabled = false - azure_activity_logs_name = "actlogs" - azure_activity_logs_event_hub = false - azure_activity_logs_retention = 365 - azure_activity_audit = { - log = [ - # ["Audit category name", "Audit enabled)"] - ["Administrative", true], - ["Security", true], - ["ServiceHealth", true], - ["Alert", true], - ["Recommendation", true], - ["Policy", true], - ["Autoscale", true], - ["ResourceHealth", true], - ] - } - azure_diagnostics_logs_name = "diaglogs" - azure_diagnostics_logs_event_hub = false - - #Logging and monitoring - analytics_workspace_name = "caflalogs-sg" - - ##Log analytics solutions to be deployed - solution_plan_map = { - NetworkMonitoring = { - "publisher" = "Microsoft" - "product" = "OMSGallery/NetworkMonitoring" - }, - ADAssessment = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ADAssessment" - }, - ADReplication = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ADReplication" - }, - AgentHealthAssessment = { - "publisher" = "Microsoft" - "product" = "OMSGallery/AgentHealthAssessment" - }, - DnsAnalytics = { - "publisher" = "Microsoft" - "product" = "OMSGallery/DnsAnalytics" - }, - ContainerInsights = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ContainerInsights" - }, - KeyVaultAnalytics = { - "publisher" = "Microsoft" - "product" = "OMSGallery/KeyVaultAnalytics" - } - } - } - eastasia = { - # Azure Subscription activity logs retention period - azure_activity_log_enabled = false - azure_activity_logs_name = "actlogs" - azure_activity_logs_event_hub = false - azure_activity_logs_retention = 365 - azure_activity_audit = { - log = [ - # ["Audit category name", "Audit enabled)"] - ["Administrative", true], - ["Security", true], - ["ServiceHealth", true], - ["Alert", true], - ["Recommendation", true], - ["Policy", true], - ["Autoscale", true], - ["ResourceHealth", true], - ] - } - azure_diagnostics_logs_name = "diaglogs" - azure_diagnostics_logs_event_hub = false - - #Logging and monitoring - analytics_workspace_name = "caflalogs-hk" - - ##Log analytics solutions to be deployed - solution_plan_map = { - NetworkMonitoring = { - "publisher" = "Microsoft" - "product" = "OMSGallery/NetworkMonitoring" - }, - ADAssessment = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ADAssessment" - }, - ADReplication = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ADReplication" - }, - AgentHealthAssessment = { - "publisher" = "Microsoft" - "product" = "OMSGallery/AgentHealthAssessment" - }, - DnsAnalytics = { - "publisher" = "Microsoft" - "product" = "OMSGallery/DnsAnalytics" - }, - ContainerInsights = { - "publisher" = "Microsoft" - "product" = "OMSGallery/ContainerInsights" - }, - KeyVaultAnalytics = { - "publisher" = "Microsoft" - "product" = "OMSGallery/KeyVaultAnalytics" - } - } - } -} - -## governance -governance_settings = { - southeastasia = { - #current code supports only two levels of managemenr groups and one root - deploy_mgmt_groups = false - management_groups = { - root = { - name = "caf-rootmgmtgroup" - subscriptions = [] - #list your subscriptions ID in this field as ["GUID1", "GUID2"] - children = { - child1 = { - name = "tree1child1" - subscriptions = [] - } - child2 = { - name = "tree1child2" - subscriptions = [] - } - child3 = { - name = "tree1child3" - subscriptions = [] - } - } - } - } - - policy_matrix = { - #autoenroll_asc = true - to be implemented via builtin policies - autoenroll_monitor_vm = true - autoenroll_netwatcher = false - - no_public_ip_spoke = false - cant_create_ip_spoke = false - managed_disks_only = true - restrict_locations = false - list_of_allowed_locs = ["southeastasia", "eastasia"] - restrict_supported_svc = false - list_of_supported_svc = ["Microsoft.Network/publicIPAddresses", "Microsoft.Compute/disks"] - msi_location = "southeastasia" - } - } - eastasia = {} -} - -## security -security_settings = { - #Azure Security Center Configuration - enable_security_center = false - security_center = { - contact_email = "email@email.com" - contact_phone = "9293829328" - alerts_to_admins = true - alert_notifications = true - } - #Enables Azure Sentinel on the Log Analaytics repo - enable_sentinel = true -} diff --git a/landingzones/landingzone_caf_foundations/foundations.tf b/landingzones/landingzone_caf_foundations/foundations.tf deleted file mode 100644 index e63e8cf8..00000000 --- a/landingzones/landingzone_caf_foundations/foundations.tf +++ /dev/null @@ -1,38 +0,0 @@ -module "foundations_accounting" { - for_each = var.global_settings.location_map - source = "./foundations_accounting/" - - prefix = local.prefix - tags = local.tags - location = each.value - tags_hub = local.tags_hub - resource_groups_hub = var.global_settings.resource_groups_hub[each.key] - convention = var.global_settings.convention - - accounting_settings = var.accounting_settings[each.key] -} - -module "foundations_security" { - for_each = var.global_settings.location_map - source = "./foundations_security/" - - tags = local.tags - location = each.value - tags_hub = local.tags_hub - resource_groups_hub = module.foundations_accounting[each.key].resource_group_operations - log_analytics = module.foundations_accounting[each.key].log_analytics_workspace - - security_settings = var.security_settings -} - -module "foundations_governance" { - for_each = var.global_settings.location_map - source = "./foundations_governance/" - - tags = local.tags - tags_hub = local.tags_hub - location = each.value - log_analytics = module.foundations_accounting[each.key].log_analytics_workspace - - governance_settings = var.governance_settings[each.key] -} \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_accounting/accounting.tf b/landingzones/landingzone_caf_foundations/foundations_accounting/accounting.tf deleted file mode 100644 index c4cec317..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_accounting/accounting.tf +++ /dev/null @@ -1,75 +0,0 @@ -#Create the resource groups to host the blueprint -resource "azurecaf_naming_convention" "rg_coresec_name" { - name = var.resource_groups_hub.HUB-CORE-SEC.name - prefix = var.prefix - resource_type = "rg" - convention = var.convention -} - -resource "azurecaf_naming_convention" "rg_operations_name" { - name = var.resource_groups_hub.HUB-OPERATIONS.name - prefix = var.prefix - resource_type = "rg" - convention = var.convention -} - -resource "azurerm_resource_group" "rg_coresec" { - name = azurecaf_naming_convention.rg_coresec_name.result - location = var.resource_groups_hub.HUB-CORE-SEC.location - tags = local.tags -} - -resource "azurerm_resource_group" "rg_operations" { - name = azurecaf_naming_convention.rg_operations_name.result - location = var.resource_groups_hub.HUB-OPERATIONS.location - tags = local.tags -} - -#Specify the subscription logging repositories -module "activity_logs" { - count = var.accounting_settings.azure_activity_log_enabled ? 1 : 0 - source = "github.com/aztfmod/terraform-azurerm-caf-activity-logs?ref=vnext" - # source = "aztfmod/caf-activity-logs/azurerm" - # version = "3.0.0" - - convention = var.convention - enable_event_hub = var.accounting_settings.azure_activity_logs_event_hub - prefix = var.prefix - resource_group_name = azurerm_resource_group.rg_coresec.name - location = var.location - tags = local.tags - log_analytics_workspace_id = module.log_analytics.id - diagnostic_name = var.accounting_settings.azure_activity_logs_name - name = var.accounting_settings.azure_activity_logs_name - audit_settings_object = var.accounting_settings.azure_activity_audit -} - -#Specify the operations diagnostic logging repositories -module "diagnostics_logging" { - source = "github.com/aztfmod/terraform-azurerm-caf-diagnostics-logging?ref=vnext" - # source = "aztfmod/caf-diagnostics-logging/azurerm" - # version = "2.0.1" - - convention = var.convention - name = var.accounting_settings.azure_diagnostics_logs_name - enable_event_hub = var.accounting_settings.azure_diagnostics_logs_event_hub - prefix = var.prefix - resource_group_name = azurerm_resource_group.rg_operations.name - location = var.location - tags = local.tags -} - -#Create the Azure Monitor - Log Analytics workspace -module "log_analytics" { - source = "github.com/aztfmod/terraform-azurerm-caf-log-analytics?ref=vnext" - #version = "2.2.0" - - convention = var.convention - prefix = var.prefix - name = var.accounting_settings.analytics_workspace_name - solution_plan_map = var.accounting_settings.solution_plan_map - resource_group_name = azurerm_resource_group.rg_operations.name - location = var.location - tags = local.tags - retention_in_days = var.accounting_settings.azure_activity_logs_retention -} \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_accounting/main.tf b/landingzones/landingzone_caf_foundations/foundations_accounting/main.tf deleted file mode 100644 index 4dccf19d..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_accounting/main.tf +++ /dev/null @@ -1,17 +0,0 @@ -data "azurerm_client_config" "current" { -} - -locals { - blueprint_tag = { - "blueprint" = basename(abspath(path.module)) - } - tags = merge(var.tags, var.tags_hub, local.blueprint_tag) -} - -terraform { - required_providers { - azurecaf = { - source = "aztfmod/azurecaf" - } - } -} \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_accounting/output.tf b/landingzones/landingzone_caf_foundations/foundations_accounting/output.tf deleted file mode 100644 index 3dd8eca7..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_accounting/output.tf +++ /dev/null @@ -1,37 +0,0 @@ -#outputs the ops log repositories -output diagnostics_map { - value = module.diagnostics_logging.diagnostics_map - description = "outputs diagnostics map as desribed in the diagnostics logging module doc" -} - -#outputs the sec log repositories -output activity_logs_map { - value = var.accounting_settings.azure_activity_log_enabled ? module.activity_logs.0.seclogs_map : null - description = "outputs subscription activity logs map as desribed in the activity logging module doc" -} - -#log analytics workspace -output log_analytics_workspace { - value = module.log_analytics - description = "outputs the log analytics configuration settings as documented in log analytics module" -} - -output location { - value = var.location - description = "exports the location where objects from foundation have been created" -} - -output tags { - value = var.tags_hub - description = "exports the tags created in this blueprint" -} - -output prefix { - value = var.prefix - description = "exports the prefix as generated in level0" -} - -output resource_group_operations { - value = azurerm_resource_group.rg_operations - description = "rg_group_operations" -} \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_accounting/readme.md b/landingzones/landingzone_caf_foundations/foundations_accounting/readme.md deleted file mode 100644 index 0e95018f..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_accounting/readme.md +++ /dev/null @@ -1,31 +0,0 @@ -# foundations accounting - -foundations sets the basics of auditing, and logging as described below. - -## Capabilities - -Foundations deploys the following components: - - - Resource groups - - Core resource groups for foundation resources - - Activity Logging - - Auditing all subscription activities and archiving - - Storage Account - - Event Hubs (optional) - - Diagnostics Logging - - All operations logs kept for x days - - Storage Account - - Event Hubs - - Log Analytics - - Stores all the operations logs - - Solutions management - -![Foundations overview](../../../_pictures/caf_foundations/foundations_accounting.png) - -## Customization - -Customization happens at the landing zone using the variables. - -## Contribute - -Pull requests are welcome to evolve the framework and integrate new features. diff --git a/landingzones/landingzone_caf_foundations/foundations_accounting/variable.tf b/landingzones/landingzone_caf_foundations/foundations_accounting/variable.tf deleted file mode 100644 index e3a90194..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_accounting/variable.tf +++ /dev/null @@ -1,50 +0,0 @@ - -variable prefix { - description = "(Optional) Prefix to uniquely identify the deployment" -} - -variable resource_groups_hub { - description = "(Required) Contains the resource groups object to be created for hub" -} - -# Example: -# resource_groups = { -# apim = { -# name = "-apim-demo" -# location = "southeastasia" -# }, -# networking = { -# name = "-networking-demo" -# location = "eastasia" -# }, -# insights = { -# name = "-insights-demo" -# location = "francecentral" -# tags = { -# project = "Pattaya" -# approver = "Gunter" -# } -# }, -# } - -variable location { - description = "Azure region to create the resources" - type = string -} - -# Example: -# location = "southeastasia" - -variable tags_hub { - description = "map of the tags to be applied" - type = map(string) -} -variable tags {} - -variable convention { - -} - -variable accounting_settings { - -} \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_governance/governance.tf b/landingzones/landingzone_caf_foundations/foundations_governance/governance.tf deleted file mode 100644 index 979b07a3..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_governance/governance.tf +++ /dev/null @@ -1,27 +0,0 @@ -# management groups hierarchy -module "management_groups" { - source = "./management_group" - - management_groups = lookup(var.governance_settings, "management_groups", {}) - deploy_mgmt_groups = lookup(var.governance_settings, "deploy_mgmt_groups", false) - tags = var.tags_hub - -} - -# # azure policies -# module "custom_policies" { -# source = "./policies/custom" - -# policies_matrix = lookup(var.governance_settings, "policy_matrix", {}) -# log_analytics = var.log_analytics.name -# scope = data.azurerm_subscription.current.id -# } - -# module "builtin_policies" { -# source = "./policies/builtin" - -# policies_matrix = lookup(var.governance_settings, "policy_matrix", {}) -# log_analytics = var.log_analytics.name -# //log_analytics needed for policies with auto-remediation -# scope = data.azurerm_subscription.current.id -# } \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_governance/main.tf b/landingzones/landingzone_caf_foundations/foundations_governance/main.tf deleted file mode 100644 index 3f821acd..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_governance/main.tf +++ /dev/null @@ -1,17 +0,0 @@ -data "azurerm_client_config" "current" { -} - -data "azurerm_subscription" "current" {} - - -terraform { - backend "azurerm" { - } -} - -locals { - blueprint_tag = { - "blueprint" = basename(abspath(path.module)) - } - tags = merge(var.tags, var.tags_hub, local.blueprint_tag) -} \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_governance/management_group/main.tf b/landingzones/landingzone_caf_foundations/foundations_governance/management_group/main.tf deleted file mode 100644 index 104f9ee5..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_governance/management_group/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -data "azurerm_client_config" "current" {} - -locals { - module_tag = { - "module" = basename(abspath(path.module)) - } - tags = merge(var.tags, local.module_tag) -} diff --git a/landingzones/landingzone_caf_foundations/foundations_governance/management_group/module.tf b/landingzones/landingzone_caf_foundations/foundations_governance/management_group/module.tf deleted file mode 100644 index 6503160f..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_governance/management_group/module.tf +++ /dev/null @@ -1,48 +0,0 @@ -resource "azurerm_management_group" "parent_management_group" { - count = var.deploy_mgmt_groups ? 1 : 0 - - display_name = var.management_groups.root.name -} - -resource "azurerm_management_group" "l1children" { - for_each = var.deploy_mgmt_groups ? var.management_groups.root.children : {} - parent_management_group_id = azurerm_management_group.parent_management_group[0].id - display_name = each.value.name - subscription_ids = each.value.subscriptions -} - - -# Following new behaviors for SP -# https://github.com/terraform-providers/terraform-provider-azurerm/issues/6091 -# Changes in behavior of 2.0 checking for existing mgmt group - need to read permissions of reading on mgmt group with role before creating it. - -# module.blueprint_foundations_governance.module.management_groups.azurerm_management_group.parent_management_group[0]: Creating... - -# Error: Error checking for presence of existing Management Group "04e85bf6-36d1-48fd-97ed-01e208201a9e": managementgroups.Client#Get: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="AuthorizationFailed" Message="The client 'cf3a0c1a-fcda-4dd1-a66a-159e7d2eda0f' with object id 'cf3a0c1a-fcda-4dd1-a66a-159e7d2eda0f' does not have authorization to perform action 'Microsoft.Management/managementGroups/read' over scope '/providers/Microsoft.Management/managementGroups/04e85bf6-36d1-48fd-97ed-01e208201a9e' or the scope is invalid. If access was recently granted, please refresh your credentials." - -# on blueprint_foundations_governance/management_group/module.tf line 1, in resource "azurerm_management_group" "parent_management_group": -# 1: resource "azurerm_management_group" "parent_management_group" { - -# data "azurerm_subscription" "primary" { -# } - -# resource "azurerm_role_definition" "mgmtrole" { -# name = "my-custom-role-mgmt" -# scope = data.azurerm_subscription.primary.id -# description = "This is a custom role created via Terraform" - -# permissions { -# actions = ["Microsoft.Management/managementGroups/settings/read"] -# not_actions = [] -# } - -# assignable_scopes = [ -# data.azurerm_subscription.primary.id, # /subscriptions/00000000-0000-0000-0000-000000000000 -# ] -# } - -# resource "azurerm_role_assignment" "example" { -# scope = data.azurerm_subscription.primary.id -# role_definition_name = "my-custom-role-mgmt" -# principal_id = data.azurerm_client_config.current.client_id -# } \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_governance/management_group/output.tf b/landingzones/landingzone_caf_foundations/foundations_governance/management_group/output.tf deleted file mode 100644 index 35873dd9..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_governance/management_group/output.tf +++ /dev/null @@ -1,19 +0,0 @@ -# output "object" { -# value = azurerm_management_group.parent_management_group -# } - -# output "firstlevelkeys" { -# value = local.firstlevelkeys -# } - -# output "name" { -# value = azurerm_management_group -# } - -# output "id" { -# value = azurerm_management_group.parent_management_group[*].id -# } - -# output "rootmgid" { -# value = azurerm_management_group.parent_management_group.id -# } \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_governance/management_group/variables.tf b/landingzones/landingzone_caf_foundations/foundations_governance/management_group/variables.tf deleted file mode 100644 index 0afb8f1a..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_governance/management_group/variables.tf +++ /dev/null @@ -1,10 +0,0 @@ - -variable "management_groups" { - description = "(Required) Gets the map of management groups and attached subscriptions" -} - -variable "tags" {} - -variable "deploy_mgmt_groups" { - description = "(Required) toggle to enable management group deployment" -} \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_governance/output.tf b/landingzones/landingzone_caf_foundations/foundations_governance/output.tf deleted file mode 100644 index 5be17f29..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_governance/output.tf +++ /dev/null @@ -1,15 +0,0 @@ -#outputs the management group objects -output "management_groups" { - value = module.management_groups - description = "management groups output" -} - -# output "custom_policies" { -# value = module.custom_policies -# description = "management groups output" -# } - -# output "builtin_policies" { -# value = module.builtin_policies -# description = "management groups output" -# } \ No newline at end of file diff --git a/landingzones/landingzone_caf_foundations/foundations_governance/policies/builtin/allowed_locations.tf b/landingzones/landingzone_caf_foundations/foundations_governance/policies/builtin/allowed_locations.tf deleted file mode 100644 index 102b8244..00000000 --- a/landingzones/landingzone_caf_foundations/foundations_governance/policies/builtin/allowed_locations.tf +++ /dev/null @@ -1,23 +0,0 @@ -#Definition ID: /providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c -#Name: Allowed locations - -locals { - loclist = "${jsonencode(var.policies_matrix.list_of_allowed_locs)}" -} - -resource "azurerm_policy_assignment" "res_location" { - count = var.policies_matrix.restrict_locations ? 1 : 0 - name = "res_location" - scope = var.scope - policy_definition_id = "/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c" - description = "Policy Assignment with Terraform" - display_name = "TF Restrict Deployment of Azure Resources in specific location" - - parameters = < - \ No newline at end of file diff --git a/landingzones/landingzone_networking/bastion.tf b/landingzones/landingzone_networking/bastion.tf deleted file mode 100644 index c6fc6b64..00000000 --- a/landingzones/landingzone_networking/bastion.tf +++ /dev/null @@ -1,37 +0,0 @@ -## Azure Bastion configuration -module "az_bastion_ip" { - source = "aztfmod/caf-public-ip/azurerm" - version = "2.1.0" - - for_each = var.bastions - - convention = lookup(each.value, "convention", local.global_settings.convention) - name = each.value.bastion_ip_addr_config.ip_name - location = each.value.location - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - ip_addr = each.value.bastion_ip_addr_config - tags = local.tags - diagnostics_map = local.caf_foundations_accounting[each.value.location].diagnostics_map - log_analytics_workspace_id = local.caf_foundations_accounting[each.value.location].log_analytics_workspace.id - diagnostics_settings = each.value.bastion_ip_addr_config.diagnostics -} - -module "az_bastion" { - source = "aztfmod/caf-azure-bastion/azurerm" - version = "1.0.0" - - for_each = var.bastions - - bastion_config = each.value.bastion_config - convention = lookup(each.value, "convention", local.global_settings.convention) - name = each.value.bastion_config.name - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - subnet_id = module.vnets[each.value.vnet_key].vnet_subnets[each.value.subnet_key] - public_ip_address_id = module.az_bastion_ip[each.key].id - location = each.value.location - tags = local.tags - diagnostics_map = local.caf_foundations_accounting[each.value.location].diagnostics_map - log_analytics_workspace = local.caf_foundations_accounting[each.value.location].log_analytics_workspace - diagnostics_settings = each.value.bastion_config.diagnostics -} - diff --git a/landingzones/landingzone_networking/ddos.tf b/landingzones/landingzone_networking/ddos.tf deleted file mode 100644 index 99b5cb0d..00000000 --- a/landingzones/landingzone_networking/ddos.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "azurerm_network_ddos_protection_plan" "ddos_protection_plan" { - for_each = var.ddos_services - - name = each.value.name - location = each.value.location - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - tags = local.tags -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/examples/101-multiple-vnets/configuration.tfvars b/landingzones/landingzone_networking/examples/101-multiple-vnets/configuration.tfvars deleted file mode 100644 index 4b2dcfe9..00000000 --- a/landingzones/landingzone_networking/examples/101-multiple-vnets/configuration.tfvars +++ /dev/null @@ -1,146 +0,0 @@ -resource_groups = { - vnet_sg = { - name = "vnet-hub-sg" - location = "southeastasia" - useprefix = true - max_length = 40 - } -} - -vnets = { - hub_sg = { - resource_group_key = "vnet_sg" - location = "southeastasia" - vnet = { - name = "hub" - address_space = ["10.10.100.0/24"] - } - specialsubnets = { - GatewaySubnet = { - name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway - cidr = ["10.10.100.224/27"] - } - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = ["10.10.100.192/27"] - } - } - subnets = { - Active_Directory = { - name = "Active_Directory" - cidr = ["10.10.100.0/27"] - nsg_name = "Active_Directory_nsg" - nsg = [] - } - AzureBastionSubnet = { - name = "AzureBastionSubnet" #Must be called AzureBastionSubnet - cidr = ["10.10.100.160/27"] - nsg_name = "AzureBastionSubnet_nsg" - nsg = [ - { - name = "bastion-in-allow", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-443", - priority = "120" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "135" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-4443", - priority = "121" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "4443" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-vnet-out-allow-22", - priority = "103" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-vnet-out-allow-3389", - priority = "101" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-azure-out-allow", - priority = "120" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "AzureCloud" - } - ] - } - } - # Override the default var.diagnostics.vnet - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - - spoke_aks_sg = { - resource_group_key = "vnet_sg" - location = "southeastasia" - vnet = { - name = "aks" - address_space = ["10.10.101.0/24"] - } - specialsubnets = {} - subnets = { - aks_nodepool_system = { - name = "aks_nodepool_system" - cidr = ["10.10.101.0/27"] - nsg_name = "aks_nodepool_system_nsg" - nsg = [] - } - aks_nodepool_user1 = { - name = "aks_nodepool_user1" - cidr = ["10.10.101.32/27"] - nsg_name = "aks_nodepool_user1_nsg" - nsg = [] - } - } - } - -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/examples/102-multiple-vnets-peering/configuration.tfvars b/landingzones/landingzone_networking/examples/102-multiple-vnets-peering/configuration.tfvars deleted file mode 100644 index 615befa1..00000000 --- a/landingzones/landingzone_networking/examples/102-multiple-vnets-peering/configuration.tfvars +++ /dev/null @@ -1,168 +0,0 @@ -resource_groups = { - vnet_sg = { - name = "vnet-sg" - location = "southeastasia" - useprefix = true - max_length = 40 - } -} - -vnets = { - hub_sg = { - resource_group_key = "vnet_sg" - location = "southeastasia" - vnet = { - name = "hub" - address_space = ["10.10.100.0/24"] - } - specialsubnets = { - GatewaySubnet = { - name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway - cidr = ["10.10.100.224/27"] - } - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = ["10.10.100.192/27"] - } - } - subnets = { - Active_Directory = { - name = "Active_Directory" - cidr = ["10.10.100.0/27"] - nsg_name = "Active_Directory_nsg" - nsg = [] - } - AzureBastionSubnet = { - name = "AzureBastionSubnet" #Must be called AzureBastionSubnet - cidr = ["10.10.100.160/27"] - nsg_name = "AzureBastionSubnet_nsg" - nsg = [ - { - name = "bastion-in-allow", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-443", - priority = "120" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "135" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-4443", - priority = "121" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "4443" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-vnet-out-allow-22", - priority = "103" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-vnet-out-allow-3389", - priority = "101" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-azure-out-allow", - priority = "120" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "AzureCloud" - } - ] - } - } - # Override the default var.diagnostics.vnet - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - - spoke_aks_sg = { - resource_group_key = "vnet_sg" - location = "southeastasia" - vnet = { - name = "aks" - address_space = ["10.10.101.0/24"] - } - specialsubnets = {} - subnets = { - aks_nodepool_system = { - name = "aks_nodepool_system" - cidr = ["10.10.101.0/27"] - nsg_name = "aks_nodepool_system_nsg" - nsg = [] - } - aks_nodepool_user1 = { - name = "aks_nodepool_user1" - cidr = ["10.10.101.32/27"] - nsg_name = "aks_nodepool_user1_nsg" - nsg = [] - } - } - } - -} - -peerings = { - hub_sg_TO_spoke_aks_sg = { - from_key = "hub_sg" - to_key = "spoke_aks_sg" - name = "hub_sg_TO_spoke_aks_sg" - allow_virtual_network_access = true - allow_forwarded_traffic = false - allow_gateway_transit = false - use_remote_gateways = false - } - - spoke_aks_sg_TO_hub_sg = { - from_key = "spoke_aks_sg" - to_key = "hub_sg" - name = "spoke_aks_sg_TO_hub_sg" - allow_virtual_network_access = true - allow_forwarded_traffic = false - allow_gateway_transit = false - use_remote_gateways = false - } -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/examples/103-hub-vnet-with-firewall/configuration.tfvars b/landingzones/landingzone_networking/examples/103-hub-vnet-with-firewall/configuration.tfvars deleted file mode 100644 index b7c5279b..00000000 --- a/landingzones/landingzone_networking/examples/103-hub-vnet-with-firewall/configuration.tfvars +++ /dev/null @@ -1,126 +0,0 @@ -resource_groups = { - vnet_sg = { - name = "vnet-hub-sg" - location = "southeastasia" - useprefix = true - max_length = 40 - } -} - -vnets = { - hub_sg = { - resource_group_key = "vnet_sg" - location = "southeastasia" - vnet = { - name = "hub" - address_space = ["10.10.100.0/24"] - } - specialsubnets = { - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = ["10.10.100.192/26"] - } - } - subnets = { - } - # Override the default var.diagnostics.vnet - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - -} - -firewalls = { - # Southeastasia firewall (do not change the key when created) - southeastasia = { - location = "southeastasia" - resource_group_key = "vnet_sg" - vnet_key = "hub_sg" - - # Settings for the public IP address to be used for Azure Firewall - # Must be standard and static for - firewall_ip_addr_config = { - ip_name = "firewall" - allocation_method = "Static" - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the Azure Firewall settings - az_fw_config = { - name = "azfw" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AzureFirewallApplicationRule", true, true, 30], - ["AzureFirewallNetworkRule", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - rules = { - azurerm_firewall_network_rule_collection = { - rule1 = { - name = "Authorize_http_https" - action = "Allow" - priority = 105 - ruleset = [ - { - name = "Authorize_http_https" - source_addresses = [ - "10.0.0.0/8", - ] - destination_ports = [ - "80", "443", - ] - destination_addresses = [ - "*" - ] - protocols = [ - "TCP", - ] - }, - { - name = "Authorize_kerberos" - source_addresses = [ - "10.0.0.0/8", - ] - destination_ports = [ - "88", - ] - destination_addresses = [ - "*" - ] - protocols = [ - "TCP", "UDP", - ] - } - ] - } - } - } - } - - } - -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/examples/104-hub-vnet-with-firewall-bastion/configuration.tfvars b/landingzones/landingzone_networking/examples/104-hub-vnet-with-firewall-bastion/configuration.tfvars deleted file mode 100644 index e4ca7de9..00000000 --- a/landingzones/landingzone_networking/examples/104-hub-vnet-with-firewall-bastion/configuration.tfvars +++ /dev/null @@ -1,198 +0,0 @@ -resource_groups = { - vnet_sg = { - name = "vnet-hub-sg" - location = "southeastasia" - useprefix = true - max_length = 40 - } -} - -vnets = { - hub_sg = { - resource_group_key = "vnet_sg" - location = "southeastasia" - vnet = { - name = "hub" - address_space = ["10.10.100.0/24"] - } - specialsubnets = { - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = ["10.10.100.192/26"] - } - } - subnets = { - AzureBastionSubnet = { - name = "AzureBastionSubnet" #Must be called AzureBastionSubnet - cidr = ["10.10.100.160/27"] - nsg_name = "AzureBastionSubnet_nsg" - nsg = [ - { - name = "bastion-in-allow", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-443", - priority = "120" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "135" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-4443", - priority = "121" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "4443" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-vnet-out-allow-22", - priority = "103" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-vnet-out-allow-3389", - priority = "101" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-azure-out-allow", - priority = "120" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "AzureCloud" - } - ] - } - } - # Override the default var.diagnostics.vnet - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - -} - -firewalls = { - # Southeastasia firewall (do not change the key when created) - southeastasia = { - location = "southeastasia" - resource_group_key = "vnet_sg" - vnet_key = "hub_sg" - - # Settings for the public IP address to be used for Azure Firewall - # Must be standard and static for - firewall_ip_addr_config = { - ip_name = "firewall" - allocation_method = "Static" - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the Azure Firewall settings - az_fw_config = { - name = "azfw" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AzureFirewallApplicationRule", true, true, 30], - ["AzureFirewallNetworkRule", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - rules = {} - } - - } - -} - -bastions = { - southeastasia = { - location = "southeastasia" - resource_group_key = "vnet_sg" - vnet_key = "hub_sg" - subnet_key = "AzureBastionSubnet" - - bastion_ip_addr_config = { - ip_name = "firewall" - allocation_method = "Static" - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - bastion_config = { - name = "bastion" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["BastionAuditLogs", true, true, 30], - ] - metric = [ - ] - } - } - } -} diff --git a/landingzones/landingzone_networking/examples/105-hub-virtual-wan-firewall/configuration.tfvars b/landingzones/landingzone_networking/examples/105-hub-virtual-wan-firewall/configuration.tfvars deleted file mode 100644 index 8750be08..00000000 --- a/landingzones/landingzone_networking/examples/105-hub-virtual-wan-firewall/configuration.tfvars +++ /dev/null @@ -1,291 +0,0 @@ -resource_groups = { - vnet_sg = { - name = "vnet-hub-sg" - location = "southeastasia" - useprefix = true - max_length = 40 - } -} - -vnets = { - hub_sg = { - resource_group_key = "vnet_sg" - location = "southeastasia" - vnet = { - name = "hub" - address_space = ["10.10.100.0/24"] - } - specialsubnets = { - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = ["10.10.100.192/26"] - } - } - subnets = { - AzureBastionSubnet = { - name = "AzureBastionSubnet" #Must be called AzureBastionSubnet - cidr = ["10.10.100.160/27"] - nsg_name = "AzureBastionSubnet_nsg" - nsg = [ - { - name = "bastion-in-allow", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-443", - priority = "120" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "135" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-4443", - priority = "121" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "4443" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-vnet-out-allow-22", - priority = "103" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-vnet-out-allow-3389", - priority = "101" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-azure-out-allow", - priority = "120" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "AzureCloud" - } - ] - } - } - # Override the default var.diagnostics.vnet - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - -} - -# firewalls = { -# # Southeastasia firewall (do not change the key when created) -# southeastasia = { -# location = "southeastasia" -# resource_group_key = "vnet_sg" -# vnet_key = "hub_sg" - -# # Settings for the public IP address to be used for Azure Firewall -# # Must be standard and static for -# firewall_ip_addr_config = { -# ip_name = "firewall" -# allocation_method = "Static" -# sku = "Standard" #defaults to Basic -# ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both -# diagnostics = { -# log = [ -# #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] -# ["DDoSProtectionNotifications", true, true, 30], -# ["DDoSMitigationFlowLogs", true, true, 30], -# ["DDoSMitigationReports", true, true, 30], -# ] -# metric = [ -# ["AllMetrics", true, true, 30], -# ] -# } -# } - -# # Settings for the Azure Firewall settings -# az_fw_config = { -# name = "azfw" -# diagnostics = { -# log = [ -# #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] -# ["AzureFirewallApplicationRule", true, true, 30], -# ["AzureFirewallNetworkRule", true, true, 30], -# ] -# metric = [ -# ["AllMetrics", true, true, 30], -# ] -# } -# } - -# } - -# } - -# bastions = { -# southeastasia = { -# location = "southeastasia" -# resource_group_key = "vnet_sg" -# vnet_key = "hub_sg" -# subnet_key = "AzureBastionSubnet" - -# bastion_ip_addr_config = { -# ip_name = "firewall" -# allocation_method = "Static" -# sku = "Standard" #defaults to Basic -# ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both -# diagnostics = { -# log = [ -# #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] -# ["DDoSProtectionNotifications", true, true, 30], -# ["DDoSMitigationFlowLogs", true, true, 30], -# ["DDoSMitigationReports", true, true, 30], -# ] -# metric = [ -# ["AllMetrics", true, true, 30], -# ] -# } -# } - -# bastion_config = { -# name = "bastion" -# diagnostics = { -# log = [ -# #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] -# ["BastionAuditLogs", true, true, 30], -# ] -# metric = [ -# ] -# } -# } -# } -# } - -vwans = { - southeastasia = { - resource_group_key = "vnet_sg" - name = "ContosovWAN" - - hubs = { - hub1 = { - hub_name = "SEA-HUB" - region = "southeastasia" - hub_address_prefix = "10.0.3.0/24" - deploy_firewall = true - peerings = {} - firewall_name = "azfwsg" - firewall_resource_groupe_name = "azfwsg" - deploy_p2s = false - p2s_config = { - name = "caf-sea-vpn-p2s" - scale_unit = 2 - connection_configuration = { - name = "client-connections" - vpn_client_address_pool = { - address_prefixes = ["192.168.0.0/24"] - } - } - server_config = { - vpn_authentication_types = ["Certificate"] - client_root_certificate = { - name = "DigiCert-Federated-ID-Root-CA" - public_cert_data = < - # optional if the virtual network has been provisionned outside. - hub_to_vitual_network_traffic_allowed = true - vitual_network_to_hub_gateways_traffic_allowed = true - internet_security_enabled = false - } - } - deploy_p2s = false - p2s_config = {} - deploy_s2s = false - s2s_config = {} - deploy_er = false - er_config = {} - } - } - } -} diff --git a/landingzones/landingzone_networking/examples/201-hub-spoke-vnets-firewall/configuration.tfvars b/landingzones/landingzone_networking/examples/201-hub-spoke-vnets-firewall/configuration.tfvars deleted file mode 100644 index 6166ddaf..00000000 --- a/landingzones/landingzone_networking/examples/201-hub-spoke-vnets-firewall/configuration.tfvars +++ /dev/null @@ -1,288 +0,0 @@ -resource_groups = { - vnet_sg = { - name = "vnet-sg" - location = "southeastasia" - useprefix = true - max_length = 40 - } -} - -vnets = { - hub_sg = { - resource_group_key = "vnet_sg" - location = "southeastasia" - vnet = { - name = "hub" - address_space = ["10.10.100.0/24"] - } - specialsubnets = { - AzureFirewallSubnet = { - name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet - cidr = ["10.10.100.192/26"] - } - } - subnets = { - Active_Directory = { - name = "Active_Directory" - cidr = ["10.10.100.0/27"] - nsg_name = "Active_Directory_nsg" - nsg = [] - } - AzureBastionSubnet = { - name = "AzureBastionSubnet" #Must be called AzureBastionSubnet - cidr = ["10.10.100.160/27"] - nsg_name = "AzureBastionSubnet_nsg" - nsg = [ - { - name = "bastion-in-allow", - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-443", - priority = "120" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "135" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-control-in-allow-4443", - priority = "121" - direction = "Inbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "4443" - source_address_prefix = "GatewayManager" - destination_address_prefix = "*" - }, - { - name = "bastion-vnet-out-allow-22", - priority = "103" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-vnet-out-allow-3389", - priority = "101" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "VirtualNetwork" - }, - { - name = "bastion-azure-out-allow", - priority = "120" - direction = "Outbound" - access = "Allow" - protocol = "tcp" - source_port_range = "*" - destination_port_range = "443" - source_address_prefix = "*" - destination_address_prefix = "AzureCloud" - } - ] - } - } - # Override the default var.diagnostics.vnet - diagnostics = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } - - spoke_aks_sg = { - resource_group_key = "vnet_sg" - location = "southeastasia" - vnet = { - name = "aks" - address_space = ["10.10.101.0/24"] - } - specialsubnets = {} - subnets = { - aks_nodepool_system = { - name = "aks_nodepool_system" - cidr = ["10.10.101.0/27"] - nsg_name = "aks_nodepool_system_nsg" - nsg = [] - } - aks_nodepool_user1 = { - name = "aks_nodepool_user1" - cidr = ["10.10.101.32/27"] - nsg_name = "aks_nodepool_user1_nsg" - nsg = [] - } - } - } - -} - -firewalls = { - # Southeastasia firewall (do not change the key when created) - southeastasia = { - location = "southeastasia" - resource_group_key = "vnet_sg" - vnet_key = "hub_sg" - - # Settings for the public IP address to be used for Azure Firewall - # Must be standard and static for - firewall_ip_addr_config = { - ip_name = "firewall" - allocation_method = "Static" - sku = "Standard" #defaults to Basic - ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["DDoSProtectionNotifications", true, true, 30], - ["DDoSMitigationFlowLogs", true, true, 30], - ["DDoSMitigationReports", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - } - - # Settings for the Azure Firewall settings - az_fw_config = { - name = "azfw" - diagnostics = { - log = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AzureFirewallApplicationRule", true, true, 30], - ["AzureFirewallNetworkRule", true, true, 30], - ["AzureFirewallDnsProxy", true, true, 30], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } - rules = { - azurerm_firewall_network_rule_collection = { - rule1 = { - name = "Authorize_http_https" - action = "Allow" - priority = 105 - ruleset = [ - { - name = "Authorize_http_https" - source_addresses = [ - "10.0.0.0/8", - ] - destination_ports = [ - "80", "443", - ] - destination_addresses = [ - "*" - ] - protocols = [ - "TCP", - ] - }, - { - name = "Authorize_kerberos" - source_addresses = [ - "10.0.0.0/8", - ] - destination_ports = [ - "88", - ] - destination_addresses = [ - "*" - ] - protocols = [ - "TCP", "UDP", - ] - } - ] - } - } - } - } - - } - -} - -peerings = { - hub_sg_TO_spoke_aks_sg = { - from_key = "hub_sg" - to_key = "spoke_aks_sg" - name = "hub_sg_TO_spoke_aks_sg" - allow_virtual_network_access = true - allow_forwarded_traffic = false - allow_gateway_transit = false - use_remote_gateways = false - } - - spoke_aks_sg_TO_hub_sg = { - from_key = "spoke_aks_sg" - to_key = "hub_sg" - name = "spoke_aks_sg_TO_hub_sg" - allow_virtual_network_access = true - allow_forwarded_traffic = false - allow_gateway_transit = false - use_remote_gateways = false - } -} - -route_tables = { - from_spoke_to_hub = { - name = "spoke_aks_sg_to_hub_sg" - resource_group_key = "vnet_sg" - - vnet_keys = { - "spoke_aks_sg" = { - subnet_keys = ["aks_nodepool_system", "aks_nodepool_user1"] - } - } - - route_entries = { - re1 = { - name = "defaultroute" - prefix = "0.0.0.0/0" - next_hop_type = "VirtualAppliance" - azfw = { - VirtualAppliance_key = "southeastasia" - ipconfig_index = 0 - } - } - re2 = { - name = "testspecialroute" - prefix = "192.168.1.1/32" - next_hop_type = "VirtualAppliance" - next_hop_in_ip_address = "1.1.1.1" - } - re3 = { - name = "testspecialroute2" - prefix = "16.0.0.0/8" - next_hop_type = "Internet" - } - } - } -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/firewall.tf b/landingzones/landingzone_networking/firewall.tf deleted file mode 100644 index 7a696867..00000000 --- a/landingzones/landingzone_networking/firewall.tf +++ /dev/null @@ -1,57 +0,0 @@ -## Azure Firewall configuration -module "az_firewall_ip" { - source = "aztfmod/caf-public-ip/azurerm" - version = "2.1.0" - - for_each = var.firewalls - - convention = lookup(each.value, "convention", local.global_settings.convention) - name = each.value.firewall_ip_addr_config.ip_name - location = each.value.location - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - ip_addr = each.value.firewall_ip_addr_config - tags = local.tags - diagnostics_map = local.caf_foundations_accounting[each.value.location].diagnostics_map - log_analytics_workspace_id = local.caf_foundations_accounting[each.value.location].log_analytics_workspace.id - diagnostics_settings = each.value.firewall_ip_addr_config.diagnostics -} - -module "az_firewall" { - source = "aztfmod/caf-azure-firewall/azurerm" - version = "2.1.0" - - for_each = var.firewalls - - convention = lookup(each.value, "convention", local.global_settings.convention) - name = each.value.az_fw_config.name - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - subnet_id = module.vnets[each.value.vnet_key].vnet_subnets["AzureFirewallSubnet"] - public_ip_id = module.az_firewall_ip[each.key].id - location = each.value.location - tags = local.tags - diagnostics_map = local.caf_foundations_accounting[each.value.location].diagnostics_map - la_workspace_id = local.caf_foundations_accounting[each.value.location].log_analytics_workspace.id - diagnostics_settings = each.value.az_fw_config.diagnostics -} - -module "firewall_dashboard" { - source = "./modules/firewall_dashboard" - - for_each = var.firewalls - - fw_id = module.az_firewall[each.key].id - pip_id = module.az_firewall_ip[each.key].id - location = each.value.location - rg = azurerm_resource_group.rg[each.value.resource_group_key].name - name = "${local.prefix_with_hyphen}${basename(abspath(path.module))}" - tags = local.tags -} - -module "firewall_rules" { - source = "./modules/firewall_rules" - - for_each = var.firewalls - - az_firewall_settings = module.az_firewall[each.key].az_firewall_config - az_firewall_rules = each.value.az_fw_config.rules -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/main.tf b/landingzones/landingzone_networking/main.tf deleted file mode 100644 index 81d74d8a..00000000 --- a/landingzones/landingzone_networking/main.tf +++ /dev/null @@ -1,42 +0,0 @@ -provider "azurerm" { - features {} -} - -terraform { - required_providers { - azurecaf = { - source = "aztfmod/azurecaf" - version = "~> 0.4.3" - } - azurerm = { - source = "hashicorp/azurerm" - version = "~> 2.25.0" - } - } - required_version = ">= 0.13" -} - -locals { - landingzone_tag = { - "landingzone" = basename(abspath(path.module)) - } - tags = merge(var.tags, local.landingzone_tag, { "environment" = local.global_settings.environment }) -} - -data "terraform_remote_state" "landingzone_caf_foundations" { - backend = "azurerm" - config = { - storage_account_name = var.lowerlevel_storage_account_name - container_name = var.workspace - key = "landingzone_caf_foundations.tfstate" - resource_group_name = var.lowerlevel_resource_group_name - } -} - -locals { - prefix = data.terraform_remote_state.landingzone_caf_foundations.outputs.prefix - prefix_with_hyphen = local.prefix == "" ? "" : "${local.prefix}-" - caf_foundations_accounting = data.terraform_remote_state.landingzone_caf_foundations.outputs.foundations_accounting - caf_foundations_security = data.terraform_remote_state.landingzone_caf_foundations.outputs.foundations_security - global_settings = data.terraform_remote_state.landingzone_caf_foundations.outputs.global_settings -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/modules/firewall_dashboard/egress-dashboard.tpl b/landingzones/landingzone_networking/modules/firewall_dashboard/egress-dashboard.tpl deleted file mode 100644 index a39ba906..00000000 --- a/landingzones/landingzone_networking/modules/firewall_dashboard/egress-dashboard.tpl +++ /dev/null @@ -1,716 +0,0 @@ - { - "lenses": { - "0": { - "order": 0, - "parts": { - "0": { - "position": { - "x": 0, - "y": 0, - "colSpan": 16, - "rowSpan": 1 - }, - "metadata": { - "inputs": [], - "type": "Extension/HubsExtension/PartType/MarkdownPart", - "settings": { - "content": { - "settings": { - "content": "", - "title": "Edge Monitoring ", - "subtitle": "" - } - } - } - } - }, - "1": { - "position": { - "x": 0, - "y": 1, - "colSpan": 8, - "rowSpan": 6 - }, - "metadata": { - "inputs": [ - { - "name": "sharedTimeRange", - "isOptional": true - }, - { - "name": "options", - "value": { - "chart": { - "metrics": [ - { - "resourceMetadata": { - "id": "${fw_id}" - }, - "name": "ApplicationRuleHit", - "aggregationType": 1, - "namespace": "microsoft.network/azurefirewalls", - "metricVisualization": { - "displayName": "Application rules hit count" - } - }, - { - "resourceMetadata": { - "id": "${fw_id}" - }, - "name": "DataProcessed", - "aggregationType": 1, - "namespace": "microsoft.network/azurefirewalls", - "metricVisualization": { - "displayName": "Data processed" - } - }, - { - "resourceMetadata": { - "id": "${fw_id}" - }, - "name": "FirewallHealth", - "aggregationType": 4, - "namespace": "microsoft.network/azurefirewalls", - "metricVisualization": { - "displayName": "Firewall health state" - } - }, - { - "resourceMetadata": { - "id": "${fw_id}" - }, - "name": "NetworkRuleHit", - "aggregationType": 1, - "namespace": "microsoft.network/azurefirewalls", - "metricVisualization": { - "displayName": "Network rules hit count" - } - }, - { - "resourceMetadata": { - "id": "${fw_id}" - }, - "name": "SNATPortUtilization", - "aggregationType": 4, - "namespace": "microsoft.network/azurefirewalls", - "metricVisualization": { - "displayName": "SNAT port utilization" - } - } - ], - "title": "Sum Application rules hit count, Sum Data processed, and 3 other metrics for az-fw-arnaud", - "titleKind": 1, - "visualization": { - "chartType": 2, - "legendVisualization": { - "isVisible": true, - "position": 2, - "hideSubtitle": false - }, - "axisVisualization": { - "x": { - "isVisible": true, - "axisType": 2 - }, - "y": { - "isVisible": true, - "axisType": 1 - } - } - } - }, - "version": 2 - }, - "isOptional": true - } - ], - "type": "Extension/HubsExtension/PartType/MonitorChartPart", - "settings": { - "content": { - "options": { - "chart": { - "metrics": [ - { - "resourceMetadata": { - "id": "${fw_id}" - }, - "name": "ApplicationRuleHit", - "aggregationType": 1, - "namespace": "microsoft.network/azurefirewalls", - "metricVisualization": { - "displayName": "Application rules hit count" - } - }, - { - "resourceMetadata": { - "id": "${fw_id}" - }, - "name": "DataProcessed", - "aggregationType": 1, - "namespace": "microsoft.network/azurefirewalls", - "metricVisualization": { - "displayName": "Data processed" - } - }, - { - "resourceMetadata": { - "id": "${fw_id}" - }, - "name": "FirewallHealth", - "aggregationType": 4, - "namespace": "microsoft.network/azurefirewalls", - "metricVisualization": { - "displayName": "Firewall health state" - } - }, - { - "resourceMetadata": { - "id": "${fw_id}" - }, - "name": "NetworkRuleHit", - "aggregationType": 1, - "namespace": "microsoft.network/azurefirewalls", - "metricVisualization": { - "displayName": "Network rules hit count" - } - }, - { - "resourceMetadata": { - "id": "${fw_id}" - }, - "name": "SNATPortUtilization", - "aggregationType": 4, - "namespace": "microsoft.network/azurefirewalls", - "metricVisualization": { - "displayName": "SNAT port utilization" - } - } - ], - "title": "Azure Firewall - Egress Overview", - "titleKind": 2, - "visualization": { - "chartType": 2, - "legendVisualization": { - "isVisible": true, - "position": 2, - "hideSubtitle": false - }, - "axisVisualization": { - "x": { - "isVisible": true, - "axisType": 2 - }, - "y": { - "isVisible": true, - "axisType": 1 - } - }, - "disablePinning": true - } - }, - "version": 2 - } - } - } - } - }, - "2": { - "position": { - "x": 8, - "y": 1, - "colSpan": 8, - "rowSpan": 6 - }, - "metadata": { - "inputs": [ - { - "name": "sharedTimeRange", - "isOptional": true - }, - { - "name": "options", - "value": { - "chart": { - "metrics": [ - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "ByteCount", - "aggregationType": 1, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Byte Count" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "PacketCount", - "aggregationType": 1, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Packet Count" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "SynCount", - "aggregationType": 1, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "SYN Count" - } - } - ], - "title": "Public IP - Egress Overview", - "titleKind": 2, - "visualization": { - "chartType": 2, - "legendVisualization": { - "isVisible": true, - "position": 2, - "hideSubtitle": false - }, - "axisVisualization": { - "x": { - "isVisible": true, - "axisType": 2 - }, - "y": { - "isVisible": true, - "axisType": 1 - } - } - } - }, - "version": 2 - }, - "isOptional": true - } - ], - "type": "Extension/HubsExtension/PartType/MonitorChartPart", - "settings": { - "content": { - "options": { - "chart": { - "metrics": [ - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "ByteCount", - "aggregationType": 1, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Byte Count" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "PacketCount", - "aggregationType": 1, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Packet Count" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "SynCount", - "aggregationType": 1, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "SYN Count" - } - } - ], - "title": "Public IP - Egress Overview", - "titleKind": 2, - "visualization": { - "chartType": 2, - "legendVisualization": { - "isVisible": true, - "position": 2, - "hideSubtitle": false - }, - "axisVisualization": { - "x": { - "isVisible": true, - "axisType": 2 - }, - "y": { - "isVisible": true, - "axisType": 1 - } - }, - "disablePinning": true - } - }, - "version": 2 - } - } - } - } - }, - "3": { - "position": { - "x": 0, - "y": 7, - "colSpan": 8, - "rowSpan": 5 - }, - "metadata": { - "inputs": [ - { - "name": "sharedTimeRange", - "isOptional": true - }, - { - "name": "options", - "value": { - "chart": { - "metrics": [ - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "BytesInDDoS", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Inbound bytes DDoS" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "BytesDroppedDDoS", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Inbound bytes dropped DDoS" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "TCPBytesInDDoS", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Inbound TCP bytes DDoS" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "DDoSTriggerSYNPackets", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Inbound SYN packets to trigger DDoS mitigation" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "UDPBytesInDDoS", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Inbound UDP bytes DDoS" - } - } - ], - "title": "DDoS Statistics", - "titleKind": 1, - "visualization": { - "chartType": 2, - "legendVisualization": { - "isVisible": true, - "position": 2, - "hideSubtitle": false - }, - "axisVisualization": { - "x": { - "isVisible": true, - "axisType": 2 - }, - "y": { - "isVisible": true, - "axisType": 1 - } - } - } - }, - "version": 2 - }, - "isOptional": true - } - ], - "type": "Extension/HubsExtension/PartType/MonitorChartPart", - "settings": { - "content": { - "options": { - "chart": { - "metrics": [ - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "BytesInDDoS", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Inbound bytes DDoS" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "BytesDroppedDDoS", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Inbound bytes dropped DDoS" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "TCPBytesInDDoS", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Inbound TCP bytes DDoS" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "DDoSTriggerSYNPackets", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Inbound SYN packets to trigger DDoS mitigation" - } - }, - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "UDPBytesInDDoS", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Inbound UDP bytes DDoS" - } - } - ], - "title": "IP address - Egress - DDoS Overview", - "titleKind": 2, - "visualization": { - "chartType": 2, - "legendVisualization": { - "isVisible": true, - "position": 2, - "hideSubtitle": false - }, - "axisVisualization": { - "x": { - "isVisible": true, - "axisType": 2 - }, - "y": { - "isVisible": true, - "axisType": 1 - } - }, - "disablePinning": true - } - }, - "version": 2 - } - } - } - } - }, - "4": { - "position": { - "x": 8, - "y": 7, - "colSpan": 8, - "rowSpan": 5 - }, - "metadata": { - "inputs": [ - { - "name": "sharedTimeRange", - "isOptional": true - }, - { - "name": "options", - "value": { - "chart": { - "metrics": [ - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "IfUnderDDoSAttack", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Under DDoS attack or not" - } - } - ], - "title": "Max Under DDoS attack or not for arnaud-pip-egress", - "titleKind": 1, - "visualization": { - "chartType": 1, - "legendVisualization": { - "isVisible": true, - "position": 2, - "hideSubtitle": false - }, - "axisVisualization": { - "x": { - "isVisible": true, - "axisType": 2 - }, - "y": { - "isVisible": true, - "axisType": 1 - } - } - } - }, - "version": 2 - }, - "isOptional": true - } - ], - "type": "Extension/HubsExtension/PartType/MonitorChartPart", - "settings": { - "content": { - "options": { - "chart": { - "metrics": [ - { - "resourceMetadata": { - "id": "${pip_id}" - }, - "name": "IfUnderDDoSAttack", - "aggregationType": 3, - "namespace": "microsoft.network/publicipaddresses", - "metricVisualization": { - "displayName": "Under DDoS attack or not" - } - } - ], - "title": "DDoS Attack Detected", - "titleKind": 2, - "visualization": { - "chartType": 1, - "legendVisualization": { - "isVisible": true, - "position": 2, - "hideSubtitle": false - }, - "axisVisualization": { - "x": { - "isVisible": true, - "axisType": 2 - }, - "y": { - "isVisible": true, - "axisType": 1 - } - }, - "disablePinning": true - } - }, - "version": 2 - } - } - } - } - }, - "5": { - "position": { - "x": 0, - "y": 12, - "colSpan": 16, - "rowSpan": 1 - }, - "metadata": { - "inputs": [], - "type": "Extension/HubsExtension/PartType/MarkdownPart", - "settings": { - "content": { - "settings": { - "content": "", - "title": "Virtual Network Monitoring", - "subtitle": "" - } - } - } - } - } - } - } - }, - "metadata": { - "model": { - "timeRange": { - "value": { - "relative": { - "duration": 24, - "timeUnit": 1 - } - }, - "type": "MsPortalFx.Composition.Configuration.ValueTypes.TimeRange" - }, - "filterLocale": { - "value": "en-us" - }, - "filters": { - "value": { - "MsPortalFx_TimeRange": { - "model": { - "format": "utc", - "granularity": "auto", - "relative": "24h" - }, - "displayCache": { - "name": "UTC Time", - "value": "Past 24 hours" - }, - "filteredPartIds": [ - "StartboardPart-MonitorChartPart-1bd243d6-36d8-4329-8ed0-02aa14c243e3", - "StartboardPart-MonitorChartPart-1bd243d6-36d8-4329-8ed0-02aa14c245fc", - "StartboardPart-MonitorChartPart-1bd243d6-36d8-4329-8ed0-02aa14c24788", - "StartboardPart-MonitorChartPart-1bd243d6-36d8-4329-8ed0-02aa14c24a01" - ] - } - } - } - } - } - } \ No newline at end of file diff --git a/landingzones/landingzone_networking/modules/firewall_dashboard/module.tf b/landingzones/landingzone_networking/modules/firewall_dashboard/module.tf deleted file mode 100644 index bf81fc08..00000000 --- a/landingzones/landingzone_networking/modules/firewall_dashboard/module.tf +++ /dev/null @@ -1,15 +0,0 @@ -resource "azurerm_dashboard" "egress_dashboard" { - name = var.name - resource_group_name = var.rg - location = var.location - tags = var.tags - - dashboard_properties = templatefile("${path.module}/egress-dashboard.tpl", - { - md_content = "CAF landing zones - Egress Dashboard" - - pip_id = var.pip_id - fw_id = var.fw_id - }) -} - diff --git a/landingzones/landingzone_networking/modules/firewall_dashboard/variables.tf b/landingzones/landingzone_networking/modules/firewall_dashboard/variables.tf deleted file mode 100644 index 57c6c416..00000000 --- a/landingzones/landingzone_networking/modules/firewall_dashboard/variables.tf +++ /dev/null @@ -1,25 +0,0 @@ -variable "fw_id" { - -} - -variable "pip_id" { - -} - -variable "name" { - -} - -variable "rg" { - -} - -variable "location" { - -} - -variable "tags" { - -} - - diff --git a/landingzones/landingzone_networking/modules/firewall_rules/application_rule_collection.tf b/landingzones/landingzone_networking/modules/firewall_rules/application_rule_collection.tf deleted file mode 100644 index e7c3f5dd..00000000 --- a/landingzones/landingzone_networking/modules/firewall_rules/application_rule_collection.tf +++ /dev/null @@ -1,30 +0,0 @@ -# processing of the rules for: -# azurerm_firewall_application_rule_collection - https://www.terraform.io/docs/providers/azurerm/r/firewall_application_rule_collection.html - -resource "azurerm_firewall_application_rule_collection" "appcollection" { - for_each = lookup(var.az_firewall_rules, "azurerm_firewall_application_rule_collection", {}) - - name = each.value.name - azure_firewall_name = var.az_firewall_settings.az_fw_name - resource_group_name = var.az_firewall_settings.az_object.resource_group_name - priority = each.value.priority - action = each.value.action - - dynamic "rule" { - for_each = each.value.ruleset - content { - name = rule.value.name - description = lookup(rule.value, "description", null) - source_addresses = rule.value.source_addresses - fqdn_tags = lookup(rule.value, "fqdn_tags", null) - target_fqdns = lookup(rule.value, "target_fqdns", null) - dynamic "protocol" { - for_each = lookup(rule.value, "protocol", []) - content { - type = protocol.value.type - port = lookup(protocol.value, "port", null) - } - } - } - } -} diff --git a/landingzones/landingzone_networking/modules/firewall_rules/nat_rule_collection.tf b/landingzones/landingzone_networking/modules/firewall_rules/nat_rule_collection.tf deleted file mode 100644 index af205c78..00000000 --- a/landingzones/landingzone_networking/modules/firewall_rules/nat_rule_collection.tf +++ /dev/null @@ -1,26 +0,0 @@ -# processing of the rules for: -# azurerm_firewall_nat_rule_collection - https://www.terraform.io/docs/providers/azurerm/r/firewall_nat_rule_collection.html - -resource "azurerm_firewall_nat_rule_collection" "natcollection" { - for_each = lookup(var.az_firewall_rules, "azurerm_firewall_nat_rule_collection", {}) - - name = each.value.name - azure_firewall_name = var.az_firewall_settings.az_fw_name - resource_group_name = var.az_firewall_settings.az_object.resource_group_name - priority = each.value.priority - action = each.value.action - - dynamic "rule" { - for_each = each.value.ruleset - content { - name = rule.value.name - description = lookup(rule.value, "description", null) - source_addresses = rule.value.source_addresses - destination_ports = rule.value.destination_ports - destination_addresses = rule.value.destination_addresses - translated_port = rule.value.translated_port - translated_address = rule.value.translated_address - protocols = rule.value.protocols - } - } -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/modules/firewall_rules/network_rule_collection.tf b/landingzones/landingzone_networking/modules/firewall_rules/network_rule_collection.tf deleted file mode 100644 index a6d1c9ea..00000000 --- a/landingzones/landingzone_networking/modules/firewall_rules/network_rule_collection.tf +++ /dev/null @@ -1,25 +0,0 @@ -# processing of the rules for: -# azurerm_firewall_network_rule_collection - https://www.terraform.io/docs/providers/azurerm/r/firewall_network_rule_collection.html -# azurerm_firewall_nat_rule_collection - https://www.terraform.io/docs/providers/azurerm/r/firewall_nat_rule_collection.html -# FQDN for azurerm_firewall_network_rule_collection https://github.com/terraform-providers/terraform-provider-azurerm/issues/7743 -resource "azurerm_firewall_network_rule_collection" "netcollection" { - for_each = lookup(var.az_firewall_rules, "azurerm_firewall_network_rule_collection", {}) - - name = each.value.name - azure_firewall_name = var.az_firewall_settings.az_fw_name - resource_group_name = var.az_firewall_settings.az_object.resource_group_name - priority = each.value.priority - action = each.value.action - - dynamic "rule" { - for_each = each.value.ruleset - content { - name = rule.value.name - description = lookup(rule.value, "description", null) - source_addresses = rule.value.source_addresses - destination_ports = rule.value.destination_ports - destination_addresses = rule.value.destination_addresses - protocols = rule.value.protocols - } - } -} diff --git a/landingzones/landingzone_networking/modules/firewall_rules/variables.tf b/landingzones/landingzone_networking/modules/firewall_rules/variables.tf deleted file mode 100644 index 56f075c7..00000000 --- a/landingzones/landingzone_networking/modules/firewall_rules/variables.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "az_firewall_settings" { - description = "Azure Firewall Object" -} - -variable "az_firewall_rules" { - description = "Azure Firewall Rules Object" -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/output.tf b/landingzones/landingzone_networking/output.tf deleted file mode 100644 index 65f786e5..00000000 --- a/landingzones/landingzone_networking/output.tf +++ /dev/null @@ -1,12 +0,0 @@ -output vnets { - value = module.vnets - sensitive = true - description = "Map of the vnet objects" -} - -output firewalls { - value = module.az_firewall - sensitive = true - description = "Map of the firewalls" -} - diff --git a/landingzones/landingzone_networking/resource_groups.tf b/landingzones/landingzone_networking/resource_groups.tf deleted file mode 100644 index 72bd504c..00000000 --- a/landingzones/landingzone_networking/resource_groups.tf +++ /dev/null @@ -1,18 +0,0 @@ -resource "azurecaf_naming_convention" "rg" { - for_each = var.resource_groups - - name = each.value.name - resource_type = "azurerm_resource_group" - convention = lookup(each.value, "convention", local.global_settings.convention) - prefix = lookup(each.value, "useprefix", false) == true ? local.prefix : "" - max_length = lookup(each.value, "max_length", null) -} - -resource "azurerm_resource_group" "rg" { - for_each = var.resource_groups - - name = azurecaf_naming_convention.rg[each.key].result - location = lookup(each.value, "location", local.global_settings.default_location) - tags = merge(lookup(each.value, "tags", {}), local.tags) -} - diff --git a/landingzones/landingzone_networking/route_table.tf b/landingzones/landingzone_networking/route_table.tf deleted file mode 100644 index b99180a0..00000000 --- a/landingzones/landingzone_networking/route_table.tf +++ /dev/null @@ -1,20 +0,0 @@ -resource "azurerm_route_table" "route_table" { - for_each = var.route_tables - - name = each.value.name - location = lookup(each.value, "location", local.global_settings.default_location) - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - tags = local.tags - disable_bgp_route_propagation = lookup(each.value, "disable_bgp_route_propagation", null) - - dynamic "route" { - for_each = each.value.route_entries - content { - name = route.value.name - address_prefix = route.value.prefix - next_hop_type = route.value.next_hop_type - next_hop_in_ip_address = (route.value.next_hop_type == "VirtualAppliance") ? (contains(keys(route.value), "azfw") == true ? module.az_firewall[route.value.azfw.VirtualAppliance_key].object.ip_configuration[route.value.azfw.ipconfig_index].private_ip_address : route.value.next_hop_in_ip_address) : null - } - } -} - diff --git a/landingzones/landingzone_networking/route_table_association.tf b/landingzones/landingzone_networking/route_table_association.tf deleted file mode 100644 index 073b5499..00000000 --- a/landingzones/landingzone_networking/route_table_association.tf +++ /dev/null @@ -1,19 +0,0 @@ -locals { - route_tables_subnets = { - for key, value in var.route_tables : key => flatten([ - for vnet_key, vnet_value in lookup(value, "vnet_keys", []) : [ - for subnet in lookup(vnet_value, "subnet_keys", []) : module.vnets[vnet_key].vnet_subnets[subnet] - ] - ]) - } -} - -resource "azurerm_subnet_route_table_association" "route_subnet" { - depends_on = [azurerm_route_table.route_table] - - for_each = transpose(local.route_tables_subnets) - - subnet_id = each.key - route_table_id = azurerm_route_table.route_table[each.value[0]].id -} - diff --git a/landingzones/landingzone_networking/variables.tf b/landingzones/landingzone_networking/variables.tf deleted file mode 100644 index 1ecc0f70..00000000 --- a/landingzones/landingzone_networking/variables.tf +++ /dev/null @@ -1,62 +0,0 @@ -# Map of the remote data state for lower level -variable lowerlevel_storage_account_name {} -variable lowerlevel_container_name {} -variable lowerlevel_key {} # Keeping the key for the lower level0 access -variable lowerlevel_resource_group_name {} -variable workspace {} - -variable tags { - type = map - default = {} -} - -variable vnets { - description = "Map of vnet objects" -} - -variable peerings { - description = "(Optional) Map of peering objects" - default = {} -} - -variable firewalls { - description = "(Optional) Map of firewall objects" - default = {} -} - -variable bastions { - description = "(Optional) Map of Azure Bastions objects" - default = {} -} - -variable vwans { - description = "(Optional) Map of virtual wan objects" - default = {} -} - -variable ddos_services { - description = "(Optional) Map of ddos objects" - default = {} -} - -variable route_tables { - description = "(Optional) User define route object" - default = {} -} - -variable resource_groups {} - -variable diagnostics { - default = { - vnet = { - log = [ - # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["VMProtectionAlerts", true, true, 60], - ] - metric = [ - #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period] - ["AllMetrics", true, true, 60], - ] - } - } -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/vhub_peering.tf b/landingzones/landingzone_networking/vhub_peering.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/landingzones/landingzone_networking/virtual_hub/arm_template_vhub_firewall.json b/landingzones/landingzone_networking/virtual_hub/arm_template_vhub_firewall.json deleted file mode 100644 index e82ac981..00000000 --- a/landingzones/landingzone_networking/virtual_hub/arm_template_vhub_firewall.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "vwan_id": { - "type": "string", - "metadata": { - "displayName": "ID of the virtual WAN object", - "description": "ID of the virtual WAN object" - } - }, - "name": { - "type": "string", - "metadata": { - "displayName": "Name of the Azure Firewall", - "description": "Name of the Azure Firewall" - } - }, - "location": { - "type": "string", - "metadata": { - "displayName": "Location of the Azure Firewall", - "description": "Location of the Azure Firewall" - } - }, - "Tier": { - "type": "string", - "metadata": { - "displayName": "Tier of the Azure Firewall", - "description": "Tier of the Azure Firewall" - } - } - }, - "variables": {}, - "resources": [ - { - "apiVersion": "2019-09-01", - "type": "Microsoft.Network/azureFirewalls", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "virtualHub": { - "id": "[parameters('vwan_id')]" - }, - "sku": { - "Name": "AZFW_Hub", - "Tier": "Standard" - } - } - } - ], - "outputs": { - "resourceID": { - "type": "string", - "value": "[resourceId('Microsoft.Network/azureFirewalls', parameters('name'))]" - } - } -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/virtual_hub/azure_firewall.tf b/landingzones/landingzone_networking/virtual_hub/azure_firewall.tf deleted file mode 100644 index af2a671f..00000000 --- a/landingzones/landingzone_networking/virtual_hub/azure_firewall.tf +++ /dev/null @@ -1,41 +0,0 @@ -# While the Azure Firewall object is using ARM template snippet, we store each object in a different RG to simplify lifecycles -resource "azurecaf_naming_convention" "rg_virtualhub_fw" { - count = var.virtual_hub_config.deploy_firewall ? 1 : 0 - name = var.virtual_hub_config.firewall_resource_groupe_name - prefix = var.prefix != "" ? var.prefix : null - resource_type = "azurerm_resource_group" - convention = var.global_settings.convention -} - -resource "azurerm_resource_group" "rg_virtualhub_fw" { - depends_on = [azurerm_virtual_hub.vwan_hub] #adding explicit dependency for destroy time since we use ARM template. - count = var.virtual_hub_config.deploy_firewall ? 1 : 0 - name = azurecaf_naming_convention.rg_virtualhub_fw.0.result - location = var.virtual_hub_config.region - tags = local.tags -} - -resource "azurecaf_naming_convention" "virtualhub_fw" { - count = var.virtual_hub_config.deploy_firewall ? 1 : 0 - name = var.virtual_hub_config.firewall_name - prefix = var.prefix != "" ? var.prefix : null - resource_type = "azurerm_virtual_network" - convention = var.global_settings.convention -} - -# As per https://docs.microsoft.com/en-us/azure/templates/microsoft.network/2019-09-01/azurefirewalls -resource "azurerm_template_deployment" "arm_template_vhub_firewall" { - count = var.virtual_hub_config.deploy_firewall ? 1 : 0 - name = var.virtual_hub_config.firewall_name - resource_group_name = azurerm_resource_group.rg_virtualhub_fw.0.name - - template_body = file("${path.module}/arm_template_vhub_firewall.json") - - parameters = { - "vwan_id" = azurerm_virtual_hub.vwan_hub.id, - "name" = var.virtual_hub_config.firewall_name, - "location" = var.location, - "Tier" = "Standard", - } - deployment_mode = "Incremental" -} diff --git a/landingzones/landingzone_networking/virtual_hub/express_route_gateway.tf b/landingzones/landingzone_networking/virtual_hub/express_route_gateway.tf deleted file mode 100644 index bdd0474b..00000000 --- a/landingzones/landingzone_networking/virtual_hub/express_route_gateway.tf +++ /dev/null @@ -1,17 +0,0 @@ -## create the ER Gateway -resource "azurerm_express_route_gateway" "er_gateway" { - depends_on = [azurerm_virtual_hub.vwan_hub] - count = var.virtual_hub_config.deploy_er ? 1 : 0 - - name = azurecaf_naming_convention.er_gateway.0.result - location = var.location - resource_group_name = var.resource_group_name - tags = local.tags - virtual_hub_id = azurerm_virtual_hub.vwan_hub.id - - scale_units = var.virtual_hub_config.er_config.scale_units - timeouts { - create = "60m" - delete = "120m" - } -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/virtual_hub/main.tf b/landingzones/landingzone_networking/virtual_hub/main.tf deleted file mode 100644 index a6ec2ca0..00000000 --- a/landingzones/landingzone_networking/virtual_hub/main.tf +++ /dev/null @@ -1,27 +0,0 @@ -terraform { - backend "azurerm" { - } -} - -data "azurerm_subscription" "current" { -} - -locals { - blueprint_tag = { - "blueprint" = basename(abspath(path.module)) - } - tags = merge(var.global_settings.tags_hub, local.blueprint_tag) -} - -terraform { - required_providers { - azurecaf = { - source = "aztfmod/azurecaf" - } - azurerm = { - source = "hashicorp/azurerm" - } - } - required_version = ">= 0.13" -} - diff --git a/landingzones/landingzone_networking/virtual_hub/output.tf b/landingzones/landingzone_networking/virtual_hub/output.tf deleted file mode 100644 index 578c4b61..00000000 --- a/landingzones/landingzone_networking/virtual_hub/output.tf +++ /dev/null @@ -1,35 +0,0 @@ -output "id" { - description = "Resource ID of the Virtual Hub" - value = azurerm_virtual_hub.vwan_hub.id -} - -output "object" { - description = "Full Virtual Hub Object" - value = azurerm_virtual_hub.vwan_hub -} - -output "name" { - description = "Name of the Virtual Hub" - value = azurerm_virtual_hub.vwan_hub.name -} - -output "firewall_id" { - description = "Resource ID of the Azure Firewall for Virtual Hub" - value = var.virtual_hub_config.deploy_firewall ? azurerm_template_deployment.arm_template_vhub_firewall.*.outputs.resourceID : null -} - -# output virtual network gateway objects: p2s, s2s, er objects -output "er_gateway" { - description = "Full Object for Virtual Network Gateway - Express Route" - value = var.virtual_hub_config.deploy_er ? azurerm_express_route_gateway.er_gateway.0 : null -} - -output "s2s_gateway" { - description = "Full Object for Virtual Network Gateway - Site 2 Site" - value = var.virtual_hub_config.deploy_s2s ? azurerm_vpn_gateway.s2s_gateway.0 : null -} - -output "p2s_gateway" { - description = "Full Object for Virtual Network Gateway - Point to Site" - value = var.virtual_hub_config.deploy_p2s ? azurerm_point_to_site_vpn_gateway.p2s_gateway.0 : null -} diff --git a/landingzones/landingzone_networking/virtual_hub/point_to_site_gateway.tf b/landingzones/landingzone_networking/virtual_hub/point_to_site_gateway.tf deleted file mode 100644 index 959e1d48..00000000 --- a/landingzones/landingzone_networking/virtual_hub/point_to_site_gateway.tf +++ /dev/null @@ -1,57 +0,0 @@ - -## create the VPN P2S if var.vwan.p2s_gateway is set to true -resource "azurerm_point_to_site_vpn_gateway" "p2s_gateway" { - depends_on = [azurerm_virtual_hub.vwan_hub, azurerm_vpn_server_configuration.p2s_configuration] - - count = var.virtual_hub_config.deploy_p2s ? 1 : 0 - - name = azurecaf_naming_convention.p2s_gateway.0.result - location = var.location - resource_group_name = var.resource_group_name - tags = local.tags - virtual_hub_id = azurerm_virtual_hub.vwan_hub.id - vpn_server_configuration_id = azurerm_vpn_server_configuration.p2s_configuration[0].id - - scale_unit = var.virtual_hub_config.p2s_config.scale_unit - - dynamic "connection_configuration" { - for_each = lookup(var.virtual_hub_config.p2s_config, "connection_configuration", {}) != {} ? [1] : [] - - content { - name = var.virtual_hub_config.p2s_config.connection_configuration.name - - dynamic "vpn_client_address_pool" { - for_each = var.virtual_hub_config.p2s_config.connection_configuration.vpn_client_address_pool - content { - address_prefixes = var.virtual_hub_config.p2s_config.connection_configuration.vpn_client_address_pool.address_prefixes - } - } - } - } - - timeouts { - create = "60m" - delete = "120m" - } - -} - -# ## creates the VPN P2S server configuration, this is required for P2S site. -# ## TBD: https://www.terraform.io/docs/providers/azurerm/r/vpn_server_configuration.html -resource "azurerm_vpn_server_configuration" "p2s_configuration" { - depends_on = [azurerm_virtual_hub.vwan_hub] - count = var.virtual_hub_config.deploy_p2s ? 1 : 0 - - name = azurecaf_naming_convention.p2s_gateway.0.result - resource_group_name = var.resource_group_name - location = var.location - tags = local.tags - vpn_authentication_types = var.virtual_hub_config.p2s_config.server_config.vpn_authentication_types - - client_root_certificate { - name = var.virtual_hub_config.p2s_config.server_config.client_root_certificate.name - public_cert_data = var.virtual_hub_config.p2s_config.server_config.client_root_certificate.public_cert_data - } - -} - diff --git a/landingzones/landingzone_networking/virtual_hub/site_to_site_gateway.tf b/landingzones/landingzone_networking/virtual_hub/site_to_site_gateway.tf deleted file mode 100644 index 78c9e1fe..00000000 --- a/landingzones/landingzone_networking/virtual_hub/site_to_site_gateway.tf +++ /dev/null @@ -1,27 +0,0 @@ -## create the VPN S2S if var.vwan.s2s_gateway is set to true -resource "azurerm_vpn_gateway" "s2s_gateway" { - depends_on = [azurerm_virtual_hub.vwan_hub] - count = var.virtual_hub_config.deploy_s2s ? 1 : 0 - - name = azurecaf_naming_convention.s2s_gateway.0.result - location = var.location - resource_group_name = var.resource_group_name - tags = local.tags - virtual_hub_id = azurerm_virtual_hub.vwan_hub.id - - scale_unit = var.virtual_hub_config.s2s_config.scale_unit - - dynamic "bgp_settings" { - for_each = lookup(var.virtual_hub_config.s2s_config, "bgp_settings", {}) != {} ? [1] : [] - - content { - asn = var.virtual_hub_config.s2s_config.bgp_settings.asn - peer_weight = var.virtual_hub_config.s2s_config.bgp_settings.peer_weight - } - } - - timeouts { - create = "60m" - delete = "120m" - } -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/virtual_hub/variables.tf b/landingzones/landingzone_networking/virtual_hub/variables.tf deleted file mode 100644 index 7b982783..00000000 --- a/landingzones/landingzone_networking/virtual_hub/variables.tf +++ /dev/null @@ -1,43 +0,0 @@ -variable "prefix" { - description = "(Optional) Prefix to uniquely identify the deployment" - type = string -} - -variable "global_settings" { - description = "global settings" -} - -variable "caf_foundations_accounting" { - description = "caf_foundations_accounting" -} - -variable "virtual_hub_config" { - description = "core_networking" -} - -variable "location" { - description = "(Required) Location where to create the hub resources" - type = string -} - -variable "resource_group_name" { - description = "(Required) Name of the resource group to create the hub resources" - type = string -} - - -variable "firewall_resource_groupe_name" { - description = "(Required) Name of the resource group for Azure Firewall" - type = string -} - - -variable "vwan_id" { - description = "(Required) Resource ID for the Virtual WAN object" - type = string -} - -variable "tags" { - type = map - default = {} -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/virtual_hub/virtual_hub.tf b/landingzones/landingzone_networking/virtual_hub/virtual_hub.tf deleted file mode 100644 index 9d90bb1c..00000000 --- a/landingzones/landingzone_networking/virtual_hub/virtual_hub.tf +++ /dev/null @@ -1,50 +0,0 @@ -## naming conventions -resource "azurecaf_naming_convention" "vwan_hub" { - name = var.virtual_hub_config.hub_name - prefix = var.prefix != "" ? var.prefix : null - resource_type = "azurerm_virtual_network" - convention = var.global_settings.convention - max_length = 20 -} - -resource "azurecaf_naming_convention" "s2s_gateway" { - count = var.virtual_hub_config.deploy_s2s ? 1 : 0 - - name = lookup(var.virtual_hub_config.s2s_config, "name", null) - prefix = var.prefix != "" ? var.prefix : null - resource_type = "azurerm_virtual_network" - convention = var.global_settings.convention -} - -resource "azurecaf_naming_convention" "p2s_gateway" { - count = var.virtual_hub_config.deploy_p2s ? 1 : 0 - - name = lookup(var.virtual_hub_config.p2s_config, "name", null) - prefix = var.prefix != "" ? var.prefix : null - resource_type = "azurerm_virtual_network" - convention = var.global_settings.convention -} - -resource "azurecaf_naming_convention" "er_gateway" { - count = var.virtual_hub_config.deploy_er ? 1 : 0 - - name = lookup(var.virtual_hub_config.er_config, "name", null) - prefix = var.prefix != "" ? var.prefix : null - resource_type = "azurerm_virtual_network" - convention = var.global_settings.convention -} - -## creates a virtual hub in the region -resource "azurerm_virtual_hub" "vwan_hub" { - name = azurecaf_naming_convention.vwan_hub.result - resource_group_name = var.resource_group_name - location = var.location - virtual_wan_id = var.vwan_id - address_prefix = var.virtual_hub_config.hub_address_prefix - tags = local.tags - - timeouts { - create = "60m" - delete = "180m" - } -} diff --git a/landingzones/landingzone_networking/virtual_hubs.tf b/landingzones/landingzone_networking/virtual_hubs.tf deleted file mode 100644 index 38ebdf7d..00000000 --- a/landingzones/landingzone_networking/virtual_hubs.tf +++ /dev/null @@ -1,35 +0,0 @@ -## create a virtual hub with settings for a region -locals { - hubs = flatten( - [ - for vwan_keys, vwan in var.vwans : [ - for hub_keys, hub in vwan.hubs : { - key = vwan_keys - vwan = vwan_keys - resource_group_key = vwan.resource_group_key - hub_key = hub_keys - hub = hub - } - ] - ]) -} - -module "virtual_hub" { - source = "./virtual_hub" - - for_each = { - for hub in local.hubs : "${hub.key}.${hub.hub_key}" => hub - } - - global_settings = local.global_settings - prefix = local.prefix - caf_foundations_accounting = local.caf_foundations_accounting - - location = each.value.hub.region - virtual_hub_config = each.value.hub - - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - firewall_resource_groupe_name = each.value.hub.firewall_resource_groupe_name - vwan_id = azurerm_virtual_wan.vwan[each.value.vwan].id - tags = local.tags -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/virtual_wan.tf b/landingzones/landingzone_networking/virtual_wan.tf deleted file mode 100644 index e2a86faa..00000000 --- a/landingzones/landingzone_networking/virtual_wan.tf +++ /dev/null @@ -1,15 +0,0 @@ -## Create the global virtual WAN -resource "azurerm_virtual_wan" "vwan" { - for_each = var.vwans - - name = each.value.name - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - location = each.key - tags = local.tags - - type = lookup(each.value, "type", null) - disable_vpn_encryption = lookup(each.value, "disable_vpn_encryption", null) - allow_branch_to_branch_traffic = lookup(each.value, "allow_branch_to_branch_traffic", null) - allow_vnet_to_vnet_traffic = lookup(each.value, "allow_vnet_to_vnet_traffic", null) - office365_local_breakout_category = lookup(each.value, "office365_local_breakout_category", null) -} diff --git a/landingzones/landingzone_networking/vnet.tf b/landingzones/landingzone_networking/vnet.tf deleted file mode 100644 index 0f43e7dc..00000000 --- a/landingzones/landingzone_networking/vnet.tf +++ /dev/null @@ -1,17 +0,0 @@ -module "vnets" { - source = "aztfmod/caf-virtual-network/azurerm" - version = "3.1.0" - - for_each = var.vnets - - convention = local.global_settings.convention - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - prefix = local.prefix - location = lookup(each.value, "location", azurerm_resource_group.rg[each.value.resource_group_key].location) - networking_object = each.value - tags = local.tags - diagnostics_map = local.caf_foundations_accounting[each.value.location].diagnostics_map - log_analytics_workspace = local.caf_foundations_accounting[each.value.location].log_analytics_workspace - diagnostics_settings = lookup(each.value, "diagnostics", var.diagnostics.vnet) - ddos_id = "" -} \ No newline at end of file diff --git a/landingzones/landingzone_networking/vnet_peering.tf b/landingzones/landingzone_networking/vnet_peering.tf deleted file mode 100644 index b9ff870a..00000000 --- a/landingzones/landingzone_networking/vnet_peering.tf +++ /dev/null @@ -1,13 +0,0 @@ -resource "azurerm_virtual_network_peering" "peering" { - for_each = var.peerings - - name = each.value.name - resource_group_name = lookup(each.value, "resource_group_name", module.vnets[each.value.from_key].vnet_obj.resource_group_name) - virtual_network_name = lookup(each.value, "virtual_network_name", module.vnets[each.value.from_key].vnet_obj.name) - remote_virtual_network_id = lookup(each.value, "remote_virtual_network_id", module.vnets[each.value.to_key].vnet_obj.id) - allow_virtual_network_access = lookup(each.value, "allow_virtual_network_access", false) - allow_forwarded_traffic = lookup(each.value, "allow_forwarded_traffic", false) - allow_gateway_transit = lookup(each.value, "allow_gateway_transit", false) - use_remote_gateways = lookup(each.value, "use_remote_gateways", false) -} - \ No newline at end of file diff --git a/landingzones/launchpad/_launchpad_light.auto.tfvars b/landingzones/launchpad/_launchpad_light.auto.tfvars deleted file mode 100644 index 53393e9b..00000000 --- a/landingzones/launchpad/_launchpad_light.auto.tfvars +++ /dev/null @@ -1,82 +0,0 @@ -level = "level0" - -launchpad_key_names = { - keyvault = "launchpad" - aad_app = "caf_launchpad_level0" -} - -resource_groups = { - tfstate = { - name = "launchpad-tfstates" - location = "southeastasia" - useprefix = true - max_length = 40 - } - security = { - name = "launchpad-security" - useprefix = true - max_length = 40 - } - gitops = { - name = "launchpad-devops-agents" - useprefix = true - max_length = 40 - } -} - -storage_account_name = "level0" - -keyvaults = { - # Do not rename the key "launchpad" to be able to upgrade to the standard launchpad - launchpad = { - name = "launchpad" - resource_group_key = "security" - region = "southeastasia" - convention = "cafrandom" - sku_name = "standard" - } -} - -subscriptions = { - logged_in_subscription = { - role_definition_name = "Owner" - aad_app_key = "caf_launchpad_level0" - } -} - -aad_apps = { - # Do not rename the key "launchpad" to be able to upgrade to the standard launchpad - caf_launchpad_level0 = { - convention = "cafrandom" - useprefix = true - application_name = "caf_launchpad_level0" - password_expire_in_days = 180 - keyvault = { - keyvault_key = "launchpad" - secret_prefix = "caf-launchpad-level0" - access_policies = { - key_permissions = [] - secret_permissions = ["Get", "List", "Set", "Delete"] - } - } - } -} - -diagnostics_settings = { - resource_diagnostics_name = "diag" - azure_diagnostics_logs_event_hub = false - resource_group_key = "gitops" -} - -log_analytics = { - resource_log_analytics_name = "logs" - resource_group_key = "gitops" - solutions_maps = { - KeyVaultAnalytics = { - "publisher" = "Microsoft" - "product" = "OMSGallery/KeyVaultAnalytics" - } - } -} - -networking = {} diff --git a/landingzones/launchpad/aad_apps.tf b/landingzones/launchpad/aad_apps.tf deleted file mode 100644 index 937abec2..00000000 --- a/landingzones/launchpad/aad_apps.tf +++ /dev/null @@ -1,10 +0,0 @@ -module azure_applications { - source = "aztfmod/caf-aad-apps/azuread" - version = "1.0.0" - - aad_apps = var.aad_apps - aad_api_permissions = var.aad_api_permissions - keyvaults = azurerm_key_vault.keyvault - prefix = local.prefix -} - diff --git a/landingzones/launchpad/aad_apps_bootstrap_keyvault.tf b/landingzones/launchpad/aad_apps_bootstrap_keyvault.tf deleted file mode 100644 index d5a45ab0..00000000 --- a/landingzones/launchpad/aad_apps_bootstrap_keyvault.tf +++ /dev/null @@ -1,32 +0,0 @@ -resource "azurerm_key_vault_secret" "launchpad_blob_name" { - name = "launchpad-blob-name" - value = var.tf_name - key_vault_id = azurerm_key_vault.keyvault[var.launchpad_key_names.keyvault].id -} - -resource "azurerm_key_vault_secret" "launchpad_blob_container" { - name = "launchpad-blob-container" - value = azurerm_storage_container.launchpad.name - key_vault_id = azurerm_key_vault.keyvault[var.launchpad_key_names.keyvault].id -} - -resource "azurerm_key_vault_secret" "launchpad_name" { - name = "launchpad-secret-prefix" - value = var.aad_apps[var.launchpad_key_names.aad_app].keyvault.secret_prefix - key_vault_id = azurerm_key_vault.keyvault[var.launchpad_key_names.keyvault].id -} - - -resource "azurerm_key_vault_secret" "launchpad_subscription_id" { - name = "launchpad-subscription-id" - value = data.azurerm_client_config.current.subscription_id - key_vault_id = azurerm_key_vault.keyvault[var.launchpad_key_names.keyvault].id -} - -# launchpad_light or launchpad -resource "azurerm_key_vault_secret" "launchpad_mode" { - name = "launchpad-mode" - value = var.launchpad_mode - key_vault_id = azurerm_key_vault.keyvault[var.launchpad_key_names.keyvault].id -} - diff --git a/landingzones/launchpad/aad_apps_consent.tf b/landingzones/launchpad/aad_apps_consent.tf deleted file mode 100644 index 991d3640..00000000 --- a/landingzones/launchpad/aad_apps_consent.tf +++ /dev/null @@ -1,62 +0,0 @@ -locals { - - api_permissions_for_sp = flatten( - [ - for key, app in var.aad_api_permissions : [ - for resources in app : [ - for resource in resources.resource_access : { - aad_app_key = key - resource_app_id = resources.resource_app_id - id = resource.id - type = resource.type - } if resource.type == "Role" - ] - ] - ] - ) - - api_permissions_for_user = distinct( - flatten( - [ - for key, app in var.aad_api_permissions : [ - for resources in app : [ - for resource in resources.resource_access : { - aad_app_key = key - } - ] - ] - ] - ) - ) - - ### Fltattening the list to only the applications when granting concent with a logged-in user type user - # value = [ - # {"aad_app_key" = "aztfmod_level0" }, - # {"aad_app_key" = "azure_caf-terraform-landingzones"}, - # ] - - api_permissions = var.user_type == "user" ? local.api_permissions_for_user : local.api_permissions_for_sp - -} - - -resource "null_resource" "grant_admin_consent" { - depends_on = [module.azure_applications] - - for_each = { - for key, permission in local.api_permissions : key => permission - } - - provisioner "local-exec" { - command = "./scripts/grant_consent.sh" - interpreter = ["/bin/sh"] - on_failure = fail - - environment = { - resourceAppId = var.user_type == "user" ? null : each.value.resource_app_id - appRoleId = var.user_type == "user" ? null : each.value.id - principalId = var.user_type == "user" ? null : module.azure_applications.aad_apps[each.value.aad_app_key].azuread_service_principal.id - applicationId = module.azure_applications.aad_apps[each.value.aad_app_key].azuread_application.application_id - } - } -} diff --git a/landingzones/launchpad/aad_apps_roles.tf b/landingzones/launchpad/aad_apps_roles.tf deleted file mode 100644 index 5eee9ed2..00000000 --- a/landingzones/launchpad/aad_apps_roles.tf +++ /dev/null @@ -1,33 +0,0 @@ -locals { - aad_roles = flatten( - [ - for key, aad_roles in var.aad_roles : [ - for role in aad_roles.roles : { - aad_app_key = key - aad_role_name = role - } - ] - ] - ) -} - - - -resource "null_resource" "set_azure_ad_roles" { - depends_on = [module.azure_applications] - - for_each = { - for key, aad_role in local.aad_roles : key => aad_role - } - - provisioner "local-exec" { - command = "./scripts/set_ad_role.sh" - interpreter = ["/bin/sh"] - on_failure = fail - - environment = { - AD_ROLE_NAME = each.value.aad_role_name - SERVICE_PRINCIPAL_OBJECT_ID = module.azure_applications.aad_apps[each.value.aad_app_key].azuread_service_principal.object_id - } - } -} \ No newline at end of file diff --git a/landingzones/launchpad/aad_users.tf b/landingzones/launchpad/aad_users.tf deleted file mode 100644 index 39b38074..00000000 --- a/landingzones/launchpad/aad_users.tf +++ /dev/null @@ -1,55 +0,0 @@ - -resource "azurecaf_naming_convention" "account" { - for_each = var.aad_users - - name = each.value.user_name - prefix = each.value.useprefix ? local.prefix : "" - resource_type = "rg" # workaround to keep the dashes - convention = lookup(each.value, "convention", local.global_settings.convention) - max_length = lookup(each.value, "max_length", null) -} - -# -# -resource "azuread_user" "account" { - for_each = var.aad_users - - user_principal_name = "${azurecaf_naming_convention.account[each.key].result}@${each.value.tenant_name}" - display_name = "${azurecaf_naming_convention.account[each.key].result} (created by CAF launchpad)" - password = random_password.account[each.key].result -} - - -resource "random_password" "account" { - for_each = var.aad_users - - length = 250 - special = false - upper = true - number = true -} - - -resource "azurerm_key_vault_secret" "aad_user_name" { - depends_on = [ - azurerm_key_vault.keyvault - ] - - for_each = var.aad_users - - name = "${lookup(each.value, "secret_prefix", each.value.user_name)}-name" - value = azuread_user.account[each.key].user_principal_name - key_vault_id = azurerm_key_vault.keyvault[each.value.keyvault_key].id -} - -resource "azurerm_key_vault_secret" "aad_user_password" { - depends_on = [ - azurerm_key_vault.keyvault - ] - - for_each = var.aad_users - - name = "${lookup(each.value, "secret_prefix", each.value.user_name)}-password" - value = random_password.account[each.key].result - key_vault_id = azurerm_key_vault.keyvault[each.value.keyvault_key].id -} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops/azdo.tf b/landingzones/launchpad/add-ons/azure_devops/azdo.tf deleted file mode 100644 index b3188eac..00000000 --- a/landingzones/launchpad/add-ons/azure_devops/azdo.tf +++ /dev/null @@ -1,27 +0,0 @@ -terraform { - experiments = [variable_validation] - - required_providers { - azurerm = "~> 2.20.0" - } -} - -provider "azurerm" { - features {} -} - - - -provider "azuredevops" { - org_service_url = var.azure_devops.organization_url - personal_access_token = data.azurerm_key_vault_secret.pat.value -} - -data "azurerm_key_vault_secret" "pat" { - name = var.azure_devops.pats[var.launchpad_key_names.azure_devops_management_pat].secret_name - key_vault_id = local.keyvaults[var.launchpad_key_names.keyvault].id -} - -data "azuredevops_project" "project" { - project_name = var.azure_devops.project -} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops/azdo_agent_pools.tf b/landingzones/launchpad/add-ons/azure_devops/azdo_agent_pools.tf deleted file mode 100644 index b3b82857..00000000 --- a/landingzones/launchpad/add-ons/azure_devops/azdo_agent_pools.tf +++ /dev/null @@ -1,51 +0,0 @@ - -locals { - organization_agent_pools = lookup(var.azure_devops, "organization_agent_pools", {}) - project_agent_pools = lookup(var.azure_devops, "project_agent_pools", {}) -} - - -## Agent pools -## Those pools are created in the organization, not the project -resource "azuredevops_agent_pool" "pool" { - for_each = local.organization_agent_pools - - name = each.value.name - auto_provision = lookup(each.value, "auto_provision", false) -} - -# -# add the agent pools into the project -# - -data "azuredevops_agent_pool" "pool" { - depends_on = [azuredevops_agent_pool.pool] - for_each = local.project_agent_pools - - name = each.value.name -} - -resource "azuredevops_agent_queue" "agent_queue" { - for_each = local.project_agent_pools - - project_id = data.azuredevops_project.project.id - agent_pool_id = data.azuredevops_agent_pool.pool[each.key].id - - lifecycle { - ignore_changes = [ - agent_pool_id - ] - } -} - - - -# Grant acccess to queue to all pipelines in the project -resource "azuredevops_resource_authorization" "auth" { - for_each = local.project_agent_pools - - project_id = azuredevops_project.project.id - resource_id = azuredevops_agent_queue.agent_queue[each.key].id - type = "queue" - authorized = true -} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops/azdo_pipelines.tf b/landingzones/launchpad/add-ons/azure_devops/azdo_pipelines.tf deleted file mode 100644 index e5e7f8a8..00000000 --- a/landingzones/launchpad/add-ons/azure_devops/azdo_pipelines.tf +++ /dev/null @@ -1,28 +0,0 @@ -data "azuredevops_git_repositories" "repos" { - project_id = data.azuredevops_project.project.id -} - - -locals { - repositories = zipmap(tolist(data.azuredevops_git_repositories.repos.repositories.*.name), tolist(data.azuredevops_git_repositories.repos.repositories) ) -} - -resource "azuredevops_build_definition" "build_definition" { - - for_each = lookup(var.azure_devops, "pipelines", {}) - project_id = data.azuredevops_project.project.id - name = each.value.name - path = each.value.folder - - repository { - repo_id = local.repositories[each.value.git_repo_name].id - repo_type = each.value.repo_type - yml_path = each.value.yaml - branch_name = lookup(each.value, "branch_name", null) - } - - ci_trigger { - use_yaml = true - } - -} diff --git a/landingzones/launchpad/add-ons/azure_devops/azdo_service_endpoint.tf b/landingzones/launchpad/add-ons/azure_devops/azdo_service_endpoint.tf deleted file mode 100644 index 33b2d436..00000000 --- a/landingzones/launchpad/add-ons/azure_devops/azdo_service_endpoint.tf +++ /dev/null @@ -1,51 +0,0 @@ -locals { - service_endpoints = lookup(var.azure_devops, "service_endpoints", {}) -} - -data "azurerm_key_vault_secret" "client_secret" { - for_each = local.service_endpoints - - name = local.aad_apps[each.value.aad_app_key].azuread_service_principal.keyvault_client_secret - key_vault_id = local.aad_apps[each.value.aad_app_key].azuread_service_principal.keyvault_id -} - -resource "azuredevops_serviceendpoint_azurerm" "azure" { - for_each = local.service_endpoints - - project_id = data.azuredevops_project.project.id - service_endpoint_name = each.value.endpoint_name - credentials { - serviceprincipalid = local.aad_apps[each.value.aad_app_key].azuread_application.application_id - serviceprincipalkey = data.azurerm_key_vault_secret.client_secret[each.key].value - } - azurerm_spn_tenantid = local.aad_apps[each.value.aad_app_key].tenant_id - azurerm_subscription_id = each.value.subscription_id - azurerm_subscription_name = each.value.subscription_name -} - -resource "azurerm_role_definition" "devops" { - for_each = local.service_endpoints - name = format("caf-azure-devops-to-%s", each.value.subscription_name) - scope = format("/subscriptions/%s", each.value.subscription_id) - description = "CAF Custom role for service principal in Azure Devops to access resources" - - permissions { - actions = [ - "Microsoft.Resources/subscriptions/read", - "Microsoft.KeyVault/vaults/read" - ] - not_actions = [] - } - - assignable_scopes = [ - format("/subscriptions/%s", each.value.subscription_id), - ] -} - -resource "azurerm_role_assignment" "devops" { - for_each = local.service_endpoints - - scope = format("/subscriptions/%s", each.value.subscription_id) - role_definition_id = azurerm_role_definition.devops[each.key].id - principal_id = local.aad_apps[each.value.aad_app_key].azuread_service_principal.object_id -} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops/azdo_variable_groups.tf b/landingzones/launchpad/add-ons/azure_devops/azdo_variable_groups.tf deleted file mode 100644 index e64a0fcf..00000000 --- a/landingzones/launchpad/add-ons/azure_devops/azdo_variable_groups.tf +++ /dev/null @@ -1,44 +0,0 @@ -# -# permissions required: -# - vso.variablegroups_manage (create) -# + vso.buid (update) -# + vso.build_execute (destroy) -# -resource "azuredevops_variable_group" "variable_group" { - for_each = { - for key, variable_group in lookup(var.azure_devops, "variable_groups", {}) : key => variable_group - } - - project_id = data.azuredevops_project.project.id - name = each.value.name - description = lookup(each.value, "description", null) - - allow_access = lookup(each.value, "allow_access", false) - - dynamic "key_vault" { - for_each = lookup(each.value, "keyvault", null) == null ? [] : [1] - - content { - name = local.keyvaults[each.value.keyvault.keyvault_key].name - service_endpoint_id = azuredevops_serviceendpoint_azurerm.azure[each.value.keyvault.serviceendpoint_key].id - } - } - - dynamic "variable" { - for_each = flatten([ - for key, variables in each.value.variables : [ - for key1, variable1 in variables : { - name = key1 == "name" ? variable1 : key1 - value = key1 == "name" ? null : variable1 - } - ] - ]) - - content { - # When used with Keyvault, the name must be the keyvault secret name and value must not be set - name = variable.value.name - value = variable.value.value - } - } - -} diff --git a/landingzones/launchpad/add-ons/azure_devops/main.tf b/landingzones/launchpad/add-ons/azure_devops/main.tf deleted file mode 100644 index 5117c943..00000000 --- a/landingzones/launchpad/add-ons/azure_devops/main.tf +++ /dev/null @@ -1,15 +0,0 @@ - -data "terraform_remote_state" "launchpad" { - backend = "azurerm" - config = { - storage_account_name = var.lowerlevel_storage_account_name - container_name = var.lowerlevel_container_name - key = var.lowerlevel_key - resource_group_name = var.lowerlevel_resource_group_name - } -} - -locals { - keyvaults = data.terraform_remote_state.launchpad.outputs.keyvaults - aad_apps = data.terraform_remote_state.launchpad.outputs.aad_apps -} diff --git a/landingzones/launchpad/add-ons/azure_devops/variables.tf b/landingzones/launchpad/add-ons/azure_devops/variables.tf deleted file mode 100644 index 583d6aad..00000000 --- a/landingzones/launchpad/add-ons/azure_devops/variables.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable lowerlevel_storage_account_name {} -variable lowerlevel_resource_group_name {} -variable lowerlevel_container_name{} -variable lowerlevel_key {} - -variable launchpad_key_names {} -variable azure_devops {} - diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/availability.tf b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/availability.tf deleted file mode 100644 index 8e7080ac..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/availability.tf +++ /dev/null @@ -1,13 +0,0 @@ - -resource "azurerm_availability_set" "avs" { - count = lookup(var.vm_object, "availability_set", null) == null ? 0 : 1 - - name = "${var.vm_object.name}-${var.vm_object.availability_set.name}" - location = lookup(var.vm_object, "location", local.global_settings.default_location) - resource_group_name = local.resource_groups[var.vm_object.resource_group_key].name - - platform_update_domain_count = var.vm_object.availability_set.platform_update_domain_count - platform_fault_domain_count = var.vm_object.availability_set.platform_fault_domain_count - - tags = merge(local.tags, lookup(var.vm_object.availability_set, "tags", {})) -} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/devops_agent.tf b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/devops_agent.tf deleted file mode 100644 index 52540612..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/devops_agent.tf +++ /dev/null @@ -1,62 +0,0 @@ - - -resource "azurecaf_naming_convention" "stg" { - name = var.storage_account_name - prefix = local.prefix - resource_type = "azurerm_storage_account" - convention = lookup(var.vm_object, "convention", local.global_settings.convention) -} - -resource "azurerm_storage_account" "devops" { - name = azurecaf_naming_convention.stg.result - location = lookup(var.vm_object, "location", local.global_settings.default_location) - resource_group_name = local.resource_groups[var.vm_object.resource_group_key].name - - account_tier = "Standard" - account_replication_type = "LRS" -} - - -resource "azurerm_storage_container" "deployment" { - name = "deployment" - storage_account_name = azurerm_storage_account.devops.name - container_access_type = "blob" -} - -resource "azurerm_storage_blob" "deployment" { - name = basename(var.vm_object.agent_init_script) - storage_account_name = azurerm_storage_account.devops.name - storage_container_name = azurerm_storage_container.deployment.name - type = "Block" - source = var.vm_object.agent_init_script -} - -# Get PAT token from keyvault -data "azurerm_key_vault_secret" "agent_pat" { - name = var.azure_devops.pat.secret_key_name - key_vault_id = local.keyvaults[var.azure_devops.pat.keyvault_key].id -} - -resource "azurerm_virtual_machine_extension" "devops" { - name = "install_azure_devops_agent" - - virtual_machine_id = azurerm_linux_virtual_machine.vm.id - publisher = "Microsoft.Azure.Extensions" - type = "CustomScript" - type_handler_version = "2.1" - - #timestamp: use this field only to trigger a re-run of the script by changing value of this field. - # Any integer value is acceptable; it must only be different than the previous value. - settings = jsonencode( - { - "timestamp" : 6 - } - ) - protected_settings = jsonencode( - { - "fileUris": ["${azurerm_storage_blob.deployment.url}"], - "commandToExecute": "bash ${basename(var.vm_object.agent_init_script)} '${var.azure_devops.url}' '${data.azurerm_key_vault_secret.agent_pat.value}' '${var.azure_devops.agent_pool.name}' '${var.azure_devops.agent_pool.agent_name_prefix}' '${var.azure_devops.agent_pool.num_agents}' '${var.vm_object.admin_username}' '${var.rover_version}'" - } - ) - -} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/level0.tfvars b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/level0.tfvars deleted file mode 100644 index f683f4e3..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/level0.tfvars +++ /dev/null @@ -1,66 +0,0 @@ - -convention = "cafrandom" - -vm_object = { - - agent_init_script = "../scripts/devops_runtime.sh" - - resource_group = { - name = "devop-agents" - location = "southeastasia" - } - - - name = "devops" - subnet_name = "level0" - - admin_username = "devopsadmin" - os_profile = { - computer_name = "devopslevel0" - - } - - # vm_size = "Standard_B1s" - vm_size = "Standard_F4s_v2" - - os = "Linux" - - save_ssh_private_key_pem = true - - source_image_reference = { - publisher = "OpenLogic" - offer = "Centos" - sku = "7.6" - version = "latest" - } - - - os_disk = { - caching = "ReadWrite" - storage_account_type = "Standard_LRS" - disk_size_gb = 128 - } - - availability_set = { - name = "avs" - platform_update_domain_count = 5 - platform_fault_domain_count = 2 - tags = {} - } -} - - -azure_devops = { - - url = "https://dev.azure.com/azure-terraform/" - - agent_pool = { - name = "test-level0" - auto_provision = true # Auto pro - num_agents = 2 - agent_name_prefix = "agent" - } - -} - - diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/main.tf b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/main.tf deleted file mode 100644 index 280bd7ca..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/main.tf +++ /dev/null @@ -1,117 +0,0 @@ -provider "azurerm" { - features {} -} - -module "devops" { - source = "../" - - prefix = local.prefix - resource_group_name = var.vm_object.resource_group.name - location = var.vm_object.resource_group.location - subnet_id = data.azurerm_subnet.agent.id - storage_account_name = lookup(var.vm_object, "storage_account_name", null) - vm_object = var.vm_object - - azure_devops_pat_token = var.azure_devops_pat_token - azure_devops = var.azure_devops - agent_init_script = var.vm_object.agent_init_script - - acr_object = var.acr_object - - log_analytics_workspace = azurerm_log_analytics_workspace.la - diagnostics_map = module.diagnostics.diagnostics_map - -} - -data "azurerm_subnet" "agent" { - depends_on = [ azurerm_subnet.level0, azurerm_subnet.level1 ] - - name = var.vm_object.subnet_name - virtual_network_name = azurerm_virtual_network.vnet.name - resource_group_name = azurerm_resource_group.rg_vnet.name -} - -resource "random_string" "prefix" { - length = 4 - special = false - upper = false - number = false -} - -locals { - prefix = var.use_prefix == true ? random_string.prefix.result : "" -} - -resource "azurecaf_naming_convention" "rg_vnet" { - name = "vnet" - prefix = local.prefix - resource_type = "azurerm_resource_group" - convention = var.convention -} - -resource "azurerm_resource_group" "rg_vnet" { - name = azurecaf_naming_convention.rg_vnet.result - location = var.vm_object.resource_group.location -} - -resource "azurecaf_naming_convention" "vnet" { - name = "vnet" - prefix = local.prefix - resource_type = "azurerm_virtual_network" - convention = var.convention -} - -resource "azurerm_virtual_network" "vnet" { - name = azurecaf_naming_convention.vnet.result - location = azurerm_resource_group.rg_vnet.location - resource_group_name = azurerm_resource_group.rg_vnet.name - address_space = ["10.0.0.0/16"] - -} - -resource "azurerm_subnet" "level0" { - name = "level0" - resource_group_name = azurerm_resource_group.rg_vnet.name - virtual_network_name = azurerm_virtual_network.vnet.name - address_prefix = "10.0.0.0/26" -} - -resource "azurerm_subnet" "level1" { - name = "level1" - resource_group_name = azurerm_resource_group.rg_vnet.name - virtual_network_name = azurerm_virtual_network.vnet.name - address_prefix = "10.0.0.64/26" -} - -resource "azurecaf_naming_convention" "la" { - name = "test" - prefix = local.prefix - resource_type = "azurerm_log_analytics_workspace" - convention = var.convention -} - -resource "azurerm_log_analytics_workspace" "la" { - name = azurecaf_naming_convention.la.result - location = azurerm_resource_group.rg_vnet.location - resource_group_name = azurerm_resource_group.rg_vnet.name - sku = "PerGB2018" - retention_in_days = 30 -} - -locals { - azure_diagnostics_logs_event_hub = false -} - -module "diagnostics" { - source = "aztfmod/caf-diagnostics-logging/azurerm" - version = "~> 2.0.1" - - name = "diag" - convention = var.convention - location = azurerm_resource_group.rg_vnet.location - resource_group_name = azurerm_resource_group.rg_vnet.name - prefix = local.prefix - tags = {} - - enable_event_hub = local.azure_diagnostics_logs_event_hub -} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/pool2.tfvars b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/pool2.tfvars deleted file mode 100644 index acb6172b..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/pool2.tfvars +++ /dev/null @@ -1,85 +0,0 @@ - -convention = "cafrandom" - -vm_object = { - - agent_init_script = "../scripts/devops_runtime.sh" - - resource_group = { - name = "devop-agents" - location = "southeastasia" - } - - - name = "devops" - - admin_username = "devopsadmin" - os_profile = { - computer_name = "devopsagent1" - - } - - # vm_size = "Standard_B1s" - vm_size = "Standard_F4s_v2" - - os = "Linux" - - save_ssh_private_key_pem = true - - source_image_reference = { - publisher = "OpenLogic" - offer = "Centos" - sku = "7.6" - version = "latest" - } - - - os_disk = { - caching = "ReadWrite" - storage_account_type = "Standard_LRS" - disk_size_gb = 128 - } - - availability_set = { - name = "avs" - platform_update_domain_count = 5 - platform_fault_domain_count = 2 - tags = {} - } -} - - -azure_devops = { - - url = "https://dev.azure.com/azure-terraform/" - - agent_pool = { - name = "laurent-level0" - auto_provision = true # Auto pro - num_agents = 2 - agent_name_prefix = "remi" - } - -} - - -acr_object = { - - resource_group = { - name = "container-registry" - location = "southeastasia" - } - - name = "level0" - sku = "Premium" - - diagnostics_settings = { - log = [ - ["ContainerRegistryRepositoryEvents", true, true, 5], - ["ContainerRegistryLoginEvents", true, true, 5], - ] - metric = [ - ["AllMetrics", true, true, 30], - ] - } -} diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/variables.tf b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/variables.tf deleted file mode 100644 index 656fe27e..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/examples/variables.tf +++ /dev/null @@ -1,22 +0,0 @@ -variable "vm_object" {} -variable "azure_devops" {} - -variable "use_prefix" { - default = true - type = bool -} - -variable "convention" { - description = "(Optional) (Default = cafrandom) Naming convention to apply to the resources at creating time" - default = "cafrandom" -} - -variable "location" { - type = string - default = "westus2" -} - - -variable "azure_devops_pat_token" {} - -variable "acr_object" {} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/keyvault_policy.tf b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/keyvault_policy.tf deleted file mode 100644 index d6764e8a..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/keyvault_policy.tf +++ /dev/null @@ -1,13 +0,0 @@ -resource "azurerm_key_vault_access_policy" "msi_landingzone" { - - key_vault_id = local.keyvaults[var.azure_devops.pat.keyvault_key].id - - tenant_id = data.azurerm_client_config.current.tenant_id - object_id = azurerm_user_assigned_identity.user_msi.principal_id - - key_permissions = [] - - secret_permissions = [ - "Get", - ] -} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/level0.tfvars b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/level0.tfvars deleted file mode 100644 index a00fb9cf..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/level0.tfvars +++ /dev/null @@ -1,62 +0,0 @@ - -convention = "cafrandom" - -vm_object = { - - agent_init_script = "./scripts/devops_runtime.sh" - - resource_group_key = "devops" - - name = "devopslevel0" - computer_name = "devopslevel0" - - subnet_name = "level0" - - admin_username = "devopsadmin" - - - - # vm_size = "Standard_B1s" - vm_size = "Standard_F4s_v2" - - os = "Linux" - - save_ssh_private_key_pem = true - - source_image_reference = { - publisher = "OpenLogic" - offer = "Centos" - sku = "7.6" - version = "latest" - } - - - os_disk = { - caching = "ReadWrite" - storage_account_type = "Standard_LRS" - disk_size_gb = 128 - } - - availability_set = { - name = "avs" - platform_update_domain_count = 5 - platform_fault_domain_count = 2 - tags = {} - } -} - - -azure_devops = { - - url = "https://dev.azure.com/azure-terraform/" - - agent_pool = { - name = "test-level0" - auto_provision = true # Auto pro - num_agents = 3 - agent_name_prefix = "agent" - } - -} - - diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/level1.tfvars b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/level1.tfvars deleted file mode 100644 index 4aa4f17b..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/level1.tfvars +++ /dev/null @@ -1,62 +0,0 @@ - -convention = "cafrandom" - -vm_object = { - - agent_init_script = "./scripts/devops_runtime.sh" - - resource_group_key = "devops" - - name = "devopslevel1" - computer_name = "devopslevel1" - - subnet_name = "level1" - - admin_username = "devopsadmin" - - - - # vm_size = "Standard_B1s" - vm_size = "Standard_F4s_v2" - - os = "Linux" - - save_ssh_private_key_pem = true - - source_image_reference = { - publisher = "OpenLogic" - offer = "Centos" - sku = "7.6" - version = "latest" - } - - - os_disk = { - caching = "ReadWrite" - storage_account_type = "Standard_LRS" - disk_size_gb = 128 - } - - availability_set = { - name = "avs" - platform_update_domain_count = 5 - platform_fault_domain_count = 2 - tags = {} - } -} - - -azure_devops = { - - url = "https://dev.azure.com/azure-terraform/" - - agent_pool = { - name = "test-level1" - auto_provision = true # Auto pro - num_agents = 5 - agent_name_prefix = "agent" - } - -} - - diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/main.tf b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/main.tf deleted file mode 100644 index 1f200ad0..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/main.tf +++ /dev/null @@ -1,46 +0,0 @@ -provider "azurerm" { - features {} -} - -provider "azurecaf" {} - -terraform { - required_providers { - azurerm = "~> 2.20.0" - null = "~> 2.1.0" - tls = "~> 2.1.1" - } -} - -data "azurerm_subscription" "current" {} -data "azurerm_client_config" "current" {} - -data "terraform_remote_state" "launchpad" { - backend = "azurerm" - config = { - storage_account_name = var.lowerlevel_storage_account_name - container_name = var.lowerlevel_container_name - key = var.lowerlevel_key - resource_group_name = var.lowerlevel_resource_group_name - } -} - -locals { - addon_tag = { - "addon" = basename(abspath(path.module)) - } - tags = merge(var.tags, local.addon_tag) - - global_settings = data.terraform_remote_state.launchpad.outputs.global_settings - - prefix = local.global_settings.prefix - - resource_groups = data.terraform_remote_state.launchpad.outputs.resource_groups - log_analytics_workspace_id = data.terraform_remote_state.launchpad.outputs.log_analytics.id - diagnostics_map = data.terraform_remote_state.launchpad.outputs.diagnostics_map - - networking = data.terraform_remote_state.launchpad.outputs.networking - - keyvaults = data.terraform_remote_state.launchpad.outputs.keyvaults - -} diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/variables.tf b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/variables.tf deleted file mode 100644 index 991fd924..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/variables.tf +++ /dev/null @@ -1,36 +0,0 @@ -variable lowerlevel_storage_account_name {} -variable lowerlevel_container_name {} -variable lowerlevel_resource_group_name {} -variable lowerlevel_key {} - - -variable tags { - default = {} - type = map -} - - -variable "storage_account_name" { - description = "Storage account name to store diagnostics and Azure DevOps init script" - default = "" -} - -variable "disk_encryption_set_id" { - description = "(Optional) The ID of the Disk Encryption Set which should be used to Encrypt this OS Disk." - type = string - default = null -} - -variable "private_key_pem_file" { - description = "(Optional) Name of the public key file name. A local key will be created if not provided" - default = "" -} - -variable vm_object {} - -variable azure_devops {} - -variable rover_version { - description = "(default=aztfmod/roverdev:vnext) Version of the rover to use on the Azure Devops self-hosted agents" - default = "aztfmod/roverdev:vnext" -} \ No newline at end of file diff --git a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/vm.tf b/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/vm.tf deleted file mode 100644 index 178b3597..00000000 --- a/landingzones/launchpad/add-ons/azure_devops_agent_self_hosted/vm.tf +++ /dev/null @@ -1,125 +0,0 @@ - - -resource "azurecaf_naming_convention" "nic" { - name = "${var.vm_object.name}-nic" - prefix = local.prefix - resource_type = "azurerm_network_interface" - convention = lookup(var.vm_object, "convention", local.global_settings.convention) -} - - -resource "azurerm_network_interface" "nic" { - name = azurecaf_naming_convention.nic.result - location = lookup(var.vm_object, "location", local.global_settings.default_location) - resource_group_name = local.resource_groups[var.vm_object.resource_group_key].name - - ip_configuration { - name = local.networking.subnet_ids_map[var.vm_object.subnet_key].name - subnet_id = local.networking.subnet_ids_map[var.vm_object.subnet_key].id - private_ip_address_allocation = "Dynamic" - } -} - -# Name of the VM in the Azure Control Plane -resource "azurecaf_naming_convention" "vm" { - name = var.vm_object.name - prefix = local.prefix - resource_type = "vml" - convention = lookup(var.vm_object, "convention", local.global_settings.convention) -} - -# Name of the Linux computer name -resource "azurecaf_naming_convention" "computer_name" { - name = var.vm_object.computer_name - prefix = local.prefix - resource_type = "vml" - convention = lookup(var.vm_object, "convention", local.global_settings.convention) -} - -resource "azurerm_linux_virtual_machine" "vm" { - depends_on = [azurerm_network_interface.nic, azurerm_availability_set.avs] - - name = azurecaf_naming_convention.vm.result - location = lookup(var.vm_object, "location", local.global_settings.default_location) - resource_group_name = local.resource_groups[var.vm_object.resource_group_key].name - size = var.vm_object.vm_size - admin_username = var.vm_object.admin_username - computer_name = azurecaf_naming_convention.computer_name.result - zone = lookup(var.vm_object, "zone", null) - - availability_set_id = lookup(var.vm_object, "availability_set", null) == null ? 0 : azurerm_availability_set.avs.0.id - - network_interface_ids = [ - azurerm_network_interface.nic.id, - ] - - admin_ssh_key { - username = var.vm_object.admin_username - public_key = local.public_key - } - - os_disk { - name = lookup(var.vm_object.os_disk, "name", "${var.vm_object.name}-os_disk") - caching = lookup(var.vm_object.os_disk, "caching", "ReadWrite") - storage_account_type = lookup(var.vm_object.os_disk, "storage_account_type", "Standard_LRS") - disk_encryption_set_id = var.disk_encryption_set_id == null ? null : var.disk_encryption_set_id - disk_size_gb = lookup(var.vm_object.os_disk, "disk_size_gb", null) - write_accelerator_enabled = lookup(var.vm_object.os_disk, "write_accelerator_enabled", false) - - dynamic "diff_disk_settings" { - - for_each = lookup(var.vm_object.os_disk, "diff_disk_settings", null) == null ? [] : [1] - - content { - option = lookup(var.vm_object.os_disk.diff_disk_settings, "option", "Local") - } - } - } - - boot_diagnostics { - storage_account_uri = azurerm_storage_account.devops.primary_blob_endpoint - } - - source_image_reference { - publisher = lookup(var.vm_object.source_image_reference, "publisher", null) - offer = lookup(var.vm_object.source_image_reference, "offer", null) - sku = lookup(var.vm_object.source_image_reference, "sku", null) - version = lookup(var.vm_object.source_image_reference, "version", "latest") - } - - identity { - type = "UserAssigned" - - identity_ids = [ - azurerm_user_assigned_identity.user_msi.id - ] - } - -} - - -resource "tls_private_key" "ssh" { - count = var.private_key_pem_file == "" ? 1 : 0 - - algorithm = "RSA" - rsa_bits = 4096 -} - -locals { - public_key = tls_private_key.ssh.0.public_key_openssh -} - - -resource "azurerm_user_assigned_identity" "user_msi" { - location = lookup(var.vm_object, "location", local.global_settings.default_location) - resource_group_name = local.resource_groups[var.vm_object.resource_group_key].name - - name = "release-agent-${var.azure_devops.pipeline_level}" -} - -# To be refactored based on configuration -resource "azurerm_role_assignment" "contributor" { - scope = data.azurerm_subscription.current.id - role_definition_name = "Contributor" - principal_id = azurerm_user_assigned_identity.user_msi.principal_id -} \ No newline at end of file diff --git a/landingzones/launchpad/azdo_keyvault_token.tf b/landingzones/launchpad/azdo_keyvault_token.tf deleted file mode 100644 index 6b6c953e..00000000 --- a/landingzones/launchpad/azdo_keyvault_token.tf +++ /dev/null @@ -1,17 +0,0 @@ -locals { - azure_devops = var.azure_devops == {} ? {} : lookup(var.azure_devops, "pats", {}) -} -resource "azurerm_key_vault_secret" "pat" { - for_each = local.azure_devops - - name = each.value.secret_name - value = "" - key_vault_id = azurerm_key_vault.keyvault[each.value.keyvault_key].id - - lifecycle { - ignore_changes = [ - value - ] - } -} - diff --git a/landingzones/launchpad/custom_roles.tf b/landingzones/launchpad/custom_roles.tf deleted file mode 100644 index 5414340f..00000000 --- a/landingzones/launchpad/custom_roles.tf +++ /dev/null @@ -1,9 +0,0 @@ -module custom_role_definition { - source = "aztfmod/caf-custom-role/azurerm" - version = "1.0.0" - - custom_role_definitions = var.custom_role_definitions - prefix = local.prefix - aad_apps = module.azure_applications.aad_apps - subscriptions = var.subscriptions -} diff --git a/landingzones/launchpad/diagnostics.tf b/landingzones/launchpad/diagnostics.tf deleted file mode 100644 index b65f5ee4..00000000 --- a/landingzones/launchpad/diagnostics.tf +++ /dev/null @@ -1,15 +0,0 @@ - -module "diagnostics" { - - source = "aztfmod/caf-diagnostics-logging/azurerm" - version = "~> 2.1.0" - - name = var.diagnostics_settings.resource_diagnostics_name - convention = lookup( var.diagnostics_settings, "convention", local.global_settings.convention) - resource_group_name = azurerm_resource_group.rg[var.diagnostics_settings.resource_group_key].name - prefix = local.prefix_start_alpha - location = lookup( var.diagnostics_settings, "location", azurerm_resource_group.rg[var.diagnostics_settings.resource_group_key].location) - tags = local.tags - - enable_event_hub = var.diagnostics_settings.azure_diagnostics_logs_event_hub -} \ No newline at end of file diff --git a/landingzones/launchpad/documentation/img/Launchpad_deployment.png b/landingzones/launchpad/documentation/img/Launchpad_deployment.png deleted file mode 100644 index 1f1f88d5..00000000 Binary files a/landingzones/launchpad/documentation/img/Launchpad_deployment.png and /dev/null differ diff --git a/landingzones/launchpad/github.tf b/landingzones/launchpad/github.tf deleted file mode 100644 index 3cb5b42f..00000000 --- a/landingzones/launchpad/github.tf +++ /dev/null @@ -1,14 +0,0 @@ -resource "azurerm_key_vault_secret" "github_pat" { - - name = "github-pat" - value = "" - key_vault_id = azurerm_key_vault.keyvault[var.launchpad_key_names.keyvault].id - - lifecycle { - ignore_changes = [ - value - ] - } -} - - diff --git a/landingzones/launchpad/keyvault.tf b/landingzones/launchpad/keyvault.tf deleted file mode 100644 index b7fb1bb8..00000000 --- a/landingzones/launchpad/keyvault.tf +++ /dev/null @@ -1,42 +0,0 @@ - -resource "azurecaf_naming_convention" "keyvault" { - for_each = var.keyvaults - - name = each.value.name - resource_type = "kv" - convention = lookup(each.value, "convention", local.global_settings.convention) - prefix = lookup(each.value, "useprefix", false) == true ? local.prefix_start_alpha : "" - max_length = lookup(each.value, "max_length", null) -} - -resource "azurerm_key_vault" "keyvault" { - for_each = var.keyvaults - - name = azurecaf_naming_convention.keyvault[each.key].result - location = lookup(each.value, "location", local.global_settings.default_location) - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - tenant_id = data.azurerm_client_config.current.tenant_id - - sku_name = each.value.sku_name - - tags = { - tfstate = var.level - environment = local.global_settings.environment - } - - access_policy { - tenant_id = data.azurerm_client_config.current.tenant_id - object_id = var.logged_user_objectId - - key_permissions = [] - secret_permissions = ["Get", "List", "Set", "Delete"] - } - - lifecycle { - ignore_changes = [ - access_policy - ] - } - -} - diff --git a/landingzones/launchpad/log_analytics.tf b/landingzones/launchpad/log_analytics.tf deleted file mode 100644 index 729f0eeb..00000000 --- a/landingzones/launchpad/log_analytics.tf +++ /dev/null @@ -1,13 +0,0 @@ - -module "log_analytics" { - source = "aztfmod/caf-log-analytics/azurerm" - version = "~> 2.3.0" - - name = var.log_analytics.resource_log_analytics_name - convention = lookup( var.log_analytics, "convention", local.global_settings.convention) - solution_plan_map = var.log_analytics.solutions_maps - resource_group_name = azurerm_resource_group.rg[var.log_analytics.resource_group_key].name - prefix = local.prefix_start_alpha - location = lookup( var.log_analytics, "location", azurerm_resource_group.rg[var.log_analytics.resource_group_key].location) - tags = local.tags -} diff --git a/landingzones/launchpad/main.tf b/landingzones/launchpad/main.tf deleted file mode 100644 index f5d40c09..00000000 --- a/landingzones/launchpad/main.tf +++ /dev/null @@ -1,67 +0,0 @@ -terraform { - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = "~> 2.25.0" - } - azuread = { - source = "hashicorp/azuread" - version = "~> 0.10.0" - } - random = { - source = "hashicorp/random" - version = "~> 2.2.1" - } - null = { - source = "hashicorp/null" - version = "~> 2.1.0" - } - azurecaf = { - source = "aztfmod/azurecaf" - version = "~>0.4.3" - } - } - required_version = ">= 0.13" -} - - -provider "azurerm" { - features {} -} - - -data "azurerm_subscription" "primary" {} -data "azurerm_client_config" "current" {} - - -resource "random_string" "prefix" { - length = 4 - special = false - upper = false - number = false -} - -resource "random_string" "alpha1" { - length = 1 - special = false - upper = false - number = false -} - -locals { - landingzone_tag = { - landingzone = var.launchpad_mode - } - tags = merge(var.tags, local.landingzone_tag, { "level" = var.level }, { "environment" = var.environment }, { "rover_version" = var.rover_version }) - - global_settings = { - prefix = local.prefix - convention = var.convention - default_location = var.location - environment = var.environment - } - - prefix = var.prefix == null ? random_string.prefix.result : var.prefix - prefix_with_hyphen = local.prefix == "" ? "" : "${local.prefix}-" - prefix_start_alpha = local.prefix == "" ? "" : "${random_string.alpha1.result}${local.prefix}" -} \ No newline at end of file diff --git a/landingzones/launchpad/networking.tf b/landingzones/launchpad/networking.tf deleted file mode 100644 index 6724c916..00000000 --- a/landingzones/launchpad/networking.tf +++ /dev/null @@ -1,18 +0,0 @@ - -module "virtual_network" { - source = "aztfmod/caf-virtual-network/azurerm" - version = "~> 3.1.0" - - for_each = var.networking - - prefix = local.global_settings.prefix - convention = lookup( var.diagnostics_settings, "convention", local.global_settings.convention) - location = azurerm_resource_group.rg[each.value.resource_group_key].location - resource_group_name = azurerm_resource_group.rg[each.value.resource_group_key].name - networking_object = each.value - tags = local.tags - diagnostics_map = module.diagnostics.diagnostics_map - diagnostics_settings = each.value.diags - log_analytics_workspace = module.log_analytics.object -} - diff --git a/landingzones/launchpad/output.tf b/landingzones/launchpad/output.tf deleted file mode 100644 index 4426dbe9..00000000 --- a/landingzones/launchpad/output.tf +++ /dev/null @@ -1,66 +0,0 @@ - -output aad_apps { - sensitive = true - value = module.azure_applications.aad_apps -} - -output global_settings { - sensitive = true - value = local.global_settings -} - -output resource_groups { - sensitive = true - value = azurerm_resource_group.rg -} - -output log_analytics { - sensitive = true - value = module.log_analytics.object -} - -output diagnostics_map { - sensitive = true - value = module.diagnostics.diagnostics_map -} - -# output azure_devops_user_admin { -# depends_on = [ azuread_user.account ] -# sensitive = true - -# value = { -# user_principal_name = lookup(azuread_user.account, var.launchpad_key_names.azure_devops_admin_for_pat, null) == null ? null : azuread_user.account[var.launchpad_key_names.azure_devops_admin_for_pat].user_principal_name -# secret_password_key = lookup(azurerm_key_vault_secret.aad_user_password, var.launchpad_key_names.azure_devops_admin_for_pat, null) == null ? null : azurerm_key_vault_secret.aad_user_password[var.launchpad_key_names.azure_devops_admin_for_pat].name -# tenant_name = var.aad_users[var.launchpad_key_names.azure_devops_admin_for_pat].tenant_name -# tenant_id = data.azurerm_client_config.current.tenant_id -# keyvault_id = azurerm_key_vault.keyvault[var.launchpad_key_names.keyvault].id -# keyvault_name = azurerm_key_vault.keyvault[var.launchpad_key_names.keyvault].name -# } -# } - -# Does not work in light mode -output azure_subscriptions { - sensitive = true - value = var.subscriptions -} - -output keyvaults { - sensitive = true - value = azurerm_key_vault.keyvault -} - -output networking { - sensitive = true - value = module.virtual_network -} - -output github_token_keyvault { - sensitive = true - - value = { - keyvault_secret_name = azurerm_key_vault_secret.github_pat.name - keyvault_name = azurerm_key_vault.keyvault[var.launchpad_key_names.keyvault].name - keyvault_id = azurerm_key_vault.keyvault[var.launchpad_key_names.keyvault].id - } -} - diff --git a/landingzones/launchpad/resource_groups.tf b/landingzones/launchpad/resource_groups.tf deleted file mode 100644 index f824ff3d..00000000 --- a/landingzones/launchpad/resource_groups.tf +++ /dev/null @@ -1,19 +0,0 @@ - -resource "azurecaf_naming_convention" "rg" { - for_each = var.resource_groups - - name = each.value.name - resource_type = "azurerm_resource_group" - convention = lookup(each.value, "convention", local.global_settings.convention) - prefix = lookup(each.value, "useprefix", false) == true ? local.prefix : "" - max_length = lookup(each.value, "max_length", null) -} - -resource "azurerm_resource_group" "rg" { - for_each = var.resource_groups - - name = azurecaf_naming_convention.rg[each.key].result - location = lookup(each.value, "location", local.global_settings.default_location) - tags = merge(lookup(each.value, "tags", {}), local.tags) -} - diff --git a/landingzones/launchpad/scripts/set_ad_role.sh b/landingzones/launchpad/scripts/set_ad_role.sh deleted file mode 100644 index c49807bb..00000000 --- a/landingzones/launchpad/scripts/set_ad_role.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -set -e - -function active_directory_role { - # Verify the AD_ROLE_NAME has been activated in the directory - # Permissions required - https://docs.microsoft.com/en-us/graph/api/directoryrole-post-directoryroles?view=graph-rest-1.0&tabs=http#permissions - - echo "Activate directory role" - ROLE_ID=$(az rest --method Get --uri https://graph.microsoft.com/v1.0/directoryRoleTemplates -o json | jq -r '.value[] | select(.displayName == "'"$(echo ${AD_ROLE_NAME})"'") | .id') - - URI="https://graph.microsoft.com/v1.0/directoryRoles" - - JSON=$( jq -n \ - --arg role_id ${ROLE_ID} \ - '{"roleTemplateId": $role_id}' ) && echo " - body: $JSON" - - - az rest --method POST --uri $URI --header Content-Type=application/json --body "$JSON" - -} - -echo "Assigning directory role '${AD_ROLE_NAME}'" - - -# Add service principal to AD Role - -export ROLE_AAD=$(az rest --method Get --uri https://graph.microsoft.com/v1.0/directoryRoles -o json | jq -r '.value[] | select(.displayName == "'"$(echo ${AD_ROLE_NAME})"'") | .id') - -if [ "${ROLE_AAD}" == '' ]; then - active_directory_role -fi - -URI=$(echo "https://graph.microsoft.com/v1.0/directoryRoles/${ROLE_AAD}/members/\$ref") && echo " - uri: $URI" - -# grant AAD role to the AAD APP -JSON=$( jq -n \ - --arg uri_role "https://graph.microsoft.com/v1.0/directoryObjects/${SERVICE_PRINCIPAL_OBJECT_ID}" \ - '{"@odata.id": $uri_role}' ) && echo " - body: $JSON" - -az rest --method POST --uri $URI --header Content-Type=application/json --body "$JSON" - -echo "Role '${AD_ROLE_NAME}' assigned to azure ad application" - diff --git a/landingzones/launchpad/storage.tf b/landingzones/launchpad/storage.tf deleted file mode 100644 index 9cd699fa..00000000 --- a/landingzones/launchpad/storage.tf +++ /dev/null @@ -1,49 +0,0 @@ - -resource "azurecaf_naming_convention" "stg" { - - name = var.storage_account_name - resource_type = "azurerm_storage_account" - convention = local.global_settings.convention - prefix = local.prefix -} - - -resource "azurerm_storage_account" "stg" { - - name = azurecaf_naming_convention.stg.result - resource_group_name = azurerm_resource_group.rg["tfstate"].name - location = azurerm_resource_group.rg["tfstate"].location - account_kind = "BlobStorage" - account_tier = "Standard" - account_replication_type = "RAGRS" - - tags = { - tfstate = var.level - environment = local.global_settings.environment - launchpad = var.launchpad_mode - } - - lifecycle { - ignore_changes = [ - tags.launchpad - ] - } -} - -resource "azurerm_storage_container" "launchpad" { - name = "level0" - storage_account_name = azurerm_storage_account.stg.name - container_access_type = "private" -} - -resource "azurerm_role_assignment" "role1_current_user" { - scope = azurerm_resource_group.rg["tfstate"].id - role_definition_name = "Storage Blob Data Contributor" - principal_id = var.logged_user_objectId - - lifecycle { - ignore_changes = [ - principal_id - ] - } -} \ No newline at end of file diff --git a/landingzones/launchpad/subscription_role.tf b/landingzones/launchpad/subscription_role.tf deleted file mode 100644 index 93870494..00000000 --- a/landingzones/launchpad/subscription_role.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "azurerm_role_assignment" "subscription" { - for_each = var.subscriptions - - scope = each.key == "logged_in_subscription" ? format("/subscriptions/%s", data.azurerm_subscription.primary.subscription_id) : format("/subscriptions/%s", each.value.subscription_id) - role_definition_name = each.value.role_definition_name - principal_id = module.azure_applications.aad_apps[each.value.aad_app_key].azuread_service_principal.object_id -} \ No newline at end of file diff --git a/landingzones/launchpad/variables.tf b/landingzones/launchpad/variables.tf deleted file mode 100644 index 90d91389..00000000 --- a/landingzones/launchpad/variables.tf +++ /dev/null @@ -1,106 +0,0 @@ -variable launchpad_mode { - default = "launchpad_light" - type = string - - validation { - condition = contains(["launchpad_light", "launchpad"], var.launchpad_mode) - error_message = "Allowed values are launchpad_light or launchpad." - } -} - -variable level { - default = "level0" - type = string - - validation { - condition = contains(["level0", "level1", "level2", "level3", "level4"], var.level) - error_message = "Allowed values are level0, level1, level2, level3 or level4." - } -} - -variable convention { - default = "cafrandom" - - validation { - condition = contains(["cafrandom", "random", "passthrough", "cafclassic"], var.convention) - error_message = "Convention allowed values are cafrandom, random, passthrough or cafclassic." - } -} - -variable location { - default = "southeastasia" -} - -variable prefix { - default = null -} - -# Do not change the default value to be able to upgrade to the standard launchpad -variable tf_name { - description = "Name of the terraform state in the blob storage (Does not include the extension .tfstate)" - default = "launchpad" -} - -variable resource_groups {} - -variable storage_account_name { - type = string -} - -variable keyvaults {} - -variable subscriptions {} - -variable aad_apps {} - -variable launchpad_key_names {} - -variable custom_role_definitions { - default = {} -} - -variable tags { - type = map - default = {} -} - -variable rover_version {} - -variable user_type {} - -variable logged_user_objectId {} - -variable aad_users { - default = {} -} - -variable aad_roles { - default = {} -} - -variable aad_api_permissions { - default = {} -} - -variable github_projects { - default = {} -} - -variable azure_devops { - default = {} -} - -variable environment { - type = string - description = "This variable is set by the rover during the deployment based on the -env or -environment flags. Default to sandpit" -} - -variable blueprint_networking { - default = {} -} - -variable diagnostics_settings {} - -variable log_analytics {} - -variable networking {}