From c308deb8ecb2dd04c8570d112479287070274bf6 Mon Sep 17 00:00:00 2001 From: Glenn Musa <4622125+glennmusa@users.noreply.github.com> Date: Fri, 17 Sep 2021 13:57:44 -0400 Subject: [PATCH] deploy Terraform modules without wrapping scripts (#415) --- .devcontainer/README.md | 3 +- .../workflows/apply-and-destroy-terraform.yml | 52 --- README.md | 8 +- docs/command-line-deployment.md | 25 ++ docs/getting-started.md | 42 +++ .../images}/custom_template_deployment.gif | Bin .../imgs => docs/images}/deploytoazure.svg | 0 .../imgs => docs/images}/deploytoazuregov.svg | 0 .../mg1-management-groups-list.png | Bin .../mg2-empty-subscription-list.png | Bin .../mg3-select-subscription.png | Bin .../mg4-subscription-in-management-group.png | Bin .../images/missionlz_as_of_may2021.png | Bin {src/docs => docs}/images/networking.png | Bin {src/docs => docs}/images/scope.png | Bin {src/docs => docs}/management-groups.md | 0 {src/docs => docs}/scca.md | 0 .../using-the-devcontainer.md | 44 +-- docs/workload-deployment.md | 21 ++ src/bicep/README.md | 22 +- src/bicep/examples/newWorkload/README.md | 4 +- src/bicep/examples/remoteAccess/README.md | 4 +- src/bicep/ui/README.md | 6 +- src/build/README.md | 76 ---- src/build/apply_tf.sh | 115 ------ src/build/destroy_tf.sh | 111 ------ src/build/get_vars.sh | 45 --- src/build/login_azcli.sh | 38 -- src/docs/command-line-deployment.md | 257 ------------- src/docs/terraform/deployment.md | 179 --------- src/docs/workload-deployment.md | 92 ----- src/mlz.config.sample | 17 - src/scripts/clean.sh | 147 -------- src/scripts/config/append_prereq_endpoints.sh | 86 ----- src/scripts/config/config_clean.sh | 87 ----- src/scripts/config/config_validate.sh | 58 --- .../config/create_mlz_config_resources.sh | 249 ------------ .../config/create_required_resources.sh | 48 --- .../create_terraform_backend_resources.sh | 99 ----- src/scripts/config/generate_config_file.sh | 140 ------- src/scripts/config/generate_names.sh | 81 ---- src/scripts/config/generate_vars.sh | 58 --- src/scripts/config/get_sp_identity.sh | 101 ----- .../config/validate_minimum_role_for_sp.sh | 81 ---- src/scripts/deploy.sh | 271 -------------- src/scripts/deploy_t3.sh | 118 ------ src/scripts/security-center/configure_asc.sh | 170 --------- src/scripts/security-center/generate_names.sh | 35 -- src/scripts/terraform/apply_terraform.sh | 51 --- .../terraform/create_tfvars_from_config.sh | 84 ----- src/scripts/terraform/destroy_terraform.sh | 46 --- src/scripts/terraform/init_terraform.sh | 70 ---- .../terraform/validate_cloud_for_tf_env.sh | 58 --- src/scripts/util/checkforarmcredential.sh | 38 -- src/scripts/util/checkforazcli.sh | 22 -- src/scripts/util/checkforfile.sh | 27 -- src/scripts/util/checkforterraform.sh | 13 - src/scripts/util/checkforzip.sh | 13 - src/scripts/util/validateazlocation.sh | 42 --- src/terraform/README.md | 353 ++++++++++++++++++ src/terraform/mlz/main.tf | 97 ++--- src/terraform/mlz/minimum.tfvars.sample | 19 - src/terraform/mlz/mlz.tfvars.sample | 248 ------------ src/terraform/mlz/output.tf | 17 - src/terraform/mlz/outputs.tf | 37 ++ src/terraform/mlz/variables.tf | 139 ++++--- src/terraform/modules/subnet/main.tf | 2 +- src/terraform/tier3/main.tf | 39 +- src/terraform/tier3/minimum.tfvars.sample | 15 - src/terraform/tier3/{output.tf => outputs.tf} | 0 src/terraform/tier3/tier3.tfvars.sample | 79 ---- src/terraform/tier3/variables.tf | 60 +-- 72 files changed, 708 insertions(+), 3851 deletions(-) delete mode 100644 .github/workflows/apply-and-destroy-terraform.yml create mode 100644 docs/command-line-deployment.md create mode 100644 docs/getting-started.md rename {src/bicep/docs/imgs => docs/images}/custom_template_deployment.gif (100%) rename {src/bicep/docs/imgs => docs/images}/deploytoazure.svg (100%) rename {src/bicep/docs/imgs => docs/images}/deploytoazuregov.svg (100%) rename {src/docs => docs}/images/management-groups/mg1-management-groups-list.png (100%) rename {src/docs => docs}/images/management-groups/mg2-empty-subscription-list.png (100%) rename {src/docs => docs}/images/management-groups/mg3-select-subscription.png (100%) rename {src/docs => docs}/images/management-groups/mg4-subscription-in-management-group.png (100%) rename {src/docs => docs}/images/missionlz_as_of_may2021.png (100%) rename {src/docs => docs}/images/networking.png (100%) rename {src/docs => docs}/images/scope.png (100%) rename {src/docs => docs}/management-groups.md (100%) rename {src/docs => docs}/scca.md (100%) rename src/docs/getting-started.md => docs/using-the-devcontainer.md (51%) create mode 100644 docs/workload-deployment.md delete mode 100644 src/build/README.md delete mode 100755 src/build/apply_tf.sh delete mode 100755 src/build/destroy_tf.sh delete mode 100755 src/build/get_vars.sh delete mode 100755 src/build/login_azcli.sh delete mode 100644 src/docs/command-line-deployment.md delete mode 100644 src/docs/terraform/deployment.md delete mode 100644 src/docs/workload-deployment.md delete mode 100644 src/mlz.config.sample delete mode 100755 src/scripts/clean.sh delete mode 100755 src/scripts/config/append_prereq_endpoints.sh delete mode 100755 src/scripts/config/config_clean.sh delete mode 100755 src/scripts/config/config_validate.sh delete mode 100755 src/scripts/config/create_mlz_config_resources.sh delete mode 100755 src/scripts/config/create_required_resources.sh delete mode 100755 src/scripts/config/create_terraform_backend_resources.sh delete mode 100755 src/scripts/config/generate_config_file.sh delete mode 100755 src/scripts/config/generate_names.sh delete mode 100755 src/scripts/config/generate_vars.sh delete mode 100755 src/scripts/config/get_sp_identity.sh delete mode 100755 src/scripts/config/validate_minimum_role_for_sp.sh delete mode 100755 src/scripts/deploy.sh delete mode 100755 src/scripts/deploy_t3.sh delete mode 100755 src/scripts/security-center/configure_asc.sh delete mode 100755 src/scripts/security-center/generate_names.sh delete mode 100755 src/scripts/terraform/apply_terraform.sh delete mode 100755 src/scripts/terraform/create_tfvars_from_config.sh delete mode 100755 src/scripts/terraform/destroy_terraform.sh delete mode 100755 src/scripts/terraform/init_terraform.sh delete mode 100755 src/scripts/terraform/validate_cloud_for_tf_env.sh delete mode 100755 src/scripts/util/checkforarmcredential.sh delete mode 100755 src/scripts/util/checkforazcli.sh delete mode 100755 src/scripts/util/checkforfile.sh delete mode 100755 src/scripts/util/checkforterraform.sh delete mode 100755 src/scripts/util/checkforzip.sh delete mode 100755 src/scripts/util/validateazlocation.sh create mode 100644 src/terraform/README.md delete mode 100644 src/terraform/mlz/minimum.tfvars.sample delete mode 100644 src/terraform/mlz/mlz.tfvars.sample delete mode 100644 src/terraform/mlz/output.tf create mode 100644 src/terraform/mlz/outputs.tf delete mode 100644 src/terraform/tier3/minimum.tfvars.sample rename src/terraform/tier3/{output.tf => outputs.tf} (100%) delete mode 100644 src/terraform/tier3/tier3.tfvars.sample diff --git a/.devcontainer/README.md b/.devcontainer/README.md index e0a33009d..8c37537c8 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -11,7 +11,8 @@ All configuration related to the development container is in the `.devcontainer` ### Step-by-Step -1. Follow the Mission LZ [Getting Started](https://github.com/Azure/missionlz/blob/main/src/docs/getting-started.md#pre-requisites) pre-requisites and step-by-step guide. +1. Follow the Mission LZ [Getting Started](../docs/getting-started.md) pre-requisites and step-by-step guide. + 1. Open a command line (e.g. `wsl.exe` or `bash.exe`), change to the root folder of the local workspace for the cloned Mission LZ project, and start VS Code from this root folder (not a sub folder or a parent folder). > **NOTE:** If you are using WSL or BASH on Linux or Mac, you can navigate to the root folder of the project (for example, in the path `$HOME/missionlz` assuming you cloned the project to $HOME) and enter the command below to launch VS Code in correct directory. Be sure to include the trailing "." in the second command. diff --git a/.github/workflows/apply-and-destroy-terraform.yml b/.github/workflows/apply-and-destroy-terraform.yml deleted file mode 100644 index 8014424a6..000000000 --- a/.github/workflows/apply-and-destroy-terraform.yml +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -name: apply-and-destroy-terraform -on: [workflow_dispatch] -jobs: - apply-and-destroy-terraform: - runs-on: ubuntu-latest - - container: - image: acrmlzcicd.azurecr.io/missionlzdev - credentials: - username: ${{ secrets.acr_username }} - password: ${{ secrets.acr_password }} - - steps: - - uses: actions/checkout@v2 - - - uses: azure/login@v1 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - - - uses: Azure/get-keyvault-secrets@v1 - with: - keyvault: ${{ secrets.KEY_VAULT_NAME }} - secrets: '*' - - - name: get vars - run : | - cd src/build - ./get_vars.sh "$STORAGEACCOUNT" "$STORAGETOKEN" "$STORAGECONTAINER" - - - name: login - run : | - cd src/build - ./login_azcli.sh "$MLZTENANTID" "$MLZCLIENTID" "$MLZCLIENTSECRET" - - - name: apply terraform - run : | - cd src/build - ./apply_tf.sh \ - vars/mlz.config \ - vars/mlz.tfvars \ - n - - - name: destroy terraform - run : | - cd src/build - ./destroy_tf.sh \ - vars/mlz.config \ - vars/mlz.tfvars \ - n diff --git a/README.md b/README.md index 11e74cb92..e3f053b02 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Mission LZ has the following scope: -Mission LZ Scope +Mission LZ Scope ## Networking @@ -53,12 +53,12 @@ Mission LZ has the following scope: Networking is set up in a hub and spoke design, separated by tiers: T0 (Identity and Authorization), T1 (Infrastructure Operations), T2 (DevSecOps and Shared Services), and multiple T3s (Workloads). Security can be configured to allow separation of duties between all tiers. Most customers will deploy each tier to a separate Azure subscription, but multiple subscriptions are not required. -Mission LZ Networking +Mission LZ Networking ## Getting Started using Mission LZ -See our [Getting Started Guide](src/docs/getting-started.md) in the docs. +See our [Getting Started Guide](docs/getting-started.md) in the docs. ## Product Roadmap @@ -67,7 +67,7 @@ See the [Projects](https://github.com/Azure/missionlz/projects) page for the rel Here's what the repo consists of as of May 2021: -Mission LZ as of April 2021 +Mission LZ as of April 2021 ## Contributing diff --git a/docs/command-line-deployment.md b/docs/command-line-deployment.md new file mode 100644 index 000000000..10611c4e9 --- /dev/null +++ b/docs/command-line-deployment.md @@ -0,0 +1,25 @@ +# Command-Line Deployment + +The steps in this article assume the following pre-requisites for command-line deployments: + +* Follow the Mission LZ [Getting Started](./getting-started.md) steps. + +## Step-by-step + +1. Follow the [steps to open the `.devcontainer`](../.devcontainer/README.md) as recommended (or start a local BASH shell with the prerequisites installed) + + > `vscode@missionlz-dev:/workspaces/missionlz$` is the root working directory for the BASH shell in the `.devcontainer` + +1. Deploy with Bicep (recommended) + 1. [Deploy](../src/bicep/README.md#Azure-CLI) + 1. [Customize deployment](../src/bicep/README.md#Deploying-to-Other-Clouds) + +1. Or, deploy with Terraform + 1. [Apply](../src/terraform/README.md) + 1. [Customize deployment](../src/terraform/README.md#Deploying-to-Other-Clouds) + +See the development container [README](../.devcontainer/README.md) for more details on building and running the container. + +## Helpful Links + +For more endpoint mappings between AzureCloud and AzureUsGovernment: diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 000000000..3f358085e --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,42 @@ +# Getting Started + +## Prerequisites + +* Current version of the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) +* An Azure Subscription where you have ['Owner' RBAC permissions](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner) + +## Concepts + +### Command Line Deployments + +You can deploy Mission LZ from your workstation using the command line. Some other configurations are possible, but this is the simplest path. + +We highly recommend deploying from the Development Container since it comes packaged with all the right versions of the dependencies you'll need. + +### Use the Development Container for Command Line Deployments + +If you are planning to deploy from your local workstation, we recommend using the VS Code development container specified in this repository. The container includes all the tools and pre-requisites, but you have to build and run the container. If you have Docker Desktop installed, then VS Code makes the rest of it easy. See the [README](../.devcontainer/README.md) document in the `.devcontainer` folder for details. + +See [Using the devcontainer](./using-the-devcontainer.md) for configuring your workstation with the development container. + +If you want to deploy from the command line on your workstation but do not want to use the development container, take a look at the [`Dockerfile`](../.devcontainer/Dockerfile) and the [`devcontainer.json`](../.devcontainer/Dockerfile) file for examples on how to configure your environment. + +## Next steps + +### 1. Deploy the Hub and Spoke + +With the environment pre-requisites out of the way, deploy the hub and spoke using the [Command Line Deployment](./command-line-deployment.md) for step-by-step instructions: + +* [Command Line Deployment](./command-line-deployment.md) + +### 2. Deploy Your Workloads + +Now that you have the core hub and spoke tiers deployed (Hub, Tier 0, Tier 1, Tier 2), the next step is to deploy one or more workload tiers. Misson LZ supports multiple workload tiers. See [Workload Deployment](./workload-deployment.md) for details and step-by-step instructions: + +* [Workload Deployment](./workload-deployment.md) + +### 3. Manage Your Deployment + +Once you have a lab deployment of Mission Landing Zone established and have decided to move forward, you will want to start planning your production deployment. We recommend reviewing the following pages during your planning phase. + +* [Using Management Groups with Mission Landing Zone](./management-groups.md) diff --git a/src/bicep/docs/imgs/custom_template_deployment.gif b/docs/images/custom_template_deployment.gif similarity index 100% rename from src/bicep/docs/imgs/custom_template_deployment.gif rename to docs/images/custom_template_deployment.gif diff --git a/src/bicep/docs/imgs/deploytoazure.svg b/docs/images/deploytoazure.svg similarity index 100% rename from src/bicep/docs/imgs/deploytoazure.svg rename to docs/images/deploytoazure.svg diff --git a/src/bicep/docs/imgs/deploytoazuregov.svg b/docs/images/deploytoazuregov.svg similarity index 100% rename from src/bicep/docs/imgs/deploytoazuregov.svg rename to docs/images/deploytoazuregov.svg diff --git a/src/docs/images/management-groups/mg1-management-groups-list.png b/docs/images/management-groups/mg1-management-groups-list.png similarity index 100% rename from src/docs/images/management-groups/mg1-management-groups-list.png rename to docs/images/management-groups/mg1-management-groups-list.png diff --git a/src/docs/images/management-groups/mg2-empty-subscription-list.png b/docs/images/management-groups/mg2-empty-subscription-list.png similarity index 100% rename from src/docs/images/management-groups/mg2-empty-subscription-list.png rename to docs/images/management-groups/mg2-empty-subscription-list.png diff --git a/src/docs/images/management-groups/mg3-select-subscription.png b/docs/images/management-groups/mg3-select-subscription.png similarity index 100% rename from src/docs/images/management-groups/mg3-select-subscription.png rename to docs/images/management-groups/mg3-select-subscription.png diff --git a/src/docs/images/management-groups/mg4-subscription-in-management-group.png b/docs/images/management-groups/mg4-subscription-in-management-group.png similarity index 100% rename from src/docs/images/management-groups/mg4-subscription-in-management-group.png rename to docs/images/management-groups/mg4-subscription-in-management-group.png diff --git a/src/docs/images/missionlz_as_of_may2021.png b/docs/images/missionlz_as_of_may2021.png similarity index 100% rename from src/docs/images/missionlz_as_of_may2021.png rename to docs/images/missionlz_as_of_may2021.png diff --git a/src/docs/images/networking.png b/docs/images/networking.png similarity index 100% rename from src/docs/images/networking.png rename to docs/images/networking.png diff --git a/src/docs/images/scope.png b/docs/images/scope.png similarity index 100% rename from src/docs/images/scope.png rename to docs/images/scope.png diff --git a/src/docs/management-groups.md b/docs/management-groups.md similarity index 100% rename from src/docs/management-groups.md rename to docs/management-groups.md diff --git a/src/docs/scca.md b/docs/scca.md similarity index 100% rename from src/docs/scca.md rename to docs/scca.md diff --git a/src/docs/getting-started.md b/docs/using-the-devcontainer.md similarity index 51% rename from src/docs/getting-started.md rename to docs/using-the-devcontainer.md index 4aecddd64..5e350c4e9 100644 --- a/src/docs/getting-started.md +++ b/docs/using-the-devcontainer.md @@ -1,27 +1,11 @@ -# Getting Started +# Using the devcontainer -## Concepts - -### Command Line Deployments - -You can deploy Mission LZ from your workstation using the command line. Some other configurations are possible, but these are the two simplest paths. - -The command-line deployments involve (1) defining configuration settings (we have examples and defaults to make this easier), and (2) running shell scripts that consolidate and wrap the Terraform commands. We strongly recommend using these scripts because they were designed to be usable, but you could also run the Terraform templates directly using the `terraform` command line tool. - -### Use the Development Container for Command Line Deployments - -If you are planning to deploy from your local workstation, we recommend using the VS Code development container specified in this repository. The container includes all the tools and pre-requisites, but you have to build and run the container. If you have Docker Desktop installed, then VS Code makes the rest of it easy. See the [README](../../.devcontainer/README.md) document in the `.devcontainer` folder for details. - -If you want to deploy from the command line on your workstation but do not want to use the development container, take a look at the [`Dockerfile`](../../.devcontainer/Dockerfile) and the [`devcontainer.json`](../../.devcontainer/Dockerfile) file for examples on how to configure your environment. - -## Pre-Requisites +## Prerequisites * **Operating system:** Mac OS, Linux, or [Windows 10 with Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install-win10) >*We developed this on Windows 10/WSL running Ubuntu 20.04* * **Docker:** Docker Desktop or Docker CE >*We use [Docker Desktop on Windows 10](https://docs.docker.com/docker-for-windows/install/), integrated with WSL* -* Current version of the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli). -* An Azure Subscription where you have ['Owner' RBAC permissions]. All other tools and resources are in the development container. The simplest path is to deploy from one of these containers, but it is not required if you want to configure your own deployment environment. @@ -46,27 +30,3 @@ All other tools and resources are in the development container. The simplest pat ```BASH git config --global credential.helper "/mnt/c/Program\ Files/Git/mingw64/libexec/git-core/git-credential-manager.exe" ``` - -## Deployment paths - -* (*Optional*) For details and pre-requisites for the development container, see the [README](../../.devcontainer/README.md) document in the `.devcontainer` folder. - -## Next steps - -### 1. Deploy the Hub and Spoke - -With the environment pre-requisites out of the way, deploy the hub and spoke using the [Command Line Deployment](command-line-deployment.md) for step-by-step instructions: - -* [Command Line Deployment](command-line-deployment.md) - -### 2. Deploy Your Workloads - -Now that you have the core hub and spoke tiers deployed (tier 0, tier 1, tier 2), the next step is to deploy one or more workload tiers. Misson LZ supports multiple workload tiers. See [Workload Deployment](workload-deployment.md) for details and step-by-step instructions: - -* [Workload Deployment](workload-deployment.md) - -### 3. Manage Your Deployment - -Once you have a lab deployment of Mission Landing Zone established and have decided to move forward, you will want to start planning your production deployment. We recommend reviewing the following pages during your planning phase. - -* [Using Management Groups with Mission Landing Zone](management-groups.md) diff --git a/docs/workload-deployment.md b/docs/workload-deployment.md new file mode 100644 index 000000000..844d68eaf --- /dev/null +++ b/docs/workload-deployment.md @@ -0,0 +1,21 @@ +# Workload Deployment (Tier 3) + +Mission LZ supports deploying multiple workload tiers that are connected to the hub. We call these tier 3s, or T3s, for convenience. Each tier 3 is intended to support a single workload or single team that needs isolation from the other teams and network connectivity via the hub. + +You'll have to have completed the deployment of Mission LZ to peer this new workload to the Hub network and Firewall. See [Command-Line Deployment](./command-line-deployment.md) for steps on how to do deploy those things. + +## Step-by-step + +1. Log in using the Azure CLI + + ```BASH + az login + ``` + +1. Deploy with Bicep (recommended) + 1. [Deploy](../src/bicep/examples/newWorkload/README.md) + 1. [Customize deployment](../src/bicep/README.md#Deploying-to-Other-Clouds) + +1. Or, deploy with Terraform + 1. [Apply](../src/terraform/README.md#Deploying-new-Spoke-Networks) + 1. [Customize deployment](../src/terraform/README.md#Deploying-to-Other-Clouds) diff --git a/src/bicep/README.md b/src/bicep/README.md index 4324951ff..3fde0f23a 100644 --- a/src/bicep/README.md +++ b/src/bicep/README.md @@ -4,8 +4,8 @@ If you want to develop with Bicep you'll need these: -1. Install Azure CLI https://docs.microsoft.com/en-us/cli/azure/install-azure-cli#install -1. Install Bicep https://github.com/Azure/bicep/blob/main/docs/installing.md#install-and-manage-via-azure-cli-easiest +1. Install Azure CLI +1. Install Bicep However, you don't need Bicep to deploy the compiled `mlz.json` in this repository. @@ -21,10 +21,12 @@ You can deploy with the Azure Portal, the Azure CLI, or with both in an Air-Gapp ### Azure Portal #### AzureCloud -[![Deploy To Azure](docs/imgs/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fglennmusa%2Fmissionlz%2Fglennmusa%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json) + +[![Deploy To Azure](../../docs/images/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fazure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json) #### AzureUSGovernment -[![Deploy To Azure US Gov](docs/imgs/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fglennmusa%2Fmissionlz%2Fglennmusa%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json) + +[![Deploy To Azure US Gov](../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fazure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json) ### Azure CLI @@ -50,7 +52,13 @@ az deployment sub create \ identitySubscriptionId=$identitySubscriptionId \ operationsSubscriptionId=$operationsSubscriptionId \ sharedServicesSubscriptionId=$sharedServicesSubscriptionId +``` +#### Deploying to Other Clouds + +Supply a different deployment `--location` or override variables with the `--parameters` options: + +```plaintext # if I were deploying into AzureUSGovernment for example: az cloud set -n AzureUsGovernment az deployment sub create \ @@ -69,15 +77,15 @@ az deployment sub create \ #### Manually upload and deploy from Portal -1. Save `mlz.json` to disk: https://raw.githubusercontent.com/glennmusa/missionlz/glennmusa/bicep/src/bicep/mlz.json -1. Create a deployment using the 'Custom Deployment' feature: https://portal.azure.com/#create/Microsoft.Template or https://portal.azure.us/#create/Microsoft.Template +1. Save `mlz.json` to disk: +1. Create a deployment using the 'Custom Deployment' feature: or 1. Click 'Build your own template in the editor' 1. Click 'Load file' 1. Select the 'mlz.json' file you saved 1. Click 'Save' 1. Click 'Review + Create' -Check out this GIF in the docs to see a visual explanation: [docs/imgs/custom_template_deployment.gif](docs/imgs/custom_template_deployment.gif) +Check out this GIF in the docs to see a visual explanation: [../../docs/images/custom_template_deployment.gif](../../docs/images/custom_template_deployment.gif) #### Deploy with Azure CLI diff --git a/src/bicep/examples/newWorkload/README.md b/src/bicep/examples/newWorkload/README.md index 1871ad4bc..f2e915e7a 100644 --- a/src/bicep/examples/newWorkload/README.md +++ b/src/bicep/examples/newWorkload/README.md @@ -117,7 +117,7 @@ az deployment sub create \ Or, completely experimentally, try the Portal: #### AzureCloud -[![Deploy To Azure](../../docs/imgs/deploytoazure.svg?sanitze=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fglennmusa%2Fmissionlz%2Fglennmusa%2Fbicep%2Fsrc%2Fbicep%2Fexamples%2FnewWorkload%2FnewWorkload.json) +[![Deploy To Azure](../../../../docs/images/deploytoazure.svg?sanitze=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fazure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fexamples%2FnewWorkload%2FnewWorkload.json) #### AzureUSGovernment -[![Deploy To Azure US Gov](../../docs/imgs/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fglennmusa%2Fmissionlz%2Fglennmusa%2Fbicep%2Fexamples%2FnewWorkload%2FnewWorkload.json) +[![Deploy To Azure US Gov](../../../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fazure%2Fmissionlz%2Fbicep%2Fexamples%2FnewWorkload%2FnewWorkload.json) diff --git a/src/bicep/examples/remoteAccess/README.md b/src/bicep/examples/remoteAccess/README.md index b0ad41f2c..1c0e73cd1 100644 --- a/src/bicep/examples/remoteAccess/README.md +++ b/src/bicep/examples/remoteAccess/README.md @@ -114,8 +114,8 @@ Or, completely experimentally, try the Portal: ### AzureCloud -[![Deploy To Azure](../../docs/imgs/deploytoazure.svg?sanitze=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fglennmusa%2Fmissionlz%2Fglennmusa%2Fbicep%2Fsrc%2Fbicep%2Fexamples%2FremoteAccess%2Fmain.json) +[![Deploy To Azure](../../../../docs/images/deploytoazure.svg?sanitze=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fglennmusa%2Fmissionlz%2Fglennmusa%2Fbicep%2Fsrc%2Fbicep%2Fexamples%2FremoteAccess%2Fmain.json) ### AzureUSGovernment -[![Deploy To Azure US Gov](../../docs/imgs/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fglennmusa%2Fmissionlz%2Fglennmusa%2Fbicep%2Fexamples%2FremoteAccess%2Fmain.json) +[![Deploy To Azure US Gov](../../../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fglennmusa%2Fmissionlz%2Fglennmusa%2Fbicep%2Fexamples%2FremoteAccess%2Fmain.json) diff --git a/src/bicep/ui/README.md b/src/bicep/ui/README.md index 940f1e39c..3fe7c3f0a 100644 --- a/src/bicep/ui/README.md +++ b/src/bicep/ui/README.md @@ -1,7 +1,7 @@ # MLZ UI -This folder contains a UI template to be executed against an mlz.json file generated from the bicep modules of MLZ. This file is intented for use as a quickstart only. +This folder contains a UI template to be executed against an mlz.json file generated from the bicep modules of MLZ. This file is intented for use as a quickstart only. -[![Deploy To Azure](../docs/imgs/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fui%2Fmlz-portal.json) +[![Deploy To Azure](../../../docs/images/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fui%2Fmlz-portal.json) -[![Deploy To Azure Gov](../docs/imgs/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fui%2Fmlz-portal.json) \ No newline at end of file +[![Deploy To Azure Gov](../../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fui%2Fmlz-portal.json) \ No newline at end of file diff --git a/src/build/README.md b/src/build/README.md deleted file mode 100644 index 977bfd679..000000000 --- a/src/build/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# build - -This folder contains scripts that would be used by some automation tool to apply/destroy terraform in the repo. - -This is a work in progress. Future work will be done to integrate this into a GitHub Actions workflow. - -## Why - -Provide an unattended way to ensure things are deployable in the repo. - -## What you need - -- Terraform CLI -- Azure CLI -- Deployed MLZ Config resources (Service Principal for deployment, Key Vault) -- A MLZ Config file -- A global.tfvars -- .tfvars for saca-hub, tier-0, tier-1, tier-2 - -## How - -See the root [README's "Configure the Terraform Backend"](../README.md#Configure-the-Terraform-Backend) on how to get the MLZ Config resources deployed and a MLZ Config file. - -Today, the global.tfvars file and the .tfvars for saca-hub, tier0-2, are well known and stored elsewhere. Reach out to the team if you need them. - -Then, to apply and destroy pass those files as arguments to the relevant script. - -There's an [optional argument to display terraform output](#Optionally-display-Terraform-output). - -```shell -usage() { - echo "apply_tf.sh: Automation that calls apply terraform given a MLZ configuration and some tfvars" - error_log "usage: apply_tf.sh " -} -``` - -```shell -# assuming src/scripts/config/create_required_resources.sh has been run before... -./apply_tf.sh \ - ./path-to/mlz.config \ - ./path-to/mlz.tfvars - y -``` - -```shell -# assuming src/scripts/config/create_required_resources.sh has been run before... -./destroy_tf.sh \ - ./path-to/mlz.config \ - ./path-to/mlz.tfvars \ - y -``` - -### Optionally display Terraform output - -There's an optional argument at the end to specify whether or not to display terraform's output. Set it to 'y' if you want to see things as they happen. - -By default, if you do not set this argument, terraform output will be sent to /dev/null (to support clean logs in a CI/CD environment) and your logs will look like: - -```plaintext -Applying saca-hub (1/5)... -Finished applying saca-hub! -Applying tier-0 (1/5)... -Finished applying tier-0! -Applying tier-1 (1/5)... -Finished applying tier-1! -Applying tier-2 (1/5)... -Finished applying tier-2! -``` - -## Gotchas - -There's wonky behavior with how Log Analytics Workspaces and Azure Monitor diagnostic log settings are deleted at the Azure Resource Manager level. - -For example, if you deployed your environment with Terraform, then deleted it with Azure CLI or the Portal, you can end up with orphan/ghost resources that will be deleted at some other unknown time. - -To ensure you're able to deploy on-top of existing resources over and over again, __use Terraform to apply and destroy your environment.__ diff --git a/src/build/apply_tf.sh b/src/build/apply_tf.sh deleted file mode 100755 index de1ec4d49..000000000 --- a/src/build/apply_tf.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC2154 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# -# Automation that calls apply terraform given a MLZ configuration - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "apply_tf.sh: Automation that calls apply terraform given a MLZ configuration and some tfvars" - error_log "usage: apply_tf.sh " -} - -if [[ "$#" -lt 2 ]]; then - usage - exit 1 -fi - -# take some valid, well known, mlz_config and tfvars as input -mlz_config=$(realpath "${1}") -mlz_tfvars=$(realpath "${2}") -display_tf_output=${3:-n} - -# reference paths -this_script_path=$(realpath "${BASH_SOURCE%/*}") -src_dir=$(dirname "${this_script_path}") -terraform_dir="${src_dir}/terraform/" -scripts_dir="${src_dir}/scripts/" - -# apply function -apply() { - sub_id=$1 - tf_dir=$2 - vars=$3 - - # generate config.vars based on MLZ Config and Terraform module - . "${scripts_dir}/config/generate_vars.sh" \ - "${mlz_config}" \ - "${sub_id}" \ - "${tf_dir}" - - # remove any existing terraform initialzation - rm -rf "${tf_dir}/.terraform" - - # copy input vars to temporary file - input_vars=$(realpath "${vars}") - temp_vars="temp_vars.tfvars" - rm -f "${temp_vars}" - touch "${temp_vars}" - cp "${input_vars}" "${temp_vars}" - - # remove any tfvars and subtitute it with input vars - tf_vars="${tf_dir}/$(basename "${vars}")" - rm -f "${tf_vars}" - touch "${tf_vars}" - cp "${temp_vars}" "${tf_vars}" - rm -f "${temp_vars}" - - # set the target subscription - az account set \ - --subscription "${sub_id}" \ - --output none - - # attempt to apply $max_attempts times before giving up - # (race conditions, transient errors etc.) - apply_success="false" - attempts=1 - max_attempts=5 - - apply_command="${scripts_dir}/terraform/apply_terraform.sh ${tf_dir} ${tf_vars} y" - destroy_command="${scripts_dir}/terraform/destroy_terraform.sh ${tf_dir} ${tf_vars} y" - - if [[ $display_tf_output == "n" ]]; then - apply_command+=" &>/dev/null" - destroy_command+=" &>/dev/null" - fi - - while [ $apply_success == "false" ] - do - echo "INFO: applying Terraform at ${tf_dir} (${attempts}/${max_attempts})..." - - if ! eval "$apply_command"; - then - # if we fail, run terraform destroy and try again - error_log "ERROR: failed to apply ${tf_dir} (${attempts}/${max_attempts}). Trying some manual clean-up and Terraform destroy..." - eval "$destroy_command" - - ((attempts++)) - - if [[ $attempts -gt $max_attempts ]]; then - error_log "ERROR: failed ${max_attempts} times to apply ${tf_dir}. Exiting." - exit 1 - fi - else - # if we succeed meet the base case - apply_success="true" - echo "INFO: finished applying ${tf_dir}!" - fi - done -} - -# source vars from mlz_config -. "${mlz_config}" - -# call apply() -apply "${mlz_saca_subid}" "${terraform_dir}/mlz" "${mlz_tfvars}" diff --git a/src/build/destroy_tf.sh b/src/build/destroy_tf.sh deleted file mode 100755 index e4fc29f42..000000000 --- a/src/build/destroy_tf.sh +++ /dev/null @@ -1,111 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC2154 -# SC1090: Can't follow non-constant source. These values come from an external file. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# -# Automation that calls destroy terraform given a MLZ configuration - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "destroy_tf.sh: Automation that calls destroy terraform given a MLZ configuration and some tfvars" - error_log "usage: destroy_tf.sh " -} - -if [[ "$#" -lt 2 ]]; then - usage - exit 1 -fi - -# take some valid, well known, mlz_config and tfvars as input -mlz_config=$(realpath "${1}") -mlz_tfvars=$(realpath "${2}") -display_tf_output=${3:-n} - -# reference paths -this_script_path=$(realpath "${BASH_SOURCE%/*}") -src_dir=$(dirname "${this_script_path}") -terraform_dir="${src_dir}/terraform/" -scripts_dir="${src_dir}/scripts/" - -# destroy function -destroy() { - sub_id=$1 - tf_dir=$2 - vars=$3 - - # generate config.vars based on MLZ Config and Terraform module - . "${scripts_dir}/config/generate_vars.sh" \ - "${mlz_config}" \ - "${sub_id}" \ - "${tf_dir}" - - # remove any existing terraform initialzation - rm -rf "${path}/.terraform" - - # copy input vars to temporary file - input_vars=$(realpath "${vars}") - temp_vars="temp_vars.tfvars" - rm -f "${temp_vars}" - touch "${temp_vars}" - cp "${input_vars}" "${temp_vars}" - - # remove any configuration tfvars and subtitute it with input vars - tf_vars="${tf_dir}/$(basename "${vars}")" - rm -f "${tf_vars}" - touch "${tf_vars}" - cp "${temp_vars}" "${tf_vars}" - rm -f "${temp_vars}" - - # set the target subscription - az account set \ - --subscription "${sub_id}" \ - --output none - - # attempt to apply $max_attempts times before giving up - # (race conditions, transient errors etc.) - destroy_success="false" - attempts=1 - max_attempts=5 - - destroy_command="${scripts_dir}/terraform/destroy_terraform.sh ${tf_dir} ${tf_vars} y" - - if [[ "$display_tf_output" == "n" ]]; then - destroy_command+=" &>/dev/null" - fi - - while [ $destroy_success == "false" ] - do - echo "INFO: destroying ${tf_dir} (${attempts}/${max_attempts})..." - - if ! eval "$destroy_command"; - then - # if we fail, run terraform destroy again until $max_attempts - error_log "ERROR: failed to destroy ${tf_dir} (${attempts}/${max_attempts})" - - ((attempts++)) - - if [[ $attempts -gt $max_attempts ]]; then - error_log "ERROR: failed ${max_attempts} times to destroy ${tf_dir}. Exiting." - exit 1 - fi - else - destroy_success="true" - echo "INFO: finished destroying ${tf_dir}!" - fi - done -} - -# source vars from mlz_config -. "${mlz_config}" - -# call destroy() -destroy "${mlz_saca_subid}" "${terraform_dir}/mlz" "${mlz_tfvars}" diff --git a/src/build/get_vars.sh b/src/build/get_vars.sh deleted file mode 100755 index c4b40f91e..000000000 --- a/src/build/get_vars.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# Get MLZ Configuration and Terraform Variables from a storage account - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "get_vars.sh: login using known Service Principal credentials into a given tenant" - error_log "usage: get_vars.sh.sh " -} - -if [[ "$#" -lt 3 ]]; then - usage - exit 1 -fi - -sa_name=$1 -sa_token=$2 -sa_container=$3 - -# create some place to hold the configuration and TF vars -rm -rf "vars" -mkdir "vars" - -# download everything in the container to that place -az storage blob download-batch \ - --account-name "${sa_name}" \ - --sas-token "${sa_token}" \ - --source "${sa_container}" \ - --pattern "*" \ - --destination "vars" \ - --output "none" \ - --only-show-errors - -# remove Windows EOL characters -for file in vars/*; do - sed -i 's/\r$//' "${file}" -done diff --git a/src/build/login_azcli.sh b/src/build/login_azcli.sh deleted file mode 100755 index d5cc606aa..000000000 --- a/src/build/login_azcli.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC2154 -# SC1090: Can't follow non-constant source. These values come from an external file. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# -# Get the tenant ID from some MLZ configuration file and login using known Service Principal credentials - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "login_azcli.sh: login using known Service Principal credentials into a given tenant" - error_log "usage: login_azcli.sh " -} - -if [[ "$#" -lt 3 ]]; then - usage - exit 1 -fi - -tenant_id=$1 -sp_id=$2 -sp_pw=$3 - -# login with known credentials -az login --service-principal \ - --user "${sp_id}" \ - --password="${sp_pw}" \ - --tenant "${tenant_id}" \ - --allow-no-subscriptions \ - --output json diff --git a/src/docs/command-line-deployment.md b/src/docs/command-line-deployment.md deleted file mode 100644 index 4e4f9d7bf..000000000 --- a/src/docs/command-line-deployment.md +++ /dev/null @@ -1,257 +0,0 @@ -# Command-Line Deployment - -The steps in this article assume the following pre-requisites for command-line deployments: - -* Follow the Mission LZ [Getting Started](https://github.com/Azure/missionlz/blob/main/src/docs/getting-started.md#pre-requisites) steps. -* **(Highly recommend)** Use the [the Mission LZ `.devcontainer`](https://github.com/Azure/missionlz/blob/main/src/docs/getting-started.md#use-the-development-container-for-command-line-deployments) provided in the Mission LZ project and perform the deployment steps below within this context. This container image provides a controlled environment that includes all the pre-requisite tools for Mission LZ deployments and should lead to an overall better user experience. - - > As an alternative, it is possible to deploy Mission LZ via BASH running from the local workstation, but requires the following additional requirements: - > - > * The current version of Azure CLI (try `az version` or see ) - > * Terraform CLI version > v0.13.4 (try `terraform -v` or see ) - -## Step-by-step - -1. Follow the [steps to open the `.devcontainer`](../../.devcontainer/README.md) as the recommended option (or start a local BASH shell with the additional requirements installed as the alternate option) - - > `vscode@missionlz-dev:/workspaces/missionlz$` is the root working directory for the BASH shell in the `.devcontainer` - -1. Log in using the Azure CLI - - ```BASH - az login - ``` - - > *(Optional)* If you needed to deploy into another cloud such as Azure Government, set the cloud name before logging in: - - ```BASH - az cloud set -n AzureUSGovernment - az login - ``` - -1. Quickstart - 1. [Deploy](#quickstart-deploy) - 1. [Clean](#quickstart-clean) - 1. [Arguments](#quickstart-arguments) -1. Advanced path (*optional*) - 1. [Setup Mission LZ Resources](#setup-mission-lz-resources) - 1. [Set Terraform Configuration Variables](#set-terraform-configuration-variables) - 1. [Deploy Terraform Configuration](#deploy-terraform-configuration) - 1. [Clean up Mission LZ Resources](#clean-up-mission-lz-resources) - -## Quickstart - -### Quickstart Deploy - -Interested in just getting started and seeing what this does? Login to Azure CLI and try this command to deploy Mission LZ with some default configuration: - -```bash -src/scripts/deploy.sh -s {your_subscription_id} -``` - -The `deploy.sh` command deploys all of the MLZ and Terraform resources, and by default, into a single subscription in Azure Commercial EastUS with a timestamped name. - -If you needed to deploy into another cloud, say Azure Government, you would [override the default region](https://azure.microsoft.com/en-us/global-infrastructure/geographies/#overview) and [default azurerm terraform environment](https://www.terraform.io/docs/language/settings/backends/azurerm.html#environment) like: - -```bash -az cloud set -n AzureUSGovernment -az login -src/scripts/deploy.sh -s {your_subscription_id} \ - --location usgovvirginia \ - --tf-environment usgovernment -``` - -For a complete list of arguments see [Quickstart Arguments](#Quickstart-Arguments). - -### Quickstart Clean - -Once the deployment is complete, you'll be presented with a command that will clean up all of the resources that were deployed: - -```plaintext -INFO: Complete! -INFO: All finished? Want to clean up? -INFO: Try this command: -INFO: src/scripts/clean.sh -z mymlzenv -``` - -Which you can then execute like: - -```bash -src/scripts/clean.sh -z mymlzenv -``` - -The `clean.sh` command will call Terraform destroy for all the resources Terraform created and delete the MLZ resources and service principal. - -### Quickstart Arguments - -If you don't wish to use those defaults, you can customize this command to target multiple subscriptions, different regions, and using different Terraform environments and azurerm configurations with the full set of arguments: - -```plaintext -deploy.sh: create all the configuration and deploy Terraform resources with minimal input - argument description - --subscription-id -s Subscription ID for MissionLZ resources - --location -l [OPTIONAL] The location that you're deploying to (defaults to 'eastus') - --tf-environment -e [OPTIONAL] Terraform azurerm environment (defaults to 'public') see: https://www.terraform.io/docs/language/settings/backends/azurerm.html#environment - --mlz-env-name -z [OPTIONAL] Unique name for MLZ environment (defaults to 'mlz' + UNIX timestamp) - --hub-sub-id -u [OPTIONAL] subscription ID for the hub network and resources (defaults to the value provided for -s --subscription-id) - --tier0-sub-id -0 [OPTIONAL] subscription ID for tier 0 network and resources (defaults to the value provided for -s --subscription-id) - --tier1-sub-id -1 [OPTIONAL] subscription ID for tier 1 network and resources (defaults to the value provided for -s --subscription-id) - --tier2-sub-id -2 [OPTIONAL] subscription ID for tier 2 network and resources (defaults to the value provided for -s --subscription-id) - --tier3-sub-id -3 [OPTIONAL] subscription ID for tier 3 network and resources (defaults to the value provided for -s --subscription-id), input is used in conjunction with deploy_t3.sh - --write-output -w [OPTIONAL] Tier 3 Deployment requires Terraform output, use this flag to write terraform output - --no-bastion [OPTIONAL] when present, do not create a Bastion Host and Jumpbox VM - --no-sentinel [OPTIONAL] when present, do not create an Azure Sentinel solution - --no-service-principal [OPTIONAL] when present, do not create an Azure Service Principal, instead use the credentials in the environment variables '$ARM_CLIENT_ID' and '$ARM_CLIENT_SECRET' - --help -h Print this message -``` - -For example, if I wanted to deploy into four subscriptions (one for each network) and provide my own name for created resources, I could do so like: - -```bash -src/scripts/deploy.sh -s {my_mlz_configuration_subscription_id} \ - -u {my_hub_network_subscription_id} \ - -0 {my_identity_network_subscription_id} \ - -1 {my_operations_network_subscription_id} \ - -2 {my_shared_services_network_subscription_id} \ - -z {my_mlz_environment_name} -``` - -Need further customization? The rest of this documentation covers in detail how to customize this deployment to your needs. - -#### Using your own Service Principal - -Were you provided a subscription(s) and credentials to use, or do you already have an identity you want to use to deploy and manage Terraform with? - -By default, Mission LZ will attempt to create a Service Principal to deploy and manage Terraform on your behalf. - -> **NOTE:** If you are providing your own Service Principal, that Service Principal must have at minimum a 'Contributor' role. - -To use your own Service Principal credentials, first, set ARM_CLIENT_ID and ARM_CLIENT_SECRET environment variables: - -```bash -export ARM_CLIENT_ID="{YOUR_SERVICE_PRINCIPAL_CLIENT_ID}" -export ARM_CLIENT_SECRET="{YOUR_SERVICE_PRINCIPAL_CLIENT_SECRET}" -``` - -Then, specify the `--no-service-principal` flag when running `deploy.sh`: - -```bash -deploy.sh --subscription-id "{YOUR_SUBSCRIPTION_ID}" --no-service-principal -``` - -If you use `--no-service-principal` without `ARM_CLIENT_ID` and `ARM_CLIENT_SECRET` set in your environment, you will recieve an error: - -```plaintext -ERROR: When specifying --no-service-principal, these environment variables are mandatory: ARM_CLIENT_ID, ARM_CLIENT_SECRET -INFO: You can set these environment variables with 'export ARM_CLIENT_ID="YOUR_CLIENT_ID"' and 'export ARM_CLIENT_SECRET="YOUR_CLIENT_SECRET"' -``` - -If you use `--no-service-principal` but the Service Principal you supply with `ARM_CLIENT_ID` does not have "Contributor" RBAC permissions for the subscriptions you wish to deploy into, you will receive an error: - -```plaintext: -ERROR: service principal with client ID AAAAAAAA-BBBB-CCCC-DDDDDDDDDD does not have 'Contributor' or 'Owner' roles for subscription 00000000-1111-2222-333333333333! -INFO: at minimum, the 'Contributor' role is required to manage resources via Terraform. -INFO: to set this role for this subscription, a user with the 'Owner' role can try this command: -INFO: az role assignment create --assignee-object-id EEEEEEEE-FFFF-GGGG-HHHHHHHHHH --role "Contributor" --scope "/subscriptions/00000000-1111-2222-333333333333" -ERROR: please assign the 'Contributor' role to this subscription and try again. -``` - -## Setup Mission LZ Resources - -Deployment of MLZ happens through use of a single Service Principal whose credentials are stored in a central "config" Key Vault. - -MLZ uses this Service Principal and its credentials from the Key Vault to deploy the resources described in Terraform at `src/terraform` and stores Terraform state for each component into separate storage accounts. - -1. First, create the MLZ Configuration file `mlz.config` file using the `mlz.config.sample` as a template. - - The information in the `mlz.config` file, will be used by `create_required_resources.sh` to create and populate a `config.vars` file for each tier and saved inside the deployment folder for each tier (example: \src\core\tier-0\config.vars). - - For example: - - ```plaintext - mlz_env_name="{MLZ_ENV_NAME}" - mlz_config_location="{MLZ_CONFIG_LOCATION}" - ``` - - Would become: - - ```plaintext - mlz_env_name="dev" - mlz_config_location="eastus" - ``` - -1. Then, run `create_required_resources.sh` at [src/scripts/config/create_required_resources.sh](/src/scripts/config/create_required_resources.sh) to create: - - * A Service Principal to execute terraform commands - * A config Resource Group to store the Key Vault - * A config Key Vault to store the Service Principal's client ID and client secret - * A terraform state Resource Groups for each tier - * A terraform state Storage Account for each tier - * A terraform state Storage Container for each tier - * Backend config file (config.vars) for the deployment - - ```bash - src/scripts/config/create_required_resources.sh src/mlz.config - ``` - -## Set Terraform Configuration Variables - -First, clone the *.tfvars.sample file ([src/terraform/mlz/mlz.tfvars.sample](/src/terraform/mlz/mlz.tfvars.sample)) and substitute placeholders marked by curly braces "{" and "}" with the values of your choosing. - -For example: - -```plaintext -location="{MLZ_LOCATION}" # the templated value in src/terraform/mlz/mlz.tfvars.sample -``` - -Would become: - -```plaintext -location="eastus" # the value used by Terraform in src/terraform/mlz/mlz.tfvars.sample -``` - -## Deploy Terraform Configuration - -You can use `apply_terraform.sh` at [src/scripts/terraform/apply_terraform.sh](/src/scripts/terraform/apply_terraform.sh) to both initialize Terraform and apply a Terraform configuration based on the backend environment variables and Terraform variables you've setup in previous steps. - -The script `destroy_terraform.sh` at [src/scripts/terraform/destroy_terraform.sh](/src/scripts/terraform/destroy_terraform.sh) is helpful during testing. This script is exactly like the -`apply_terraform.sh` except it destroys resources defined in the target state file - -`apply_terraform.sh` and `destroy_terraform.sh` take two arguments: - - 1. The directory that contains the main.tf to apply - 1. The path to the .tfvars variables file to apply - -For example, run the following command to apply the MLZ terraform configuration repository. - -```bash - src/scripts/terraform/apply_terraform.sh \ - src/terraform/mlz \ - src/terraform/mlz.tfvars -``` -Use `init_terraform.sh` at [src/scripts/terraform/init_terraform.sh](/src/scripts/terraform/init_terraform.sh) to perform just an initialization of the Terraform environment: - -```bash -src/scripts/terraform/init_terraform.sh \ - src/terraform/mlz -``` - -## Clean up Mission LZ Resources - -After you've deployed your environments with Terraform, it is no longer mandatory to keep Mission LZ Resources like the Service Principal, Key Vault, nor the Terraform state files (though you can re-use these resources and stored Terraform state for updating the deployed environment incrementally using `terraform apply` or destroying them from terraform with `terraform destroy`). - -If you no longer have the need for a Service Principal with Contributor rights, the Key Vault that stores this Service Principal's credentials, nor the Terraform state, you can clean up these Mission LZ Resources with the [config_clean.sh](/src/scripts/config/config_clean.sh) script passing in the MLZ Configuration file you created earlier: - -```bash -src/scripts/config/config_clean.sh src/mlz.config -``` - -## Terraform Providers - -The development container definition downloads the required Terraform plugin providers during the container build so that the container can be transported to an air-gapped network for use. The container also sets the `TF_PLUGIN_CACHE_DIR` environment variable, which Terraform uses as the search location for locally installed providers. If you are not using the container to deploy or if the `TF_PLUGIN_CACHE_DIR` environment variable is not set, Terraform will automatically attempt to download the provider from the internet when you execute the `terraform init` command. - -See the development container [README](/.devcontainer/README.md) for more details on building and running the container. - -## Helpful Links - -For more endpoint mappings between AzureCloud and AzureUsGovernment: diff --git a/src/docs/terraform/deployment.md b/src/docs/terraform/deployment.md deleted file mode 100644 index 4fcb86035..000000000 --- a/src/docs/terraform/deployment.md +++ /dev/null @@ -1,179 +0,0 @@ -# Terraform Deployment - -Mission LZ also deploys the Hub and Spoke network architecture using [Terraform](https://www.terraform.io/). - -To get started with Terraform on Azure check out their useful tutorial: - -Once you're comfortable with Terraform, ensure you have the Prerequisites below and follow the instructions to deploy and clean-up Mission LZ. - -## Prerequisistes - -* Current version of the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) -* The version of the [Terraform CLI](https://www.terraform.io/downloads.html) described in the [.devcontainer Dockerfile](../../../.devcontainer/Dockerfile) -* An Azure Subscription where you or an identity you manage has `Owner` [RBAC permissions](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner) - -## Login to Azure CLI - -1. Log in using the Azure CLI - - ```BASH - az login - ``` - - > *(Optional)* If you needed to deploy into another cloud such as Azure Government, set the cloud name before logging in: - - ```BASH - az cloud set -n AzureUSGovernment - az login - ``` - -1. (OPTIONAL) Deploying to a Cloud other than Azure Commercial? This requires updating the `azurerm` provider block `environment` and `metadata_host` values. Checkout the [Deploying to Other Clouds](#Deploying-to-Other-Clouds) documentation. - -1. (OPTIONAL) Deploying with a Service Principal? This requires updating the `azurerm` provider block. Check out the [Deploying with a Service Principal](#Deploying-with-a-Service-Principal) documentation. - -## Terraform init - -Before provisioning any Azure resources with Terraform you must initialize a working directory. - -Here's the docs on `terraform init`: - -1. Navigate to the directory in the repository that contains the MissionLZ Terraform module: - - ```bash - cd src/terraform/mlz - ``` - -1. Execute `terraform init` - - ```bash - terraform init - ``` - -## Terrafrom apply - -After intializing the directory, use `terraform apply` to provision the resources described in `mlz/main.tf` and its referenced modules at `mlz/modules/*`. - -Here's the docs on `terraform apply`: - -When you run `terraform apply`, by default, Terraform will inspect the state of your environment to determine what resource creation, modification, or deletion needs to occur as if you invoked a `terraform plan` and then prompt you for your approval before taking action. - -Here's the docs on `terraform plan`: - -1. From the directory in which you executed `terraform init` execute `terraform apply`: - - ```bash - terraform apply - ``` - -1. When prompted for your approval to create, modify, or destroy resources, supply `yes`: - - ```plaintext - Do you want to perform these actions? - Terraform will perform the actions described above. - Only 'yes' will be accepted to approve. - - Enter a value: yes - ``` - -This command will deploy all of the resources that make up Mission LZ and could take up to 45 minutes. - -## Terraform destroy - -Once you're happy with the deployment output and want to modify Mission LZ or just want to tear it down to save on costs, you can use `terraform destroy`. - -Here's the docs on `terraform destroy`: - -1. From the directoy in which you executed `terraform init` and `terraform apply` execute `terraform destroy`: - - ```bash - terraform destroy - ``` - -This command will attempt to remove all the resources that were deployed by `terraform apply` and could take up to 45 minutes. - -## Deploying with a Service Principal - -This is not required, in fact, the current Terraform modules are written as if you're executing them as a user. - -But, if you're using a Service Principal to deploy Azure resources with Terraform check out this doc: - -Using a Service Principal will require updating the resource providers for `mlz/main.tf`, also described in that doc: : - -```terraform -variable "client_secret" { -} - -terraform { - required_providers { - azurerm = { - ... - } - } -} - -provider "azurerm" { - features {} - - subscription_id = "00000000-0000-0000-0000-000000000000" - client_id = "00000000-0000-0000-0000-000000000000" - client_secret = var.client_secret - tenant_id = "00000000-0000-0000-0000-000000000000" -} -``` - -## Terraform Providers - -The development container definition downloads the required Terraform plugin providers during the container build so that the container can be transported to an air-gapped network for use. The container also sets the `TF_PLUGIN_CACHE_DIR` environment variable, which Terraform uses as the search location for locally installed providers. If you are not using the container to deploy or if the `TF_PLUGIN_CACHE_DIR` environment variable is not set, Terraform will automatically attempt to download the provider from the internet when you execute the `terraform init` command. - -See the development container [README](/.devcontainer/README.md) for more details on building and running the container. - -## Terraform Backends - -The default templates write a state file directly to disk locally to where you are executing terraform from. If you wish to change the output directory you can set the path directly in the terraform backend block located in the main.tf file via the path variable in the backend configuration block. - -```terraform -terraform { - backend "local" { - path = "relative/path/to/terraform.tfstate" - } - - required_version = ">= 1.0.3" - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = "= 2.71.0" - } - random = { - source = "hashicorp/random" - version = "= 3.1.0" - } - time = { - source = "hashicorp/time" - version = "0.7.2" - } - } -} -``` - -To find more information about setting the backend see [Local Backend](https://www.terraform.io/docs/language/settings/backends/local.html), if you wish to AzureRM backend please see [AzureRM Backend](https://www.terraform.io/docs/language/settings/backends/azurerm.html) - -## Deploying to Other Clouds - -The `azurerm` Terraform provider provides a mechanism for changing the Azure cloud in which to deploy Terraform modules. - -When specifying your provider, pass in the correct value for `environment` and `metadata_host` for the cloud you're targeting: - -```terraform -provider "azurerm" { - features {} - - environment = var.tf_environment # e.g. 'public' or 'usgovernment' - metadata_host = var.mlz_metadatahost # e.g. 'management.azure.com' or 'management.usgovcloudapi.net' -} -``` - -For the supported `environment` values, see this doc: - -For the supported `metadata_host` values, see this doc: - -For more endpoint mappings between AzureCloud and AzureUsGovernment: diff --git a/src/docs/workload-deployment.md b/src/docs/workload-deployment.md deleted file mode 100644 index 5d737ce02..000000000 --- a/src/docs/workload-deployment.md +++ /dev/null @@ -1,92 +0,0 @@ -# Workload Deployment (Tier 3) - -Mission LZ supports deploying multiple workload tiers that are connected to the hub. We call these tier 3s, or T3s, for convenience. Each tier 3 is intended to support a single workload or single team that needs isolation from the other teams and network connectivity via the hub. - -## Command Line Step-by-step - -1. Log in using the Azure CLI - - ```BASH - az login - ``` - -1. [Quickstart](#Quickstart) -1. [Advanced Deployment](#Advanced-Deployment) - -### Quickstart - -#### Quickstart Deploy - -In tandem with the quickstart found in [QuickStart Deploying MLZ](command-line-deployment.md#Quickstart) you can quickly get up and running and deploy a single workload instance to your configuration. - -> NOTE: This should be run using the `--tier3-sub-id` flag and `--write-output` flag if you wish to specify the subscription ID for the tier 3. Be sure to use the "-w" flag to ensure that the output required for deployment is generated. - -After you have deployed the core MLZ resources, you can use this command (the generated-configuration item artifacts come from the base deployment and can be reused), substituting `{mlz_env_name}` with the appropriate value. - -```bash -./deploy_t3.sh ../generated-configurations/{mlz_env_name}.mlzconfig ../generated-configurations/{mlz_env_name}.tfvars ../generated-configurations/output.tfvars.json y -``` - -> **CONSIDERATIONS** This script should not be run unless the instructions for setting up the core MLZ deployment have been followed. It will deploy a single workload with default configurations for testing/demonstration purposes. - -### Advanced Deployment - -A production usage of tier 3 workloads will require a more advanced setup than allowed through a quick start. In order to perform these deployments you will have to modify three configuration files, and use the deployment script with the resulting files. - -> **NOTE** These steps will need to be repeated for each workload tier you wish to add. - - -> **NOTE** Like the other Mission LZ tiers, each tier 3 workload can be deployed into its own subscription or they can be deployed into a single subscription. For production deployments we recommend that each tier 3 is deployed into its own subscription to simplify managing security and access. - - -1. First, modify the MLZ Configuration file `mlz.config` file using the `mlz.config.sample` as a template, this file should be a copy of the file used to deploy MLZ. You will need to modify the following to include the actual subscription number: - - ```plaintext - mlz_tier3_subid="{MLZ_TIER3_SUBID}" # Optional if not currently deploying a tier 3 - ``` - -2. You will need to source the global terraform configuration you used for your primarily deployment. This is typically located at [src/terraform/mlz/mlz.tfvars.sample](/src/terraform/mlz/mlz.tfvars.sample)), if you used quickstart you may find it in the src/generated-configurations directory. Make note of the location. To specify the changes to the custom Tier 3 you will be making, scroll to the tier 3 variables located in the file and change the values to what you need. - - > **NOTE** If you will be deploying multiple T3's the subnet network addresses and subscriptions will be the most important values that need your attention as they will conflict otherwise. - -3. The deployment of a Tier 3 relies on an already completed deployment of MLZ and a resulting output json file containing 3 variables: - - ```json - { - "firewall_private_ip": { - "sensitive": false, - "type": "string", - "value": "{value}" - }, - "laws_name": { - "sensitive": false, - "type": "string", - "value": "{value}" - }, - "laws_rgname": { - "sensitive": false, - "type": "string", - "value": "{value}" - } - } - ``` - - ```plaintext - Values: - laws_name: The Log Analytic workspace name - laws_rgname: The resource group you've deployed LAWS to. - firewall_private_ip: The Ip address of the firewall that the tier 3 will be connecting to. - ``` - - You can manually provide these in an output.tfvars.json file if needed. - -4. Once you have collected all of these artifacts you can deploy your workload tier with. The folder names are examples, these files can be placed anywhere. - - ```bash - src/scripts/deploy_t3.sh \ - src/mlz.config - src/terraform/output.tfvars.json - src/terraform/tier-3/tier-3.tfvars - ``` - -After completing these steps, the workload tier will be deployed and you can add whatever services you need to the tier. diff --git a/src/mlz.config.sample b/src/mlz.config.sample deleted file mode 100644 index 0c233d802..000000000 --- a/src/mlz.config.sample +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# You can generate one of these with generate_config_file.sh -tf_environment="{TF_ENVIRONMENT}" # https://www.terraform.io/docs/language/settings/backends/azurerm.html#environment -mlz_env_name="{MLZ_ENV_NAME}" # Unique name for MLZ environment -mlz_config_subid="{MLZ_CONFIG_SUBID}" # Subscription ID for MissionLZ configuration resources -mlz_config_location="{MLZ_CONFIG_LOCATION}" # Azure Region for deploying Mission LZ configuration resources -mlz_tier0_subid="{MLZ_TIER0_SUBID}" -mlz_tier1_subid="{MLZ_TIER1_SUBID}" -mlz_tier2_subid="{MLZ_TIER2_SUBID}" -mlz_tier3_subid="{MLZ_TIER3_SUBID}" # Optional if not currently deploying a tier 3 -mlz_saca_subid="{MLZ_SACA_SUBID}" -mlz_metadatahost="{MLZ_METADATAHOST}" # e.g. https://management.azure.com/ -mlz_acrLoginServerEndpoint="{MLZ_ACRLOGINSERVERENDPOINT}" # e.g. .azurecr.io -mlz_keyvaultDns="{MLZ_KEYVAULTDNS}" # e.g. .vault.azure.net -mlz_cloudname="{MLZ_CLOUDNAME}" # e.g. AzureCloud -mlz_activeDirectory="{MLZ_ACTIVEDIRECTORY}" # e.g. https://login.microsoftonline.com diff --git a/src/scripts/clean.sh b/src/scripts/clean.sh deleted file mode 100755 index a66663173..000000000 --- a/src/scripts/clean.sh +++ /dev/null @@ -1,147 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=1090,1091,2154 -# -# remove resources deployed by deploy.sh by mlz env name - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -show_help() { - print_formatted() { - long_name=$1 - char_name=$2 - desc=$3 - printf "%20s %2s %s \n" "$long_name" "$char_name" "$desc" - } - print_formatted "argument" "" "description" - print_formatted "--mlz-env-name" "-z" "Unique name for MLZ environment" - print_formatted "--help" "-h" "Print this message" -} - -usage() { - echo "clean.sh: remove resources deployed by deploy.sh by mlz env name" - show_help -} - -check_dependencies() { - "${this_script_path}/util/checkforazcli.sh" - "${this_script_path}/util/checkforterraform.sh" -} - -inspect_user_input() { - # check mandatory parameters - # shellcheck disable=1083 - for i in { $mlz_env_name } - do - if [[ $i == "notset" ]]; then - error_log "ERROR: Missing required arguments. These arguments are mandatory: -z" - usage - exit 1 - fi - done -} - -import_configuration() { - . "${mlz_config_file_path}" - . "${this_script_path}/config/generate_names.sh" "${mlz_config_file_path}" -} - -login_azcli() { - echo "INFO: setting current subscription to ${mlz_config_subid}..." - az account set \ - --subscription "${mlz_config_subid}" \ - --only-show-errors \ - --output none -} - -destroy_terraform() { - echo "INFO: destroying Terraform using ${mlz_config_file_path} and ${tfvars_file_path}..." - "${this_script_path}/../build/destroy_tf.sh" \ - "${mlz_config_file_path}" \ - "${tfvars_file_path}" \ - "y" -} - -notify_failed_to_destroy_terraform() { - error_log "ERROR: failed to destroy Terraform deployment..." - echo "INFO: continuing to destroy MLZ Configuration resources..." -} - -destroy_mlz() { - echo "INFO: cleaning up MLZ Configuration resources with tag 'DeploymentName=${mlz_env_name}'..." - - # clean up MLZ config resources - . "${this_script_path}/config/config_clean.sh" "${mlz_config_file_path}" - - delete_files_in_directory_by_name() { - directory_to_search=$1 - file_name_to_match=$2 - - matches=$(find "$directory_to_search" -type f -name "$file_name_to_match") - - for match in $matches - do - echo "INFO: deleting $match ..." - rm -f "$match" - done - } - - # clean up files - delete_files_in_directory_by_name "${src_path}" "${tfvars_file_name}" - echo "INFO: deleting ${configuration_output_path}/${mlz_env_name}.mlzconfig ..." - rm -rf "${configuration_output_path}/${mlz_env_name}.mlzconfig" - echo "INFO: deleting ${tf_mlz_main_path}/config.vars ..." - rm -rf "${tf_mlz_main_path}/config.vars" - echo "INFO: deleting terraform.lock file and .terraform folder ..." - rm -rf "${tf_mlz_main_path}/.terraform.lock.hcl" - rm -rf "${tf_mlz_main_path}/.terraform" -} - -########## -# main -########## - -this_script_path=$(realpath "${BASH_SOURCE%/*}") -src_path="$(realpath "${this_script_path}/../")" -configuration_output_path=$(realpath "${this_script_path}/../generated-configurations") - -mlz_env_name="notset" - -while [ $# -gt 0 ] ; do - case $1 in - -z | --mlz-env-name) - shift - mlz_env_name="$1" ;; - -h | --help) - show_help - exit 0 ;; - *) - error_log "ERROR: Unexpected argument: ${1}" - usage && exit 1 ;; - esac - shift -done - -# validate requirements -inspect_user_input -check_dependencies - -# set paths -mlz_config_file_path="${configuration_output_path}/${mlz_env_name}.mlzconfig" -tfvars_file_name="${mlz_env_name}.tfvars" -tfvars_file_path="${configuration_output_path}/${tfvars_file_name}" -tf_mlz_main_path=$(realpath "${configuration_output_path}/../terraform/mlz") - -# teardown resources -# if terraform destroy fails, notify and continue to destroy mlz -import_configuration -login_azcli -destroy_terraform || notify_failed_to_destroy_terraform -destroy_mlz diff --git a/src/scripts/config/append_prereq_endpoints.sh b/src/scripts/config/append_prereq_endpoints.sh deleted file mode 100755 index 7a5dd062a..000000000 --- a/src/scripts/config/append_prereq_endpoints.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# append pre-req endpoints to an MLZ config file - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "append_prereq_endpoints.sh: append pre-req endpoints to an MLZ config file" - error_log "usage: append_prereq_endpoints.sh " -} - -if [[ "$#" -lt 1 ]]; then - usage - exit 1 -fi - -file_to_append=$1 - -# create a dictionary of mlz_* values we want from an `az cloud show` result -declare -A mlz_az_cloud_keys -mlz_az_cloud_keys['mlz_metadatahost']='endpoints.resourceManager' -mlz_az_cloud_keys['mlz_acrLoginServerEndpoint']='suffixes.acrLoginServerEndpoint' -mlz_az_cloud_keys['mlz_keyvaultDns']='suffixes.keyvaultDns' -mlz_az_cloud_keys['mlz_cloudname']='name' -mlz_az_cloud_keys['mlz_activeDirectory']='endpoints.activeDirectory' - -# if it's the metadatahost, strip it of URI components -# in some clouds, Terraform allows only the domain name -format_if_metadatahost() { - local mlz_key_name=$1 - local cloud_key_value=$2 - - if [[ $mlz_key_name != "mlz_metadatahost" ]]; then - echo "$cloud_key_value" - else - - # 1) awk -F/ '{print $3}' - # - # -F/ is "using the character / as a field separator" - # - # '{print $3}' is "print me the third field" - # - # 2) for example on https://management.azure.com/ - # - # $1 $2 $3 $4 - # https: / / management.azure.com / - # - # $1 is https: - # $2 is - # $3 is management.azure.com - # $4 is - - echo "$cloud_key_value" | awk -F/ '{print $3}' - fi -} - -# since we cannot guarantee the results of `az cloud show` for each value we require, -# query for values individually and skip printing any empty results -append_cloud_value() { - local mlz_key_name=$1 - local cloud_key_name=$2 - local file=$3 - - local cloud_key_value - cloud_key_value=$(az cloud show --query "${cloud_key_name}" --output tsv) - - if [[ $cloud_key_value ]]; then - cloud_key_value=$(format_if_metadatahost "$mlz_key_name" "$cloud_key_value") - printf "%s=%s\n" "${mlz_key_name}" "${cloud_key_value}" >> "${file}" - else - echo "INFO: Oops! Did not find a value for 'az cloud show --query ${cloud_key_name}'..." - echo "INFO: There will not be a value for ${mlz_key_name} on the MLZ config file at ${file}..." - fi -} - -# for each member of the dictionary, write "key=$(az cloud show...)" to a file -for mlz_key_name in "${!mlz_az_cloud_keys[@]}"; do - append_cloud_value "$mlz_key_name" "${mlz_az_cloud_keys[$mlz_key_name]}" "${file_to_append}" -done diff --git a/src/scripts/config/config_clean.sh b/src/scripts/config/config_clean.sh deleted file mode 100755 index c598be2d6..000000000 --- a/src/scripts/config/config_clean.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=1090,2154 -# -# remove mlz configuration resources from an mlz configuration file - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "config_clean.sh: remove mlz configuration resources from an mlz configuration file" - error_log "usage: config_clean.sh " -} - -if [[ "$#" -lt 1 ]]; then - usage - exit 1 -fi - -mlz_config_file=$(realpath "${1}") -this_script_path=$(realpath "${BASH_SOURCE%/*}") - -# check for dependencies -"${this_script_path}/../util/checkforazcli.sh" -"${this_script_path}/../util/checkforterraform.sh" -"${this_script_path}/../util/checkforfile.sh" \ - "${mlz_config_file}" \ - "The configuration file ${mlz_config_file} is empty or does not exist." - -# generate names from config -. "${mlz_config_file}" -. "${this_script_path}/generate_names.sh" "${mlz_config_file}" - -# Create array of unique subscription IDs. The 'sed' command below search thru the source -# variables file looking for all lines that do not have a '#' in the line. If a line with -# a '#' is found, the '#' and ever character after it in the line is ignored. The output -# of what remains from the sed command is then piped to grep to find the words that match -# the pattern. These words are what make up the 'mlz_subs' array. -mlz_sub_pattern="mlz_.*._subid" -mlz_subs=$(< "${mlz_config_file}" sed 's:#.*$::g' | grep -w "${mlz_sub_pattern}") -subs=() - -for mlz_sub in $mlz_subs -do - mlz_sub_id=$(echo "${mlz_sub#*=}" | tr -d '"') - if [[ ! "${subs[*]}" =~ ${mlz_sub_id} ]];then - subs+=("${mlz_sub_id}") - fi -done - -# delete resource groups where deploymentname is mlz_env_name in each subscription -for sub in "${subs[@]}"; -do - rgs_to_delete=$(az group list --subscription "${sub}" --tag "DeploymentName=${mlz_config_tag}" --query [].name -o tsv) - for rg in $rgs_to_delete; - do - echo "INFO: deleting ${rg}..." - - az group delete \ - --subscription "${sub}" \ - --name "${rg}" \ - --yes \ - --only-show-errors \ - --output none - done -done - -echo "INFO: querying for any created service principal with name ${mlz_sp_name}..." -sp_id=$(az ad sp list --display-name "http://${mlz_sp_name}" --query [0].appId --output tsv) - -if [[ $sp_id ]]; then - echo "INFO: deleting service principal ${mlz_sp_name}..." - az ad sp delete --id "${sp_id}" -fi - -echo "INFO: purging key vault ${mlz_kv_name}..." -az keyvault purge \ - --name "${mlz_kv_name}" \ - --subscription "${mlz_config_subid}" - -echo "INFO: Complete! MLZ Configuration resources for ${mlz_env_name} deleted!" \ No newline at end of file diff --git a/src/scripts/config/config_validate.sh b/src/scripts/config/config_validate.sh deleted file mode 100755 index 3c32f60de..000000000 --- a/src/scripts/config/config_validate.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC1091,SC2154 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC1091: Not following. Shellcheck can't follow non-constant source. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# -# Validates the existence of resources required to run Terraform init and apply scripts - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "config_validate.sh : Validates the existence of resources required to run Terraform init and apply scripts" - error_log "usage: config_validate.sh " -} - -if [[ "$#" -lt 1 ]]; then - usage - exit 1 -fi - -tf_dir=$(realpath "${1}") -config_vars="${tf_dir}/config.vars" - -# Validate resources -if [[ -s "${config_vars}" ]]; then - source "${tf_dir}/config.vars" -else - echo "The variable file ${config_vars} is either empty or does not exist. Please verify file and re-run script" - exit 1 -fi - -# Validate Terraform Backend resource group -rg_exists="az group show \ - --name ${tf_rg_name} \ - --subscription ${mlz_config_subid}" - -if ! $rg_exists &> /dev/null; then - echo "Terraform State Resource Group '${tf_rg_name}' does not exist...validate config.vars file and re-run script" - exit 1 -fi - -# Validate config key vault -kv_exists="az keyvault show \ - --name ${mlz_kv_name} \ - --subscription ${mlz_config_subid}" - -if ! $kv_exists &> /dev/null; then - echo "Key Vault to source client_id for deployment '${mlz_kv_name}' does not exist...validate config.vars file and re-run script" - exit 1 -fi diff --git a/src/scripts/config/create_mlz_config_resources.sh b/src/scripts/config/create_mlz_config_resources.sh deleted file mode 100755 index d169a5ce1..000000000 --- a/src/scripts/config/create_mlz_config_resources.sh +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC1091,SC2154,SC2207 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# -# Create MLZ backend config resources - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "create_mlz_config_resources.sh: Create MLZ config resources" - error_log "usage: create_mlz_config_resources.sh " -} - -if [[ "$#" -lt 1 ]]; then - usage - exit 1 -fi - -mlz_config=$(realpath "${1}") -create_service_principal=${2:-true} - -this_script_path=$(realpath "${BASH_SOURCE%/*}") - -# Source variables -. "${mlz_config}" - -# Create array of unique subscription IDs. The 'sed' command below search thru the source -# variables file looking for all lines that do not have a '#' in the line. If a line with -# a '#' is found, the '#' and ever character after it in the line is ignored. The output -# of what remains from the sed command is then piped to grep to find the words that match -# the pattern. These words are what make up the 'mlz_subs' array. -mlz_sub_pattern="mlz_.*._subid" -mlz_subs=$(< "${mlz_config}" sed 's:#.*$::g' | grep -w "${mlz_sub_pattern}") -subs=() - -# generate MLZ configuration names -. "${BASH_SOURCE%/*}/generate_names.sh" "${mlz_config}" - -echo "INFO: creating MLZ resources for ${mlz_env_name}..." - -for mlz_sub in $mlz_subs -do - # Grab value of variable - mlz_sub_id=$(echo "${mlz_sub#*=}" | tr -d '"') - if [[ ! "${subs[*]}" =~ ${mlz_sub_id} ]];then - subs+=("${mlz_sub_id}") - fi -done - -# accomodate for transient behavior where Service Principal is created -# but an immediate query for it will fail -# and attempt for max_wait_in_seconds before giving up. -wait_for_sp_creation() { - sp_name=$1 - sp_query="az ad sp show --id ${sp_name}" - - sleep_time_in_seconds=10 - max_wait_in_seconds=180 - max_retries=$((max_wait_in_seconds/sleep_time_in_seconds)) - - count=1 - - while ! $sp_query &> /dev/null - do - echo "INFO: waiting for service principal ${sp_name} to come back from query '${sp_query}' (${count}/${max_retries})..." - echo "INFO: trying again in ${sleep_time_in_seconds} seconds..." - sleep "${sleep_time_in_seconds}" - - if [[ ${count} -eq max_retries ]]; then - error_log "ERROR: unable to retrieve the service principal ${sp_name} from query '${sp_query}' in ${max_wait_in_seconds} seconds. Investigate and re-run script." - exit 1 - fi - - count=$((count +1)) - done -} - -# accomodate for transient behavior where Service Principal is created -# but an immediate query for its properties will fail -# and attempt for max_wait_in_seconds before giving up. -wait_for_sp_property() { - sp_name=$1 - sp_property=$2 - - args=(--filter "\"appId eq '$sp_name'\"" --query "[0].$sp_property" --output tsv) - query="az ad sp list ${args[*]}" - - sleep_time_in_seconds=10 - max_wait_in_seconds=180 - max_retries=$((max_wait_in_seconds/sleep_time_in_seconds)) - - count=1 - - while [[ -z $(eval "$query") ]] - do - echo "INFO: waiting for query \"${query}\" to return results (${count}/${max_retries})" - echo "INFO: trying again in ${sleep_time_in_seconds} seconds..." - sleep "${sleep_time_in_seconds}" - - if [[ ${count} -eq max_retries ]]; then - error_log "ERROR: unable to get results from query \"${query}\" in ${max_wait_in_seconds} seconds. Investigate and re-run script." - exit 1 - fi - - count=$((count +1)) - done -} - -check_for_arm_credential() { - util_path=$(realpath "${this_script_path}/../util") - "${util_path}/checkforarmcredential.sh" "ERROR: When using a user-provided service principal, these environment variables are mandatory: ARM_CLIENT_ID, ARM_CLIENT_SECRET" -} - -validate_minimum_role_for_sp() { - "${this_script_path}/validate_minimum_role_for_sp.sh" "${mlz_config}" "${ARM_CLIENT_ID}" -} - -# Create Service Principal -if [[ "${create_service_principal}" == false ]]; -then - check_for_arm_credential - validate_minimum_role_for_sp - - echo "INFO: using user-supplied service principal with client ID ${ARM_CLIENT_ID}..." - - sp_client_id="${ARM_CLIENT_ID}" - sp_client_secret="${ARM_CLIENT_SECRET}" - sp_object_id=$(az ad sp list \ - --filter "appId eq '${ARM_CLIENT_ID}'" \ - --query "[].objectId" \ - --output tsv) -else - echo "INFO: verifying service principal ${mlz_sp_name} is unique..." - if [[ -z $(az ad sp list \ - --filter "displayName eq 'http://${mlz_sp_name}'" \ - --query "[].displayName" \ - --output tsv) ]]; - then - echo "INFO: creating service principal ${mlz_sp_name}..." - sp_creds=($(az ad sp create-for-rbac \ - --name "http://${mlz_sp_name}" \ - --skip-assignment true \ - --query "[password, appId]" \ - --only-show-errors \ - --output tsv)) - - sp_client_secret=${sp_creds[0]} - sp_client_id=${sp_creds[1]} - - wait_for_sp_creation "${sp_client_id}" - wait_for_sp_property "${sp_client_id}" "objectId" - - odata_filter_args=(--filter "\"appId eq '$sp_client_id'\"" --query "[0].objectId" --output tsv) - object_id_query="az ad sp list ${odata_filter_args[*]}" - - sp_object_id=$(eval "$object_id_query") - - # Assign Contributor Role to Subscriptions - for sub in "${subs[@]}" - do - echo "INFO: setting Contributor role assignment for ${sp_client_id} on subscription ${sub}..." - az role assignment create \ - --role Contributor \ - --assignee-object-id "${sp_object_id}" \ - --scope "/subscriptions/${sub}" \ - --assignee-principal-type ServicePrincipal \ - --output none - done - else - error_log "ERROR: A service principal named ${mlz_sp_name} already exists. This must be a unique service principal for your use only. Try again with a new mlz-env-name. Exiting script." - exit 1 - fi -fi - -# Validate or create Terraform Config resource group -rg_exists="az group show \ - --name ${mlz_rg_name} \ - --subscription ${mlz_config_subid}" - -echo "INFO: sourcing resource group ${mlz_rg_name} for MLZ resources..." -if ! $rg_exists &> /dev/null; then - echo "INFO: creating resource group ${mlz_rg_name} for MLZ resources..." - az group create \ - --subscription "${mlz_config_subid}" \ - --location "${mlz_config_location}" \ - --name "${mlz_rg_name}" \ - --tags "DeploymentName=${mlz_config_tag}" \ - --output none -fi - -# Create Key Vault -kv_exists="az keyvault show \ - --name ${mlz_kv_name} \ - --subscription ${mlz_config_subid}" - -echo "INFO: sourcing keyvault ${mlz_kv_name} for MLZ resources..." -if ! $kv_exists &> /dev/null; then - echo "INFO: creating keyvault ${mlz_kv_name} for MLZ resources..." - az keyvault create \ - --name "${mlz_kv_name}" \ - --subscription "${mlz_config_subid}" \ - --resource-group "${mlz_rg_name}" \ - --location "${mlz_config_location}" \ - --output none -fi - -# Create Key Vault Access Policy for Service Principal -echo "INFO: setting access policy on ${mlz_kv_name} for service principal ${mlz_sp_name}..." -az keyvault set-policy \ - --name "${mlz_kv_name}" \ - --subscription "${mlz_config_subid}" \ - --resource-group "${mlz_rg_name}" \ - --object-id "${sp_object_id}" \ - --secret-permissions get list set \ - --output none - -# Set Key Vault Secrets -echo "INFO: setting secrets in ${mlz_kv_name} for service principal ${mlz_sp_name}..." -az keyvault secret set \ - --name "${mlz_kv_sp_client_secret}" \ - --subscription "${mlz_config_subid}" \ - --vault-name "${mlz_kv_name}" \ - --value "${sp_client_secret}" \ - --output none - -az keyvault secret set \ - --name "${mlz_kv_sp_client_id}" \ - --subscription "${mlz_config_subid}" \ - --vault-name "${mlz_kv_name}" \ - --value "${sp_client_id}" \ - --output none - -az keyvault secret set \ - --name "${mlz_kv_sp_object_id}" \ - --subscription "${mlz_config_subid}" \ - --vault-name "${mlz_kv_name}" \ - --value "${sp_object_id}" \ - --output none - -echo "INFO: MLZ resources for ${mlz_env_name} created!" diff --git a/src/scripts/config/create_required_resources.sh b/src/scripts/config/create_required_resources.sh deleted file mode 100755 index f469309a9..000000000 --- a/src/scripts/config/create_required_resources.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC1091,SC2154 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC1091: Not following. Shellcheck can't follow non-constant source. -# SC2154: Referenced but not assigned. These arguments come sourced from other scripts. -# -# A script to configure a resource group that contains Terraform state and a secret store. - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "create_required_resources.sh: configure a resource group that contains Terraform state and a secret store" - error_log "usage: create_required_resources.sh " -} - -if [[ "$#" -lt 1 ]]; then - usage - exit 1 -fi - -mlz_config=$(realpath "${1}") -create_service_principal=${2:-true} - -this_script_path=$(realpath "${BASH_SOURCE%/*}") - -mlz_path="$(realpath "${this_script_path}/../../terraform/mlz")" - -# check for dependencies -. "${this_script_path}/../util/checkforazcli.sh" - -# source variables -. "${mlz_config}" - -# create MLZ configuration resources -. "${this_script_path}/create_mlz_config_resources.sh" \ - "${mlz_config}" \ - "${create_service_principal}" - -# create terraform resources given a subscription ID and terraform configuration folder -. "${this_script_path}/create_terraform_backend_resources.sh" "${mlz_config}" "${mlz_config_subid}" "${mlz_path}" diff --git a/src/scripts/config/create_terraform_backend_resources.sh b/src/scripts/config/create_terraform_backend_resources.sh deleted file mode 100755 index 42b102b95..000000000 --- a/src/scripts/config/create_terraform_backend_resources.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC1091,SC2154 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# -# Create Terraform module backend config resources - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "create_terraform_backend_resources.sh: Create Terraform module config resources" - error_log "usage: create_terraform_backend_resources.sh " -} - -if [[ "$#" -lt 3 ]]; then - usage - exit 1 -fi - -mlz_config=$(realpath "${1}") -tf_sub_id=$2 -tf_dir=$(realpath "${3}") - -# source MLZ config vars -. "${mlz_config}" - -# derive TF names from the terraform directory -tf_name=$(basename "${tf_dir}") - -# generate names -. "${BASH_SOURCE%/*}/generate_names.sh" "${mlz_config}" "${tf_name}" - -echo "INFO: creating resources for ${tf_name} Terraform state..." - -# create TF Resource Group and Storage Account for Terraform State files -echo "INFO: sourcing resource group ${tf_rg_name} for Terraform state..." -rg_exists="az group show \ - --name ${tf_rg_name} \ - --subscription ${tf_sub_id}" - -if ! $rg_exists &> /dev/null; then - echo "INFO: creating resource group ${tf_rg_name}..." - az group create \ - --subscription "${tf_sub_id}" \ - --location "${mlz_config_location}" \ - --name "${tf_rg_name}" \ - --tags "DeploymentName=${mlz_config_tag}" \ - --output none - echo "INFO: resource group ${tf_rg_name} created!" -fi - -echo "INFO: sourcing storage account ${tf_sa_name} for Terraform state..." -sa_exists="az storage account show \ - --name ${tf_sa_name} \ - --subscription ${tf_sub_id}" - -if ! $sa_exists &> /dev/null; then - echo "INFO: creating storage account ${tf_sa_name}..." - az storage account create \ - --name "${tf_sa_name}" \ - --subscription "${tf_sub_id}" \ - --resource-group "${tf_rg_name}" \ - --location "${mlz_config_location}" \ - --sku Standard_LRS \ - --output none - - sa_key=$(az storage account keys list \ - --account-name "${tf_sa_name}" \ - --subscription "${tf_sub_id}" \ - --resource-group "${tf_rg_name}" \ - --query "[?keyName=='key1'].value" \ - --output tsv) - - echo "INFO: creating container ${container_name} in storage account ${tf_sa_name}..." - az storage container create \ - --name "${container_name}" \ - --subscription "${tf_sub_id}" \ - --resource-group "${tf_rg_name}" \ - --account-name "${tf_sa_name}" \ - --account-key "${sa_key}" \ - --output none - echo "INFO: storage account ${tf_sa_name} and container ${container_name} created!" -fi - -# generate a config.vars file -. "${BASH_SOURCE%/*}/generate_vars.sh" \ - "${mlz_config}" \ - "${tf_sub_id}" \ - "${tf_dir}" - -echo "INFO: Terraform state resources for ${tf_name} created!" diff --git a/src/scripts/config/generate_config_file.sh b/src/scripts/config/generate_config_file.sh deleted file mode 100755 index 23f82958c..000000000 --- a/src/scripts/config/generate_config_file.sh +++ /dev/null @@ -1,140 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=1083,1090,2154 -# -# Generate a configuration file for MLZ prerequisites and optional SACA and T0-T2 subscriptions. - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -show_help() { - print_formatted() { - long_name=$1 - char_name=$2 - desc=$3 - printf "%15s %2s %s \n" "$long_name" "$char_name" "$desc" - } - print_formatted "argument" "" "description" - print_formatted "--file" "-f" "the destination file path and name (e.g. 'src/mlz.config')" - print_formatted "--tf-env" "-e" "Terraform azurerm environment (e.g. 'public') see: https://www.terraform.io/docs/language/settings/backends/azurerm.html#environment" - print_formatted "--mlz-env-name" "-z" "Unique name for MLZ environment" - print_formatted "--location" "-l" "The location that you're deploying to (e.g. 'eastus')" - print_formatted "--config-sub-id" "-s" "Subscription ID for MissionLZ configuration resources" - print_formatted "--tenant-id" "-t" "Tenant ID where your subscriptions live" - print_formatted "--hub-sub-id" "-u" "[OPTIONAL]: subscription ID for the hub network and resources" - print_formatted "--tier0-sub-id" "-0" "[OPTIONAL]: subscription ID for tier 0 network and resources" - print_formatted "--tier1-sub-id" "-1" "[OPTIONAL]: subscription ID for tier 1 network and resources" - print_formatted "--tier2-sub-id" "-2" "[OPTIONAL]: subscription ID for tier 2 network and resources" - print_formatted "--tier3-sub-id" "-3" "[OPTIONAL]: subscription ID for tier 3 network and resources" - print_formatted "--help" "-h" "Print this message" -} - -usage() { - echo "generate_config_file.sh: Generate a configuration file for MLZ prerequisites and optional SACA and T0-T2 subscriptions" - show_help -} - -# stage required parameters as not set -dest_file="notset" -tf_environment="notset" -mlz_env_name="notset" -mlz_config_location="notset" -mlz_config_subid="notset" -mlz_tenant_id="notset" - -# inspect arguments -while [ $# -gt 0 ] ; do - case $1 in - -f | --file) - shift - dest_file="$1" ;; - -e | --tf-env) - shift - tf_environment="$1" ;; - -z | --mlz-env-name) - shift - mlz_env_name="$1" ;; - -l | --location) - shift - mlz_config_location="$1" ;; - -s | --config-sub-id) - shift - mlz_config_subid="$1" ;; - -t | --tenant-id) - shift - mlz_tenant_id="$1" ;; - -u | --hub-sub-id) - shift - mlz_saca_subid="$1" ;; - -0 | --tier0-sub-id) - shift - mlz_tier0_subid="$1" ;; - -1 | --tier1-sub-id) - shift - mlz_tier1_subid="$1" ;; - -2 | --tier2-sub-id) - shift - mlz_tier2_subid="$1" ;; - -3 | --tier3-sub-id) - shift - mlz_tier3_subid="$1" ;; - -h | --help) - show_help - exit 0 ;; - *) - error_log "ERROR: Unexpected argument: ${1}" - usage && exit 1 ;; - esac - shift -done - -# check mandatory parameters -for i in { $dest_file $tf_environment $mlz_env_name $mlz_config_location $mlz_config_subid $mlz_tenant_id } -do - if [[ $i == "notset" ]]; then - error_log "ERROR: Missing required arguments. These arguments are mandatory: -f, -e, -z, -l, -s, -t" - usage - exit 1 - fi -done - -# write the file to the desired path -rm -f "$dest_file" -dest_file_dir=$(dirname "${dest_file}") -mkdir -p "${dest_file_dir}" -touch "$dest_file" -{ - echo "tf_environment=${tf_environment}" - echo "mlz_env_name=${mlz_env_name}" - echo "mlz_config_location=${mlz_config_location}" - echo "mlz_config_subid=${mlz_config_subid}" - echo "mlz_tenantid=${mlz_tenant_id}" -} >> "$dest_file" - -# for any optional parameters, check if they're set before appending them to the file -append_optional_args() { - key_name=$1 - key_value=$2 - default_value=$3 - file_to_append=$4 - if [[ $key_value ]]; then - printf "%s=%s\n" "${key_name}" "${key_value}" >> "${file_to_append}" - else - printf "%s=%s\n" "${key_name}" "${default_value}" >> "${file_to_append}" - fi -} -append_optional_args "mlz_saca_subid" "${mlz_saca_subid}" "${mlz_config_subid}" "${dest_file}" -append_optional_args "mlz_tier0_subid" "${mlz_tier0_subid}" "${mlz_config_subid}" "${dest_file}" -append_optional_args "mlz_tier1_subid" "${mlz_tier1_subid}" "${mlz_config_subid}" "${dest_file}" -append_optional_args "mlz_tier2_subid" "${mlz_tier2_subid}" "${mlz_config_subid}" "${dest_file}" -append_optional_args "mlz_tier3_subid" "${mlz_tier3_subid}" "${mlz_config_subid}" "${dest_file}" - -# append cloud specific endpoints -this_script_path=$(realpath "${BASH_SOURCE%/*}") -. "${this_script_path}/append_prereq_endpoints.sh" "${dest_file}" diff --git a/src/scripts/config/generate_names.sh b/src/scripts/config/generate_names.sh deleted file mode 100755 index b03fd6078..000000000 --- a/src/scripts/config/generate_names.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC1091,SC2002,SC2154 -# -# Generate MLZ resource names -# rules from: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "generate_names.sh: Generate MLZ resource names" - error_log "usage: generate_names.sh " -} - -if [[ "$#" -lt 1 ]]; then - usage - exit 1 -fi - -create_resource_group_names() { - export mlz_config_tag="${mlz_prefix}-${env_name_alphanumeric}-config" - export mlz_rg_name="${mlz_config_tag:0:63}" -} - -create_service_principal_name(){ - local mlz_sp_name_full="${mlz_prefix}-${env_name_alphanumeric}-terraform-sp" - export mlz_sp_name="${mlz_sp_name_full:0:120}" -} - -create_keyvault_names(){ - local mlz_kv_name_full="${mlz_prefix}${env_name_alphanumeric}kv${randomish_identifier}" - export mlz_kv_name="${mlz_kv_name_full:0:24}" - - export mlz_kv_sp_client_id="serviceprincipal-clientid" - export mlz_kv_sp_client_secret="serviceprincipal-pwd" - export mlz_kv_sp_object_id="serviceprincipal-objectid" - export mlz_login_app_kv_name="login-app-clientid" - export mlz_login_app_kv_password="login-app-pwd" -} - -create_terraform_backend_names() { - if [[ $tf_name_raw != "notset" ]]; then - tf_name=$(echo "${tf_name_raw}" | tr -cd '[:alnum:]') - - local tfstate_resource_group_name="${mlz_prefix}-${env_name_alphanumeric}-tfstate-${tf_name}" - export tf_rg_name="${tfstate_resource_group_name:0:63}" - - local tfstate_storage_account_name="tfsa${tf_name}${env_name_alphanumeric}${randomish_identifier}" - valid_tfstate_storage_account_name=$(echo "${tfstate_storage_account_name:0:24}" | tr '[:upper:]' '[:lower:]') - export tf_sa_name=${valid_tfstate_storage_account_name} - - export container_name="tfstate" - fi -} - -########## -# main -########## - -mlz_config=$(realpath "${1}") -tf_name_raw=${2:-notset} - -# source variables from MLZ config -. "${mlz_config}" - -mlz_prefix="mlz" - -env_name_alphanumeric=$(echo "${mlz_env_name}" | tr -cd '[:alnum:]') -randomish_identifier=${mlz_config_subid:0:8} # take the first octet in the subscription ID - -create_resource_group_names -create_service_principal_name -create_keyvault_names -create_terraform_backend_names diff --git a/src/scripts/config/generate_vars.sh b/src/scripts/config/generate_vars.sh deleted file mode 100755 index 2d259bfc6..000000000 --- a/src/scripts/config/generate_vars.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC1091,SC2154 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# -# Generate a config.vars file at a given Terraform directory - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "generate_vars.sh: Generate a config.vars file at a given Terraform directory" - error_log "usage: generate_vars.sh " -} - -if [[ "$#" -lt 3 ]]; then - usage - exit 1 -fi - -mlz_config=$(realpath "${1}") -tf_sub_id="${2}" -tf_dir=$(realpath "${3}") -tf_name=$(basename "${tf_dir}") - -# source mlz config -. "${mlz_config}" - -# generate names -. "${BASH_SOURCE%/*}/generate_names.sh" "${mlz_config}" "${tf_name}" - -# generate a config.vars file -config_vars="${tf_dir}/config.vars" -rm -f "$config_vars" -touch "$config_vars" -{ - echo "metadata_host=${mlz_metadatahost}" - echo "tenant_id=${mlz_tenantid}" - echo "mlz_env_name=${mlz_env_name}" - echo "mlz_config_subid=${mlz_config_subid}" - echo "mlz_kv_name=${mlz_kv_name}" - echo "sub_id=${tf_sub_id}" - echo "location=${mlz_config_location}" - echo "tf_rg_name=${tf_rg_name}" - echo "tf_sa_name=${tf_sa_name}" - echo "mlz_kv_sp_client_id=${mlz_kv_sp_client_id}" - echo "mlz_kv_sp_client_secret=${mlz_kv_sp_client_secret}" - echo "mlz_kv_sp_object_id=${mlz_kv_sp_object_id}" - echo "environment=${tf_environment}" - echo "container_name=${container_name}" -} >> "$config_vars" diff --git a/src/scripts/config/get_sp_identity.sh b/src/scripts/config/get_sp_identity.sh deleted file mode 100755 index f5b72951a..000000000 --- a/src/scripts/config/get_sp_identity.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC2154 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# -# Given a MLZTF config.vars file, export a mlz_client_id and mlz_client_secret - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "get_sp_identity.sh: Given a MLZTF config.vars file, export a mlz_client_id, mlz_client_secret, and mlz_object_id" - error_log "usage: get_sp_identity.sh " -} - -if [[ "$#" -lt 1 ]]; then - usage - exit 1 -fi - -config_vars=$1 - -# Validate configuration file exists -. "$(dirname "${BASH_SOURCE%/*}")/util/checkforfile.sh" \ - "${config_vars}" \ - "The configuration file ${config_vars} is empty or does not exist. You may need to run MLZ setup." - -# Source configuration file -. "${config_vars}" - -# query for service principal client ID -kv_id_exists="az keyvault secret show \ - --name ${mlz_kv_sp_client_id} \ - --vault-name ${mlz_kv_name} \ - --subscription ${mlz_config_subid}" - -if ! $kv_id_exists &> /dev/null; then - echo "The Key Vault secret ${mlz_kv_sp_client_id} does not exist...validate config.vars file and re-run script" - exit 1 -else - client_id=$(az keyvault secret show \ - --name "${mlz_kv_sp_client_id}" \ - --vault-name "${mlz_kv_name}" \ - --subscription "${mlz_config_subid}" \ - --query value \ - --output tsv) - export client_id -fi - -# query for service principal password -kv_pwd_exists="az keyvault secret show \ - --name ${mlz_kv_sp_client_secret} \ - --vault-name ${mlz_kv_name} \ - --subscription ${mlz_config_subid}" - -if ! $kv_pwd_exists &> /dev/null; then - echo "The Key Vault secret ${mlz_kv_sp_client_secret} does not exist...validate config.vars file and re-run script" - exit 1 -else - client_secret=$(az keyvault secret show \ - --name "${mlz_kv_sp_client_secret}" \ - --vault-name "${mlz_kv_name}" \ - --subscription "${mlz_config_subid}" \ - --query value \ - --output tsv) - export client_secret -fi - -# query for service principal object ID -kv_obj_id_exists="az keyvault secret show \ - --name ${mlz_kv_sp_object_id} \ - --vault-name ${mlz_kv_name} \ - --subscription ${mlz_config_subid}" -if ! $kv_obj_id_exists &> /dev/null; then - echo "The Key Vault secret ${mlz_kv_sp_object_id} does not exist...validate config.vars file and re-run script" - exit 1 -else - object_id=$(az keyvault secret show \ - --name "${mlz_kv_sp_object_id}" \ - --vault-name "${mlz_kv_name}" \ - --subscription "${mlz_config_subid}" \ - --query value \ - --output tsv) - export object_id -fi - -# Validate Service Principal exists -sp_exists="az ad sp show \ - --id ${client_id}" - -if ! $sp_exists &> /dev/null; then - echo "Service Principal with Client ID ${client_id} could not be found...validate config.vars file and re-run script" - exit 1 -fi diff --git a/src/scripts/config/validate_minimum_role_for_sp.sh b/src/scripts/config/validate_minimum_role_for_sp.sh deleted file mode 100755 index 60802e564..000000000 --- a/src/scripts/config/validate_minimum_role_for_sp.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# -# validates that a Service Principal has 'Contributor' or 'Owner' -# role assigned for the subscriptions in a given .mlzconfig - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - error_log "usage: validate_minimum_role_for_sp.sh " - echo "validate_minimum_role_for_sp.sh: validates that a Service Principal for a given Client ID has 'Contributor' or 'Owner' role assigned for the subscriptions in a given .mlzconfig" -} - -if [[ "$#" -lt 2 ]]; then - usage - exit 1 -fi - -mlz_config=$(realpath "${1}") -client_id=${2} - -# Source variables -. "${mlz_config}" - -# Create array of unique subscription IDs. The 'sed' command below search thru the source -# variables file looking for all lines that do not have a '#' in the line. If a line with -# a '#' is found, the '#' and ever character after it in the line is ignored. The output -# of what remains from the sed command is then piped to grep to find the words that match -# the pattern. These words are what make up the 'mlz_subs' array. -mlz_sub_pattern="mlz_.*._subid" -mlz_subs=$(< "${mlz_config}" sed 's:#.*$::g' | grep -w "${mlz_sub_pattern}") -subs=() -for mlz_sub in $mlz_subs -do - mlz_sub_id=$(echo "${mlz_sub#*=}" | tr -d '"') - if [[ ! "${subs[*]}" =~ ${mlz_sub_id} ]];then - subs+=("${mlz_sub_id}") - fi -done - -object_id=$(az ad sp list \ - --filter "appId eq '${client_id}'" \ - --query "[].objectId" \ - --output tsv) - -subs_requiring_role_assignment=() - -for sub in "${subs[@]}" -do - valid_assignments=$(az role assignment list \ - --assignee "${object_id}" \ - --scope "/subscriptions/${sub}" \ - --query "[?roleDefinitionName=='Contributor' || roleDefinitionName=='Owner'].{scope: scope}" \ - --output tsv) - if [[ -z $valid_assignments ]]; then - subs_requiring_role_assignment+=("${sub}") - fi -done - -if [[ ${#subs_requiring_role_assignment[@]} -gt 0 ]]; then - error_log "ERROR: service principal with client ID ${client_id} is missing 'Contributor' role!" - echo "INFO: at minimum, the 'Contributor' role is required to manage resources via Terraform." - echo "INFO: to set this role for the relevant subscriptions, a user with the 'Owner' role can try these commands:" - - for sub in "${subs_requiring_role_assignment[@]}" - do - echo "INFO: az role assignment create --assignee-object-id ${object_id} --role \"Contributor\" --scope \"/subscriptions/${sub}\"" - done - - error_log "ERROR: please assign the 'Contributor' role to this service principal and try again." - exit 1 -fi diff --git a/src/scripts/deploy.sh b/src/scripts/deploy.sh deleted file mode 100755 index 676d7b7cb..000000000 --- a/src/scripts/deploy.sh +++ /dev/null @@ -1,271 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=1091,2155 -# -# create all the configuration and deploy Terraform resources with minimal input - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -show_help() { - print_formatted() { - local long_name=$1 - local char_name=$2 - local desc=$3 - printf "%25s %2s %s \n" "$long_name" "$char_name" "$desc" - } - print_formatted "--------" "" "-----------" - print_formatted "argument" "" "description" - print_formatted "--------" "" "-----------" - print_formatted "--subscription-id" "-s" "Subscription ID for MissionLZ resources" - print_formatted "--location" "-l" "[OPTIONAL] The location that you're deploying to (defaults to 'eastus')" - print_formatted "--tf-environment" "-e" "[OPTIONAL] Terraform azurerm environment (defaults to 'public') see: https://www.terraform.io/docs/language/settings/backends/azurerm.html#environment" - print_formatted "--mlz-env-name" "-z" "[OPTIONAL] Unique name for MLZ environment (defaults to 'mlz' + UNIX timestamp)" - print_formatted "--hub-sub-id" "-u" "[OPTIONAL] subscription ID for the hub network and resources (defaults to the value provided for -s --subscription-id)" - print_formatted "--tier0-sub-id" "-0" "[OPTIONAL] subscription ID for tier 0 network and resources (defaults to the value provided for -s --subscription-id)" - print_formatted "--tier1-sub-id" "-1" "[OPTIONAL] subscription ID for tier 1 network and resources (defaults to the value provided for -s --subscription-id)" - print_formatted "--tier2-sub-id" "-2" "[OPTIONAL] subscription ID for tier 2 network and resources (defaults to the value provided for -s --subscription-id)" - print_formatted "--tier3-sub-id" "-3" "[OPTIONAL] subscription ID for tier 3 network and resources (defaults to the value provided for -s --subscription-id), input is used in conjunction with deploy_t3.sh" - print_formatted "--write-output" "-w" "[OPTIONAL] Tier 3 Deployment requires Terraform output, use this flag to write terraform output" - print_formatted "--no-bastion" "" "[OPTIONAL] when present, do not create a Bastion Host and Jumpbox VM" - print_formatted "--no-sentinel" "" "[OPTIONAL] when present, do not create an Azure Sentinel solution" - print_formatted "--no-service-principal" "" "[OPTIONAL] when present, do not create an Azure Service Principal, instead use the credentials in the environment variables '\$ARM_CLIENT_ID' and '\$ARM_CLIENT_SECRET'" - print_formatted "--help" "-h" "Print this message" -} - -usage() { - echo "deploy.sh: create all the configuration and deploy Terraform resources with minimal input" - show_help -} - -check_dependencies() { - "${this_script_path}/util/checkforazcli.sh" - "${this_script_path}/util/checkforterraform.sh" -} - -inspect_user_input() { - # check mandatory parameters - # shellcheck disable=1083 - for i in { $mlz_config_subid } - do - if [[ $i == "notset" ]]; then - error_log "ERROR: Missing required arguments. These arguments are mandatory: -s" - usage - exit 1 - fi - done - - # notify the user about any defaults - log_default() { - local argument_name=$1 - local argument_default=$2 - local argument_value=$3 - if [[ "${argument_value}" = "${argument_default}" ]]; then - echo "INFO: using the default value '${argument_default}' for '${argument_name}', specify the '${argument_name}' argument to provide a different value." - fi - } - log_default "--location" "${default_config_location}" "${mlz_config_location}" - log_default "--tf-environment" "${default_tf_environment}" "${tf_environment}" - log_default "--mlz-env-name" "${default_env_name}" "${mlz_env_name}" - - # if the user has set --no-service-principal, ensure mandatory environment variables are set - # and that the service principal exists - if [[ "${create_service_principal}" == false ]]; then - "${this_script_path}/util/checkforarmcredential.sh" "ERROR: When specifying --no-service-principal, these environment variables are mandatory: ARM_CLIENT_ID, ARM_CLIENT_SECRET" - fi -} - -login_azcli() { - echo "INFO: setting current subscription to ${mlz_config_subid}..." - az account set \ - --subscription "${mlz_config_subid}" \ - --only-show-errors \ - --output none -} - -validate_cloud_arguments() { - echo "INFO: validating settings for '${mlz_config_location}' and '${tf_environment}'..." - # ensure location is present and terraform environment matches for the current cloud - "${this_script_path}/util/validateazlocation.sh" "${mlz_config_location}" - "${this_script_path}/terraform/validate_cloud_for_tf_env.sh" "${tf_environment}" -} - -create_mlz_configuration_file() { - echo "INFO: creating an MLZ config file at ${mlz_config_file_path}..." - - local mlz_tenantid=$(az account show \ - --query "tenantId" \ - --output tsv) - - local gen_config_args=() - gen_config_args+=("-f ${mlz_config_file_path}") - gen_config_args+=("-e ${tf_environment}") - gen_config_args+=("-z ${mlz_env_name}") - gen_config_args+=("-l ${mlz_config_location}") - gen_config_args+=("-s ${mlz_config_subid}") - gen_config_args+=("-t ${mlz_tenantid}") - - # add hubs and spokes input, if present - for j in "${subs_args[@]}" - do - gen_config_args+=("$j") - done - - # expand array into a string of space separated arguments - local gen_config_args_str=$(printf '%s ' "${gen_config_args[*]}") - - # ignoring shellcheck for word splitting because that is the desired behavior - # shellcheck disable=SC2086 - "${this_script_path}/config/generate_config_file.sh" $gen_config_args_str -} - -validate_mlz_configuration_file() { - . "${mlz_config_file_path}" - - ensure_vars_are_set() - { - local var_names=("$@") - local any_required_var_unset=false - - for var_name in "${var_names[@]}"; do - if [[ -z "${!var_name}" ]]; then - echo "ERROR: ${var_name} is required but is not set in MLZ configuration file at ${mlz_config_file_path}" - any_required_var_unset=true - fi - done - - if [[ "$any_required_var_unset" == true ]]; then - exit 1 - fi - } - - ensure_vars_are_set mlz_metadatahost mlz_cloudname -} - -create_mlz_resources() { - echo "INFO: creating MLZ resources using ${mlz_config_file_path}..." - "${this_script_path}/config/create_required_resources.sh" "${mlz_config_file_path}" "${create_service_principal}" -} - -create_terraform_variables() { - echo "INFO: creating terraform variables at ${tfvars_file_path}..." - "${this_script_path}/terraform/create_tfvars_from_config.sh" "${tfvars_file_path}" "${mlz_config_file_path}" "${create_bastion_jumpbox}" "${create_sentinel}" -} - -apply_terraform() { - echo "INFO: applying Terraform using ${mlz_config_file_path} and ${tfvars_file_path}..." - . "${this_script_path}/config/generate_names.sh" "${mlz_config_file_path}" - "${this_script_path}/../build/apply_tf.sh" \ - "${mlz_config_file_path}" \ - "${tfvars_file_path}" \ - "y" -} - -write_outputs() { - echo "INFO: Writing outputs from terraform deployment" - cd "${this_script_path}/../terraform/mlz" - terraform output -json | tee ${configuration_output_path}/output.tfvars.json -} - -display_clean_hint() { - echo "INFO: Try this command to clean up what was deployed:" - echo "INFO: ${this_script_path}/clean.sh -z ${mlz_env_name}" -} - -########## -# main -########## - -this_script_path=$(realpath "${BASH_SOURCE%/*}") -configuration_output_path="$(realpath ${this_script_path}/../generated-configurations)" -timestamp=$(date +%s) - -# set some defaults -default_config_subid="notset" -default_config_location="eastus" -default_tf_environment="public" -default_env_name="mlz${timestamp}" -create_bastion_jumpbox=true -create_sentinel=true -create_service_principal=true - -mlz_config_subid="${default_config_subid}" -mlz_config_location="${default_config_location}" -tf_environment="${default_tf_environment}" -mlz_env_name="${default_env_name}" -write_output="false" -subs_args=() - -while [ $# -gt 0 ] ; do - case $1 in - -s | --subscription-id) - shift - mlz_config_subid="$1" ;; - -l | --location) - shift - mlz_config_location="$1" ;; - -e | --tf-environment) - shift - tf_environment="$1" ;; - -z | --mlz-env-name) - shift - mlz_env_name="$1" ;; - -u | --hub-sub-id) - shift - subs_args+=("-u ${1}") ;; - -0 | --tier0-sub-id) - shift - subs_args+=("-0 ${1}") ;; - -1 | --tier1-sub-id) - shift - subs_args+=("-1 ${1}") ;; - -2 | --tier2-sub-id) - shift - subs_args+=("-2 ${1}") ;; - -3 | --tier3-sub-id) - shift - subs_args+=("-3 ${1}") ;; - -w | --write-output) - write_output="true" ;; - --no-bastion) - create_bastion_jumpbox=false ;; - --no-sentinel) - create_sentinel=false ;; - --no-service-principal) - create_service_principal=false ;; - -h | --help) - show_help - exit 0 ;; - *) - error_log "ERROR: Unexpected argument: ${1}" - usage && exit 1 ;; - esac - shift -done - -# validate requirements -check_dependencies -inspect_user_input -login_azcli -validate_cloud_arguments - -# create variables -mlz_config_file_path="${configuration_output_path}/${mlz_env_name}.mlzconfig" -tfvars_file_path="${configuration_output_path}/${mlz_env_name}.tfvars" -create_mlz_configuration_file -validate_mlz_configuration_file -create_terraform_variables - -# create resources -trap 'display_clean_hint' EXIT # no matter if the next commands fail, run display_clean_hint -create_mlz_resources -apply_terraform -if [[ $write_output == "true" ]]; then - write_outputs -fi diff --git a/src/scripts/deploy_t3.sh b/src/scripts/deploy_t3.sh deleted file mode 100755 index 7f4bdcc4a..000000000 --- a/src/scripts/deploy_t3.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC2154 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# -# Deployment script for performing all of the required steps to deploy and bind a tier3 to an existing MLZ deployment - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "deploy_t3.sh: Automation that calls apply terraform given a MLZ configuration and some tfvars" - error_log "usage: deploy_t3.sh " -} - -if [[ "$#" -lt 3 ]]; then - usage - exit 1 -fi - -# take some valid, well known, mlz_config and vars as input -mlz_config=$1 -output_vars=$(realpath "${2}") -tier3_vars=$3 -display_tf_output=${4:-n} - -# reference paths -this_script_path=$(realpath "${BASH_SOURCE%/*}") -src_dir=$(dirname "${this_script_path}") -terraform_path="${src_dir}/terraform/" -scripts_dir="${src_dir}/scripts/" - -# apply function -apply() { - sub_id=$1 - tf_dir=$2 - vars=$3 - - . "${this_script_path}/config/create_terraform_backend_resources.sh" "${mlz_config}" "${sub_id}" "${tf_dir}" - - # generate config.vars based on MLZ Config and Terraform module - . "${scripts_dir}/config/generate_vars.sh" \ - "${mlz_config}" \ - "${sub_id}" \ - "${tf_dir}" - - # remove any existing terraform initialzation - rm -rf "${tf_dir}/.terraform" - - # copy input vars to temporary file - input_vars=$(realpath "${vars}") - temp_vars="temp_vars.tfvars" - rm -f "${temp_vars}" - touch "${temp_vars}" - cp "${input_vars}" "${temp_vars}" - - # remove any tfvars and subtitute it with input vars - tf_vars="${tf_dir}/$(basename "${vars}")" - rm -f "${tf_vars}" - touch "${tf_vars}" - cp "${temp_vars}" "${tf_vars}" - rm -f "${temp_vars}" - - # set the target subscription - az account set \ - --subscription "${sub_id}" \ - --output none - - # attempt to apply $max_attempts times before giving up - # (race conditions, transient errors etc.) - apply_success="false" - attempts=1 - max_attempts=5 - - apply_command="${scripts_dir}/terraform/apply_terraform.sh ${tf_dir} ${tf_vars} y ${output_vars}" - destroy_command="${scripts_dir}/terraform/destroy_terraform.sh ${tf_dir} ${tf_vars} y" - - if [[ $display_tf_output == "n" ]]; then - apply_command+=" &>/dev/null" - destroy_command+=" &>/dev/null" - fi - - while [ $apply_success == "false" ] - do - echo "INFO: applying Terraform at ${tf_dir} (${attempts}/${max_attempts})..." - - if ! eval "$apply_command"; - then - # if we fail, run terraform destroy and try again - error_log "ERROR: failed to apply ${tf_dir} (${attempts}/${max_attempts}). Trying some manual clean-up and Terraform destroy..." - eval "$destroy_command" - - ((attempts++)) - - if [[ $attempts -gt $max_attempts ]]; then - error_log "ERROR: failed ${max_attempts} times to apply ${tf_dir}. Exiting." - exit 1 - fi - else - # if we succeed meet the base case - apply_success="true" - echo "INFO: finished applying ${tf_dir}!" - fi - done -} - -# source vars from mlz_config -. "${mlz_config}" - -# call apply() -apply "${mlz_tier3_subid}" "${terraform_path}/tier3" "${tier3_vars}" diff --git a/src/scripts/security-center/configure_asc.sh b/src/scripts/security-center/configure_asc.sh deleted file mode 100755 index ef8ceb4d9..000000000 --- a/src/scripts/security-center/configure_asc.sh +++ /dev/null @@ -1,170 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC1091,SC2154 -# -# Configures the landing zone subscriptions for Azure Security Center - -set -e - -PGM=$(basename "${0}") - -if [[ "${PGM}" == "configure_asc.sh" && "$#" -lt 1 ]]; then - echo "${PGM}: Initializes Azure Security Center Standard tier for Storage Accounts and Virtual Machines" - echo "usage: ${PGM} " - exit 1 -elif [[ ! "${PGM}" == "create_required_resources.sh" ]];then - - mlz_config=$(realpath "${1}") - - # Source variables - . "${mlz_config}" - - mlz_sub_pattern="mlz_.*._subid" - mlz_subs=$(< "$(realpath "${1}")" sed 's:#.*$::g' | grep -w "${mlz_sub_pattern}") - subs=() - - for mlz_sub in $mlz_subs - do - # Grab value of variable - mlz_sub_id=$(echo "${mlz_sub#*=}" | tr -d '"') - if [[ ! "${subs[*]}" =~ ${mlz_sub_id} ]];then - subs+=("${mlz_sub_id}") - fi - done -fi - -# Configure Azure Security Center -for sub in "${subs[@]}" -do - ascAutoProv=$(az security auto-provisioning-setting show \ - --subscription "${sub}" \ - --name "default" \ - --query autoProvision \ - --output tsv \ - --only-show-errors) - if [[ ${ascAutoProv} == "Off" ]]; then - - # generate names - . "${BASH_SOURCE%/*}"/generate_names.sh "${mlz_env_name}" - - # Create Resource Group for Log Analytics workspace - rg_exists="az group show \ - --name ${mlz_lawsrg_name} \ - --subscription ${sub}" - - if ! $rg_exists &> /dev/null; then - echo "Resource Group does not exist...creating resource group ${mlz_lawsrg_name}" - az group create \ - --subscription "${sub}" \ - --location "${mlz_config_location}" \ - --name "${mlz_lawsrg_name}" \ - --output none - else - echo "Resource Group ${mlz_lawsrg_name} already exists. Verify desired ASC configuration and re-run script" - exit 1 - fi - - # Create Log Analytics workspace - laws_exists="az monitor log-analytics workspace show \ - --resource-group ${mlz_lawsrg_name} \ - --workspace-name ${mlz_laws_name} - --subscription ${sub}" - - if ! $laws_exists &> /dev/null; then - echo "Log Analytics workspace does not exist...creating workspace ${mlz_laws_name}" - lawsId=$(az monitor log-analytics workspace create \ - --resource-group "${mlz_lawsrg_name}" \ - --workspace-name "${mlz_laws_name}" \ - --location "${mlz_config_location}" \ - --subscription "${sub}" \ - --query id \ - --output tsv) - else - echo "Log Analytics workspace ${mlz_laws_name} already exists. Verify desired ASC configuration and re-run script" - exit 1 - fi - - # Set ASC pricing tier on Virtual Machines - if [[ $(az security pricing show --name VirtualMachines --subscription "${sub}" --only-show-errors --query pricingTier --output tsv) == "Free" ]]; then - echo "Setting ASC pricing tier for Virtual Machines to Standard..." - az security pricing create \ - --name VirtualMachines \ - --subscription "${sub}" \ - --tier "Standard" \ - --output none - fi - - # Set ASC pricing tier on Storage Accounts - if [[ $(az security pricing show --name StorageAccounts --subscription "${sub}" --only-show-errors --query pricingTier --output tsv --only-show-errors) == "Free" ]]; then - echo "Setting ASC pricing tier for Storage Accounts to Standard..." - az security pricing create \ - --name StorageAccounts \ - --subscription "${sub}" \ - --tier "Standard" \ - --output none - fi - - # Create default setting for ASC Log Analytics workspace - ascwss_exists="az security workspace-setting show \ - --name default \ - --subscription ${sub} \ - --only-show-errors" - - if ! $ascwss_exists &> /dev/null; then - - sleep_time_in_seconds=30 - max_wait_in_minutes=30 - max_wait_in_seconds=$((max_wait_in_minutes*60)) - max_retries=$((max_wait_in_seconds/sleep_time_in_seconds)) - - echo "Maximum time to wait in seconds = ${max_wait_in_seconds}" - echo "Maximum number of retries = ${max_retries}" - - echo "ASC Log Analytics workspace setting does not exist...creating default setting" - echo "This script will attempt to create the setting for ${max_wait_in_minutes} minutes and then timeout if the setting has not been created" - - az security workspace-setting create \ - --name "default" \ - --target-workspace "${lawsId}" \ - --subscription "${sub}" \ - --output none - - count=1 - - # TODO (20210309): this could take an unusually long time and even fail altogether. - # This is under investigation by the `az security` team. - while [ -z "$(az security workspace-setting show --name default --subscription "${sub}" --query workspaceId --output tsv --only-show-errors)" ] - do - - echo "Waiting for ASC workspace setting to finish provisioning (${count}/${max_retries})" - echo "Trying again in ${sleep_time_in_seconds} seconds..." - sleep "${sleep_time_in_seconds}" - - if [[ ${count} -eq max_retries ]];then - echo "Provisioning the workspace setting has exceeded ${max_wait_in_minutes} minutes. Investigate and re-run script." - exit 1 - fi - - count=$((count + 1)) - - done - else - echo "ASC already has a \"default\" Log Analytics workspace configuration. Verify desired ASC configuration and re-run script" - exit 1 - fi - - # Set ASC auto-provisioning to On - az security auto-provisioning-setting update \ - --auto-provision "On" \ - --subscription "${sub}" \ - --name "default" \ - --only-show-errors \ - --output none - else - echo "ASC auto-provisioning is already set to \"On\". Verify desired ASC configuration and re-run script" - exit 1 - fi -done \ No newline at end of file diff --git a/src/scripts/security-center/generate_names.sh b/src/scripts/security-center/generate_names.sh deleted file mode 100755 index fb4c9d5cb..000000000 --- a/src/scripts/security-center/generate_names.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# Generate Azure Security Center resource names - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "${0}: Generate Security Center resource names" - error_log "usage: ${0} " -} - -if [[ "$#" -ne 2 ]]; then - usage - exit 1 -fi - -mlz_enclave_name_raw=$1 -sub_raw=$2 - -# remove hyphens for resource naming restrictions -# in the future, do more cleansing -mlz_enclave_name="${mlz_enclave_name_raw//-}" -safeSubId="${sub_raw//-}" - - -# Name MLZ config resources -export mlz_lawsrg_name="rg-mlz-laws-${mlz_enclave_name}" -export mlz_laws_name="laws-${mlz_enclave_name}-${safeSubId}" \ No newline at end of file diff --git a/src/scripts/terraform/apply_terraform.sh b/src/scripts/terraform/apply_terraform.sh deleted file mode 100755 index 460e1bcaf..000000000 --- a/src/scripts/terraform/apply_terraform.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC1091,SC2154,SC2143 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC1091: Not following. Shellcheck can't follow non-constant source. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# SC2143: Use grep -q instead of comparing output. Ignored for legibility. -# -# Applies a Terraform configuration given a backend configuration, a global variables file, and a terraform configurationd directory - -set -e - -if [[ "$#" -lt 2 ]]; then - echo "apply_terraform.sh: initializes Terraform for a given directory using given a .env file for backend configuration" - echo "usage: apply_terraform.sh " - exit 1 -fi - -tf_dir=$(realpath "${1}") -tf_vars=$(realpath "${2}") -auto_approve=${3:-n} -extra_vars=${4:-notset} - -scripts_path=$(realpath "${BASH_SOURCE%/*}/..") - -# init terraform for the directory -. "${scripts_path}/terraform/init_terraform.sh" "$tf_dir" - -# verify Service Principal is valid and set client_id, client_secret, object_id -. "${scripts_path}/config/get_sp_identity.sh" "${config_vars}" - -apply_command="terraform apply" - -if [[ $auto_approve == "y" ]]; then - apply_command+=" -input=false -auto-approve" -fi - -apply_command+=" -var-file=${tf_vars}" -apply_command+=" -var mlz_clientid=${client_id}" -apply_command+=" -var mlz_clientsecret=${client_secret}" -apply_command+=" -var mlz_objectid=${object_id}" - -if [[ $extra_vars != "notset" ]]; then - extra_vars_real=$(realpath "${4}") - apply_command+=" -var-file=${extra_vars_real}" -fi - -eval "${apply_command}" diff --git a/src/scripts/terraform/create_tfvars_from_config.sh b/src/scripts/terraform/create_tfvars_from_config.sh deleted file mode 100755 index 26003a32c..000000000 --- a/src/scripts/terraform/create_tfvars_from_config.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=1090,2154 -# SC1090: Can't follow non-constant source. This file is input. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# -# generate a terraform globals tfvars file given an MLZ config and a desired tfvars file name - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "create_tfvars_from_config.sh: generate a terraform tfvars file given an MLZ config and a desired tfvars file name" - echo "create_tfvars_from_config.sh: " - show_help -} - -if [[ "$#" -lt 2 ]]; then - usage - exit 1 -fi - -file_to_create=$1 -mlz_config=$2 -create_bastion_jumpbox=${3:-true} -create_sentinel=${4:-true} - -# source config -. "${mlz_config}" - -# given a key and value write a key="value" new line to a file -append_kvp() { - key=$1 - value=$2 - printf "%s=\"%s\"\n" "${key}" "${value}" >> "${file_to_create}" -} - -# write the file to the desired path -rm -f "$file_to_create" -dest_file_dir=$(dirname "${file_to_create}") -mkdir -p "${dest_file_dir}" -touch "$file_to_create" - -append_kvp "deploymentname" "${mlz_env_name}" - -append_kvp "tf_environment" "${tf_environment}" - -append_kvp "mlz_cloud" "${mlz_cloudname}" -append_kvp "mlz_tenantid" "${mlz_tenantid}" -append_kvp "mlz_location" "${mlz_config_location}" -append_kvp "mlz_metadatahost" "${mlz_metadatahost}" - -append_kvp "hub_subid" "${mlz_saca_subid}" -append_kvp "hub_rgname" "rg-saca-${mlz_env_name}" -append_kvp "hub_vnetname" "vn-saca-${mlz_env_name}" -append_kvp "create_bastion_jumpbox" "${create_bastion_jumpbox}" - -append_kvp "tier0_subid" "${mlz_tier0_subid}" -append_kvp "tier0_rgname" "rg-t0-${mlz_env_name}" -append_kvp "tier0_vnetname" "vn-t0-${mlz_env_name}" - -append_kvp "tier1_subid" "${mlz_tier1_subid}" -append_kvp "tier1_rgname" "rg-t1-${mlz_env_name}" -append_kvp "tier1_vnetname" "vn-t1-${mlz_env_name}" -append_kvp "mlz_lawsname" "laws-${mlz_env_name}" -append_kvp "create_sentinel" "${create_sentinel}" - -append_kvp "tier2_subid" "${mlz_tier2_subid}" -append_kvp "tier2_rgname" "rg-t2-${mlz_env_name}" -append_kvp "tier2_vnetname" "vn-t2-${mlz_env_name}" - -if [ -n "${mlz_tier3_subid+x}" ]; then - -append_kvp "tier3_subid" "${mlz_tier3_subid}" -append_kvp "tier3_rgname" "rg-t3-${mlz_env_name}" -append_kvp "tier3_vnetname" "vn-t3-${mlz_env_name}" - -fi diff --git a/src/scripts/terraform/destroy_terraform.sh b/src/scripts/terraform/destroy_terraform.sh deleted file mode 100755 index 8743e8c25..000000000 --- a/src/scripts/terraform/destroy_terraform.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC1091,SC2154,SC2143 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC1091: Not following. Shellcheck can't follow non-constant source. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# SC2143: Use grep -q instead of comparing output. Ignored for legibility. -# -# Destroys a Terraform configuration given a backend configuration, a global variables file, and a terraform configurationd directory - -set -e - -if [[ "$#" -lt 2 ]]; then - echo "destroy_terraform.sh: initializes Terraform for a given directory using given a .env file for backend configuration" - echo "usage: destroy_terraform.sh " - exit 1 -fi - -tf_dir=$(realpath "${1}") -tf_vars=$(realpath "${2}") -auto_approve=${3:-n} - -scripts_path=$(realpath "${BASH_SOURCE%/*}/..") - -# init terraform for the directory -. "${scripts_path}/terraform/init_terraform.sh" "$tf_dir" - -# verify Service Principal is valid and set client_id, client_secret, object_id -. "${scripts_path}/config/get_sp_identity.sh" "${config_vars}" - -# destroy the terraform configuration with global vars and the configuration's tfvars -destroy_command="terraform destroy" - -if [[ $auto_approve == "y" ]]; then - destroy_command+=" -input=false -auto-approve" -fi - -destroy_command+=" -var-file=${tf_vars}" -destroy_command+=" -var mlz_clientid=${client_id}" -destroy_command+=" -var mlz_clientsecret=${client_secret}" -destroy_command+=" -var mlz_objectid=${object_id}" - -eval "${destroy_command}" diff --git a/src/scripts/terraform/init_terraform.sh b/src/scripts/terraform/init_terraform.sh deleted file mode 100755 index 24eeee20e..000000000 --- a/src/scripts/terraform/init_terraform.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# shellcheck disable=SC1090,SC1091,SC2143,SC2154 -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC1091: Not following. Shellcheck can't follow non-constant source. -# SC2154: "var is referenced but not assigned". These values come from an external file. -# SC2143: Use grep -q instead of comparing output. Ignored for legibility. -# -# Initializes Terraform for a given directory using given a .env file for backend configuration - -set -e - -if [[ "$#" -lt 1 ]]; then - echo "init_terraform.sh: initializes Terraform for a given directory using given a .env file for backend configuration" - echo "usage: init_terraform.sh " - exit 1 -fi - -tf_dir=$(realpath "${1}") -tf_name=$(basename "${tf_dir}") - -config_vars="${tf_dir}/config.vars" - -scripts_path=$(realpath "${BASH_SOURCE%/*}/..") - -# check for dependencies -. "${scripts_path}/util/checkforazcli.sh" -. "${scripts_path}/util/checkforterraform.sh" - -# Validate necessary Azure resources exist -. "${scripts_path}/config/config_validate.sh" "${tf_dir}" - -# Validate configuration file exists -. "${scripts_path}/util/checkforfile.sh" \ - "${config_vars}" \ - "The configuration file ${config_vars} is empty or does not exist. You may need to run MLZ setup." - -# Source configuration file -. "${config_vars}" - -# Verify Service Principal is valid and set client_id and client_secret environment variables -. "${scripts_path}/config/get_sp_identity.sh" "${config_vars}" - -# Set the terraform state key -key="${mlz_env_name}${tf_name}" - -# declare terraform init arguments for the backend configuration -init_args=() -init_args+=("-backend-config=\"metadata_host=${metadata_host}\"") -init_args+=("-backend-config=\"key=${key}\"") -init_args+=("-backend-config=\"resource_group_name=${tf_rg_name}\"") -init_args+=("-backend-config=\"storage_account_name=${tf_sa_name}\"") -init_args+=("-backend-config=\"container_name=${container_name}\"") -init_args+=("-backend-config=\"environment=${environment}\"") -init_args+=("-backend-config=\"tenant_id=${tenant_id}\"") -init_args+=("-backend-config=\"subscription_id=${mlz_config_subid}\"") -init_args+=("-backend-config=\"client_id=${client_id}\"") -init_args+=("-backend-config=\"client_secret=${client_secret}\"") - -# If there is an offline terraform provider (plugin) cache, append it to the init arguments -if [[ -d $TF_PLUGIN_CACHE_DIR ]]; then - init_args+=("-plugin-dir=${TF_PLUGIN_CACHE_DIR}") -fi - -# Initialize terraform in the configuration directory -cd "${tf_dir}" || exit -eval terraform init "${init_args[@]}" diff --git a/src/scripts/terraform/validate_cloud_for_tf_env.sh b/src/scripts/terraform/validate_cloud_for_tf_env.sh deleted file mode 100755 index ab1d88e92..000000000 --- a/src/scripts/terraform/validate_cloud_for_tf_env.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# validate cloud matches known tf_environment values - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "validate_cloud_for_tf_env.sh: validate a given tf_environment matches the user's cloud" - error_log "usage: validate_cloud_for_tf_env.sh public" -} - -this_script_path=$(realpath "${BASH_SOURCE%/*}") - -# check for dependencies -"${this_script_path}/../util/checkforazcli.sh" - -# inspect user input -if [[ "$#" -lt 1 ]]; then - usage - exit 1 -fi - -tf_env=$1 -tf_env_lower=${tf_env,,} # ${var,,} syntax is to output a string as lowercase - -current_cloud=$(az cloud show --query name --output tsv) -current_cloud_lower=${current_cloud,,} # ${var,,} syntax is to output a string as lowercase - -# declare a dictionary of Terraform environment names and their clouds -# sourcing the valid combinations from here https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#environment -declare -A tfenv_cloud_pairs -tfenv_cloud_pairs['public']='azurecloud' -tfenv_cloud_pairs['usgovernment']='azureusgovernment' -tfenv_cloud_pairs['german']='azuregermancloud' -tfenv_cloud_pairs['china']='azurechinacloud' -tfenv_cloud_pairs['ussec']='ussec' -tfenv_cloud_pairs['usnat']='usnat' - -tf_env_is_valid=false - -# if the dictionary does contain the environment and it maps to the current cloud, then we're good -if [[ ${tfenv_cloud_pairs["${tf_env_lower}"]} == "${current_cloud_lower}" ]]; then - tf_env_is_valid=true -fi - -# otherwise, throw an error and exit -if [[ "${tf_env_is_valid}" = false ]]; then - error_log "ERROR: Terraform environment '${tf_env}' is not a valid environment for cloud '${current_cloud}'" - echo "INFO: check the valid settings for Terraform environment here: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#environment" - exit 1 -fi diff --git a/src/scripts/util/checkforarmcredential.sh b/src/scripts/util/checkforarmcredential.sh deleted file mode 100755 index d3ad46356..000000000 --- a/src/scripts/util/checkforarmcredential.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# validate that ARM_CLIENT_ID and ARM_CLIENT_SECRET environment variables are set - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "checkforarmcredential.sh: validate that ARM_CLIENT_ID and ARM_CLIENT_SECRET environment variables are set" - error_log "usage: checkforarmcredential.sh " -} - -if [[ "$#" -lt 1 ]]; then - usage - exit 1 -fi - -error_message=$1 - -if [[ -z $ARM_CLIENT_ID || -z $ARM_CLIENT_SECRET ]]; then - error_log "${error_message}" - echo "INFO: You can set these environment variables with 'export ARM_CLIENT_ID=\"YOUR_CLIENT_ID\"' and 'export ARM_CLIENT_SECRET=\"YOUR_CLIENT_SECRET\"'" - exit 1 -fi - -sp_exists="az ad sp show --id ${ARM_CLIENT_ID}" - -if ! $sp_exists &> /dev/null; then - error_log "ERROR: unable to find a Service Principal with Client ID ${ARM_CLIENT_ID}!" - echo "INFO: check the value of the environment variable \$ARM_CLIENT_ID and try 'az ad sp show --id \$ARM_CLIENT_ID' to inspect results..." - exit 1 -fi diff --git a/src/scripts/util/checkforazcli.sh b/src/scripts/util/checkforazcli.sh deleted file mode 100755 index abed1df50..000000000 --- a/src/scripts/util/checkforazcli.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -set -e - -# Check for Azure CLI -if ! command -v az &> /dev/null; then - echo "az could not be found. This script requires the Azure CLI." - echo "see https://docs.microsoft.com/en-us/cli/azure/install-azure-cli for installation instructions." - exit 1 -fi - -# Check for Azure CLI account -if ! az account show &> /dev/null; then - echo "Please login to Azure CLI before running this script." - echo "To set the cloud: az cloud set --name " - echo "To login as a Service Principal: az login --service-principal -u --password= --tenant --allow-no-subscriptions" - echo "To login interactively: az login --username " - exit 1 -fi diff --git a/src/scripts/util/checkforfile.sh b/src/scripts/util/checkforfile.sh deleted file mode 100755 index 06fa46cfb..000000000 --- a/src/scripts/util/checkforfile.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# -# Check for an empty or missing file and return an error - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "checkforfile.sh: Check for an empty or missing file and return an error" - error_log "usage: checkforfile.sh " -} - -if [[ "$#" -lt 2 ]]; then - usage - exit 1 -fi - -file_path=$1 -error_message=$2 - -if [[ ! -s "${file_path}" ]]; then - error_log "${error_message}" - exit 1 -fi \ No newline at end of file diff --git a/src/scripts/util/checkforterraform.sh b/src/scripts/util/checkforterraform.sh deleted file mode 100755 index 1d040cc3c..000000000 --- a/src/scripts/util/checkforterraform.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -set -e - -# Check for Terraform -if ! command -v terraform &> /dev/null; then - echo "terraform could not be found. This script requires the Terraform CLI." - echo "see https://learn.hashicorp.com/tutorials/terraform/install-cli for installation instructions." - exit 1 -fi \ No newline at end of file diff --git a/src/scripts/util/checkforzip.sh b/src/scripts/util/checkforzip.sh deleted file mode 100755 index 28f703240..000000000 --- a/src/scripts/util/checkforzip.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -set -e - -# Check for zip -if ! command -v zip &> /dev/null; then - echo "zip could not be found. This script requires zip." - echo "On debian based distributions you can try this to install it: sudo apt install zip" - exit 1 -fi diff --git a/src/scripts/util/validateazlocation.sh b/src/scripts/util/validateazlocation.sh deleted file mode 100755 index bab3537fa..000000000 --- a/src/scripts/util/validateazlocation.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# validate that a given location is present in a user's cloud - -set -e - -error_log() { - echo "${1}" 1>&2; -} - -usage() { - echo "validateazlocation.sh: validate that a given location is present in a user's cloud" - error_log "usage: validateazlocation.sh eastus" -} - -this_script_path=$(realpath "${BASH_SOURCE%/*}") - -# check for dependencies -"${this_script_path}/checkforazcli.sh" - -# inspect user input -if [[ "$#" -lt 1 ]]; then - usage - exit 1 -fi - -location=$1 - -current_cloud=$(az cloud show --query name --output tsv) -current_sub=$(az account show --query id --output tsv) -valid_locations=$(az account list-locations --query [].name --output tsv) - -# if the active subscription does not support the given location, throw an error and exit -if ! echo "$valid_locations" | grep -iwq "${location}"; then - error_log "ERROR: could not find region '${location}' for subscription of '${current_sub}' in current cloud '${current_cloud}' " - echo "INFO: is this a valid region? Try 'az account list-locations' to see what regions are available to you." - echo "INFO: do you have the correct cloud set? Try 'az cloud set' to set it." - exit 1 -fi diff --git a/src/terraform/README.md b/src/terraform/README.md new file mode 100644 index 000000000..7212dfad8 --- /dev/null +++ b/src/terraform/README.md @@ -0,0 +1,353 @@ +# Mission LZ Terraform + +Mission LZ also deploys the Hub and Spoke network architecture using [Terraform](https://www.terraform.io/). + +To get started with Terraform on Azure check out their useful tutorial: + +Once you're comfortable with Terraform, ensure you have the [Prerequisites](#Prerequisites) below and follow the instructions to deploy and clean-up Mission LZ. + +## High-Level Steps + +From a birds-eye view, we're going to deploy the core Mission LZ deployment of the Hub, Tier 0 (Identity), Tier 1 (Operations), and Tier 2 (Shared Services) networks and supporting resources, followed by a new spoke network/Tier 3. The commands we'll execute along the way will look something like this: + +```bash +cd src/terraform/mlz +terraform init +terraform apply # supply some parameters, approve, copy the output values +cd src/terraform/tier3 +terraform init +terraform apply # supply some parameters, approve +``` + +Read on to understand the [prerequisites](#Prerequisistes), how to get started, and how to optionally [configure your deployment for use in other clouds](#Deploying-to-Other-Clouds) or [deploy with a Service Principal](#Deploying-with-a-Service-Principal). + +## Prerequisistes + +* Current version of the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) +* The version of the [Terraform CLI](https://www.terraform.io/downloads.html) described in the [.devcontainer Dockerfile](../../../.devcontainer/Dockerfile) +* An Azure Subscription(s) where you or an identity you manage has `Owner` [RBAC permissions](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner) + +Deploying to a Cloud other than Azure Commercial? This requires updating the `azurerm` provider block `environment` and `metadata_host` values. Checkout the [Deploying to Other Clouds](#Deploying-to-Other-Clouds) documentation. + +### Login to Azure CLI + +1. Log in using the Azure CLI + + ```BASH + az login + ``` + + > *(Optional)* If you needed to deploy into another cloud such as Azure Government, set the cloud name before logging in: + + ```BASH + az cloud set -n AzureUSGovernment + az login + ``` + +1. (OPTIONAL) Deploying with a Service Principal? This requires updating the `azurerm` provider block. Check out the [Deploying with a Service Principal](#Deploying-with-a-Service-Principal) documentation. + +## Deploy Mission LZ + +### Terraform init + +Before provisioning any Azure resources with Terraform you must initialize a working directory. + +Here's the docs on `terraform init`: + +1. Navigate to the directory in the repository that contains the MissionLZ Terraform module: + + ```bash + cd src/terraform/mlz + ``` + +1. Execute `terraform init` + + ```bash + terraform init + ``` + +### Terraform apply + +After intializing the directory, use `terraform apply` to provision the resources described in `mlz/main.tf` and its referenced modules at `mlz/modules/*`. + +> Looking to deploy this new spoke in a cloud other than `AzureCloud`, say `AzureUsGovernment`? Follow the guidance at [Deploying to Other Clouds](#Deploying-to-Other-Clouds) to set the correct variables for the deployment. + +Here's the docs on `terraform apply`: + +When you run `terraform apply`, by default, Terraform will inspect the state of your environment to determine what resource creation, modification, or deletion needs to occur as if you invoked a `terraform plan` and then prompt you for your approval before taking action. + +Here's the docs on `terraform plan`: + +1. From the directory in which you executed `terraform init` execute `terraform apply`: + + ```bash + terraform apply + ``` + +1. You'll be prompted for a subscription ID. Supply the subscription ID you want to use for the Hub network: + + ```plaintext + > terraform apply + var.hub_subid + Subscription ID for the deployment + + Enter a value: + ``` + +1. Terraform will then inspect the state of your Azure environment and compare it with what is described in the Mission LZ Terraform module. Eventually, you'll be prompted for your approval to create, modify, or destroy resources. Supply `yes`: + + ```plaintext + Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: yes + ``` + +1. The deployment will begin. These commands will deploy all of the resources that make up Mission LZ. Deployment could take up to 45 minutes. + +If you'd like to deploy from Terraform over-and-over again with the same resource names and environment values, follow the docs on using [Terraform Destroy](#Terraform-destroy) to clean-up your environment. + +#### Apply Complete + +When it's complete, you'll see some output values that will be necessary if you want to stand up new spoke, or Tier 3, networks: + +```plaintext +Apply complete! Resources: 99 added, 0 changed, 0 destroyed. + +Outputs: + +firewall_private_ip = "10.0.100.4" +hub_rgname = "hub-rg" +hub_subid = "{the Hub subscription ID}" +hub_vnetname = "hub-vnet" +laws_name = "{the name of the Log Analytics Workspace}" +laws_rgname = "operations-rg" +tier1_subid = "{the Tier 1 subscription ID}" +``` + +Interested in standing up new spoke networks, or Tier 3 environments, after a deployment? See [Deploying New Spoke Networks](#Deploying-New-Spoke-Networks) + +### Terraform destroy + +Once you're happy with the deployment output and want to modify Mission LZ or just want to tear it down to save on costs, you can use `terraform destroy`. + +Here's the docs on `terraform destroy`: + +1. From the directory in which you executed `terraform init` and `terraform apply` execute `terraform destroy`: + + ```bash + terraform destroy + ``` + +1. You'll be prompted for a subscription ID. Supply the subscription ID you want to used previously: + + ```plaintext + > terraform destroy + var.hub_subid + Subscription ID for the deployment + + Enter a value: + ``` + +1. Terraform will then inspect the state of your Azure environment and compare it with what is described in Terraform state. Eventually, you'll be prompted for your approval to destroy resources. Supply `yes`: + + ```plaintext + Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: yes + ``` + +This command will attempt to remove all the resources that were created by `terraform apply` and could take up to 45 minutes. + +## Deploying new Spoke Networks + +Once you've deployed Mission LZ, you can use the Tier 3 module to deploy and peer new Spoke Networks and workloads to the Hub and Firewall. + +>Looking to deploy this new spoke in a cloud other than `AzureCloud`, say `AzureUsGovernment`? Follow the guidance at [Deploying to Other Clouds](#Deploying-to-Other-Clouds) to set the correct variables for the deployment. + +1. Navigate to the directory in the repository that contains the MissionLZ Tier 3 Terraform module: + + ```bash + cd src/terraform/tier3 + ``` + +1. Execute `terraform init` + + ```bash + terraform init + ``` + +1. Execute `terraform apply`: + + ```bash + terraform apply + ``` + +1. You'll be prompted for environment values for resources deployed by the core Mission LZ deployment for: 1) the Hub Firewall, 2) the Log Analytics Workspace resources and 3) the desired subscription ID for the new spoke network/Tier 3: + + ```plaintext + > terraform apply + var.firewall_private_ip + Firewall IP to bind network to + + Enter a value: 10.0.100.4 + + var.hub_rgname + Resource Group for the Hub deployment + + Enter a value: hub-rg + + var.hub_subid + Subscription ID for the Hub deployment + + Enter a value: {the Hub subscription ID} + + var.hub_vnetname + Virtual Network Name for the Hub deployment + + Enter a value: hub-vnet + + var.laws_name + Log Analytics Workspace Name for the deployment + + Enter a value: {the name of the Log Analytics Workspace} + + var.laws_rgname + The resource group that Log Analytics Workspace was deployed to + + Enter a value: operations-rg + + var.tier1_subid + Subscription ID for the Tier 1 deployment + + Enter a value: {the Tier 1 subscription ID} + + var.tier3_subid + Subscription ID for this Tier 3 deployment + + Enter a value: {the Tier 3 subscription ID} + ``` + + You get these values when `terraform apply` is complete for the core Mission LZ deployment. See the [Apply Complete](#Apply-Complete) section for what these values look like. You can also source the values after a successful core Mission LZ deployment by inspecting the `outputs` object in the Terraform state file. By default that state file is at `src/terraform/mlz/terraform.tfstate`. + +1. Terraform will then inspect the state of your Azure environment and compare it with what is described in the Tier 3 Terraform module. Eventually, you'll be prompted for your approval to create, modify, or destroy resources. Supply `yes`: + + ```plaintext + Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: yes + ``` + +When this Tier 3 network has served its purpose, you can follow the same steps in [Terraform destroy](#Terraform-destroy) to remove the provisioned resources. + +## Deploying with a Service Principal + +This is not required, in fact, the current Terraform modules are written as if you're executing them as a user. + +But, if you're using a Service Principal to deploy Azure resources with Terraform check out this doc: + +Using a Service Principal will require updating the resource providers for `mlz/main.tf`, also described in that doc: : + +```terraform +variable "client_secret" { +} + +terraform { + required_providers { + azurerm = { + ... + } + } +} + +provider "azurerm" { + features {} + + subscription_id = "00000000-0000-0000-0000-000000000000" + client_id = "00000000-0000-0000-0000-000000000000" + client_secret = var.client_secret + tenant_id = "00000000-0000-0000-0000-000000000000" +} +``` + +## Terraform Providers + +The development container definition downloads the required Terraform plugin providers during the container build so that the container can be transported to an air-gapped network for use. The container also sets the `TF_PLUGIN_CACHE_DIR` environment variable, which Terraform uses as the search location for locally installed providers. If you are not using the container to deploy or if the `TF_PLUGIN_CACHE_DIR` environment variable is not set, Terraform will automatically attempt to download the provider from the internet when you execute the `terraform init` command. + +See the development container [README](/.devcontainer/README.md) for more details on building and running the container. + +## Terraform Backends + +The default templates write a state file directly to disk locally to where you are executing terraform from. If you wish to change the output directory you can set the path directly in the terraform backend block located in the main.tf file via the path variable in the backend configuration block. + +```terraform +terraform { + backend "local" { + path = "relative/path/to/terraform.tfstate" + } + + required_version = ">= 1.0.3" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "= 2.71.0" + } + random = { + source = "hashicorp/random" + version = "= 3.1.0" + } + time = { + source = "hashicorp/time" + version = "0.7.2" + } + } +} +``` + +To find more information about setting the backend see [Local Backend](https://www.terraform.io/docs/language/settings/backends/local.html), if you wish to AzureRM backend please see [AzureRM Backend](https://www.terraform.io/docs/language/settings/backends/azurerm.html) + +## Deploying to Other Clouds + +The `azurerm` Terraform provider provides a mechanism for changing the Azure cloud in which to deploy Terraform modules. + +If you want to deploy to another cloud, pass in the correct value for `environment`, `metadata_host`, and `location` for the cloud you're targeting to the relevant module's variables file [mlz/variables.tf](../../terraform/mlz/variables.tf) or [tier3/variables.tf](../../terraform/tier3/variables.tf): + +```terraform +variable "environment" { + description = "The Terraform backend environment e.g. public or usgovernment" + type = string + default = "usgovernment" +} + +variable "metadata_host" { + description = "The metadata host for the Azure Cloud e.g. management.azure.com" + type = string + default = "management.usgovcloudapi.net" +} + +variable "location" { + description = "The Azure region for most Mission LZ resources" + type = string + default = "usgovvirginia" +} +``` + +```terraform +provider "azurerm" { + features {} + + environment = var.environment # e.g. 'public' or 'usgovernment' + metadata_host = var.metadata_host # e.g. 'management.azure.com' or 'management.usgovcloudapi.net' +} +``` + +For the supported `environment` values, see this doc: + +For the supported `metadata_host` values, see this doc: + +For more endpoint mappings between AzureCloud and AzureUsGovernment: diff --git a/src/terraform/mlz/main.tf b/src/terraform/mlz/main.tf index 4c7ec6998..7e99bff05 100644 --- a/src/terraform/mlz/main.tf +++ b/src/terraform/mlz/main.tf @@ -21,8 +21,8 @@ terraform { } provider "azurerm" { - environment = var.tf_environment - metadata_host = var.mlz_metadatahost + environment = var.environment + metadata_host = var.metadata_host subscription_id = var.hub_subid features { @@ -37,8 +37,8 @@ provider "azurerm" { provider "azurerm" { alias = "hub" - environment = var.tf_environment - metadata_host = var.mlz_metadatahost + environment = var.environment + metadata_host = var.metadata_host subscription_id = var.hub_subid features { @@ -53,9 +53,9 @@ provider "azurerm" { provider "azurerm" { alias = "tier0" - environment = var.tf_environment - metadata_host = var.mlz_metadatahost - subscription_id = var.tier0_subid + environment = var.environment + metadata_host = var.metadata_host + subscription_id = coalesce(var.tier0_subid, var.hub_subid) features { log_analytics_workspace { @@ -69,9 +69,9 @@ provider "azurerm" { provider "azurerm" { alias = "tier1" - environment = var.tf_environment - metadata_host = var.mlz_metadatahost - subscription_id = var.tier1_subid + environment = var.environment + metadata_host = var.metadata_host + subscription_id = coalesce(var.tier1_subid, var.hub_subid) features { log_analytics_workspace { @@ -85,9 +85,9 @@ provider "azurerm" { provider "azurerm" { alias = "tier2" - environment = var.tf_environment - metadata_host = var.mlz_metadatahost - subscription_id = var.tier2_subid + environment = var.environment + metadata_host = var.metadata_host + subscription_id = coalesce(var.hub_subid, var.tier2_subid) features { log_analytics_workspace { @@ -105,13 +105,16 @@ provider "random" { provider "time" { } +data "azurerm_client_config" "current_client" { +} + ################################ ### GLOBAL VARIABLES ### ################################ locals { - # azurerm terraform environments where Azure Firewall Premium is supported - firewall_premium_tf_environments = ["public"] + firewall_premium_environments = ["public"] # terraform azurerm environments where Azure Firewall Premium is supported + deploymentname_default = "mlz-${formatdate("YYYYMMDD'T'hhmmssZ", timestamp())}" } ################################ @@ -121,44 +124,44 @@ locals { resource "azurerm_resource_group" "hub" { provider = azurerm.hub - location = var.mlz_location + location = var.location name = var.hub_rgname tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } resource "azurerm_resource_group" "tier0" { provider = azurerm.tier0 - location = var.mlz_location + location = var.location name = var.tier0_rgname tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } resource "azurerm_resource_group" "tier1" { provider = azurerm.tier1 - location = var.mlz_location + location = var.location name = var.tier1_rgname tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } resource "azurerm_resource_group" "tier2" { provider = azurerm.tier2 - location = var.mlz_location + location = var.location name = var.tier2_rgname tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -178,14 +181,14 @@ resource "azurerm_log_analytics_workspace" "laws" { provider = azurerm.tier1 depends_on = [random_id.laws] - name = format("%.24s", lower(replace("${var.mlz_lawsname}${random_id.laws.hex}", "/[[:^alnum:]]/", ""))) - resource_group_name = var.tier1_rgname - location = var.mlz_location + name = coalesce(var.log_analytics_workspace_name, format("%.24s", lower(replace("logAnalyticsWorkspace${random_id.laws.hex}", "/[[:^alnum:]]/", "")))) + resource_group_name = azurerm_resource_group.tier1.name + location = var.location sku = "PerGB2018" retention_in_days = "30" tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -205,7 +208,7 @@ resource "azurerm_log_analytics_solution" "laws_sentinel" { } tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -218,7 +221,7 @@ module "hub-network" { depends_on = [azurerm_resource_group.hub] source = "../modules/hub" - location = var.mlz_location + location = var.location resource_group_name = var.hub_rgname vnet_name = var.hub_vnetname vnet_address_space = var.hub_vnet_address_space @@ -228,7 +231,7 @@ module "hub-network" { log_analytics_workspace_resource_id = azurerm_log_analytics_workspace.laws.id tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -239,13 +242,13 @@ module "firewall" { sub_id = var.hub_subid resource_group_name = module.hub-network.resource_group_name - location = var.mlz_location + location = var.location vnet_name = module.hub-network.virtual_network_name vnet_address_space = module.hub-network.virtual_network_address_space client_address_space = var.hub_client_address_space firewall_name = var.firewall_name - firewall_sku = contains(local.firewall_premium_tf_environments, lower(var.tf_environment)) ? "Premium" : "Standard" + firewall_sku = contains(local.firewall_premium_environments, lower(var.environment)) ? "Premium" : "Standard" firewall_client_subnet_name = module.hub-network.firewall_client_subnet_name firewall_management_subnet_name = module.hub-network.firewall_management_subnet_name firewall_policy_name = var.firewall_policy_name @@ -259,7 +262,7 @@ module "firewall" { log_analytics_workspace_resource_id = azurerm_log_analytics_workspace.laws.id tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -272,7 +275,7 @@ module "spoke-network-t0" { firewall_private_ip = module.firewall.firewall_private_ip - laws_location = var.mlz_location + laws_location = var.location laws_workspace_id = azurerm_log_analytics_workspace.laws.workspace_id laws_resource_id = azurerm_log_analytics_workspace.laws.id @@ -282,7 +285,7 @@ module "spoke-network-t0" { subnets = var.tier0_subnets tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -319,7 +322,7 @@ module "spoke-network-t1" { firewall_private_ip = module.firewall.firewall_private_ip - laws_location = var.mlz_location + laws_location = var.location laws_workspace_id = azurerm_log_analytics_workspace.laws.workspace_id laws_resource_id = azurerm_log_analytics_workspace.laws.id @@ -329,7 +332,7 @@ module "spoke-network-t1" { subnets = var.tier1_subnets tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -366,7 +369,7 @@ module "spoke-network-t2" { firewall_private_ip = module.firewall.firewall_private_ip - laws_location = var.mlz_location + laws_location = var.location laws_workspace_id = azurerm_log_analytics_workspace.laws.workspace_id laws_resource_id = azurerm_log_analytics_workspace.laws.id @@ -376,7 +379,7 @@ module "spoke-network-t2" { subnets = var.tier2_subnets tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -420,7 +423,7 @@ module "jumpbox-subnet" { source = "../modules/subnet" name = var.jumpbox_subnet.name - location = var.mlz_location + location = var.location resource_group_name = var.hub_rgname virtual_network_name = var.hub_vnetname address_prefixes = var.jumpbox_subnet.address_prefixes @@ -437,11 +440,11 @@ module "jumpbox-subnet" { log_analytics_storage_id = module.hub-network.log_analytics_storage_id log_analytics_workspace_id = azurerm_log_analytics_workspace.laws.workspace_id - log_analytics_workspace_location = var.mlz_location + log_analytics_workspace_location = var.location log_analytics_workspace_resource_id = azurerm_log_analytics_workspace.laws.id tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -460,7 +463,7 @@ module "bastion-host" { ipconfig_name = var.bastion_ipconfig_name tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -474,10 +477,12 @@ module "jumpbox" { resource_group_name = var.hub_rgname virtual_network_name = var.hub_vnetname subnet_name = var.jumpbox_subnet.name - location = var.mlz_location + location = var.location keyvault_name = var.jumpbox_keyvault_name - object_id = var.mlz_objectid + + tenant_id = data.azurerm_client_config.current_client.tenant_id + object_id = data.azurerm_client_config.current_client.object_id windows_name = var.jumpbox_windows_vm_name windows_size = var.jumpbox_windows_vm_size @@ -494,6 +499,6 @@ module "jumpbox" { linux_image_version = var.jumpbox_linux_vm_version tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } diff --git a/src/terraform/mlz/minimum.tfvars.sample b/src/terraform/mlz/minimum.tfvars.sample deleted file mode 100644 index 501dee6aa..000000000 --- a/src/terraform/mlz/minimum.tfvars.sample +++ /dev/null @@ -1,19 +0,0 @@ -tf_environment = "" -deploymentname = "" -mlz_location = "" -mlz_metadatahost = "" -mlz_objectid = "" - -hub_subid = "" -hub_rgname = "" -hub_vnetname = "" -tier0_subid = "" -tier0_rgname = "" -tier0_vnetname = "" -tier1_subid = "" -tier1_rgname = "" -tier1_vnetname = "" -mlz_lawsname = "" -tier2_subid = "" -tier2_rgname = "" -tier2_vnetname = "" diff --git a/src/terraform/mlz/mlz.tfvars.sample b/src/terraform/mlz/mlz.tfvars.sample deleted file mode 100644 index 5f9920f2a..000000000 --- a/src/terraform/mlz/mlz.tfvars.sample +++ /dev/null @@ -1,248 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -################################# -# Global Configuration -################################# - -tf_environment ="{TF_ENVIRONMENT}" -deploymentname ="{DEPLOYMENTNAME}" -mlz_location ="{MLZ_LOCATION}" -mlz_metadatahost ="{MLZ_METADATAHOST}" -mlz_objectid ="{MLZ_OBJECTID}" - -################################# -# Hub Configuration -################################# - -hub_subid = "{HUB_SUBID}" -hub_rgname = "{HUB_RGNAME}" -hub_vnetname = "{HUB_VNETNAME}" -hub_vnet_address_space = ["{HUB_VNET_ADDRESS_SPACE}"] -hub_client_address_space = "{HUB_CLIENT_ADDRESS_SPACE}" -hub_management_address_space = "{HUB_MANAGEMENT_ADDRESS_SPACE}" - -################################# -# Firewall configuration section -################################# - -firewall_name = "{FIREWALL_NAME}" -firewall_policy_name = "{FIREWALL_POLICY_NAME}" -client_ipconfig_name = "{CLIENT_IPCONFIG_NAME}" -client_publicip_name = "{CLIENT_PUBLICIP_NAME}" -management_ipconfig_name = "{MANAGEMENT_IPCONFIG_NAME}" -management_publicip_name = "{MANAGEMENT_PUBLICIP_NAME}" - -################################# -# Bastion Host Configuration -################################# - -create_bastion_jumpbox = "{CREATE_BASTION_JUMPBOX}" -bastion_host_name = "{BASTION_HOST_NAME}" -bastion_address_space = "{BASTION_ADDRESS_SPACE}" -bastion_public_ip_name = "{BASTION_PUBLIC_IP_NAME}" -bastion_ipconfig_name = "{BASTION_IPCONFIG_NAME}" - -################################# -# Jumpbox VM Configuration -################################# - -jumpbox_subnet = { - name = "{JUMPBOX_SUBNET_NAME}" - address_prefixes = ["{JUMPBOX_SUBNET_SPACE}"] - service_endpoints = ["Microsoft.Storage"] - - enforce_private_link_endpoint_network_policies = false - enforce_private_link_service_network_policies = false - - nsg_name = "{JUMPBOX_SUBNET_NSG_NAME}" - nsg_rules = { - "allow_ssh" = { - name = "allow_ssh" - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "22" - destination_port_range = "" - source_address_prefix = "*" - destination_address_prefix = "" - } - "allow_rdp" = { - name = "allow_rdp" - priority = "200" - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "3389" - destination_port_range = "" - source_address_prefix = "*" - destination_address_prefix = "" - } - } - - routetable_name = "{JUMPBOX_SUBNET_RT_NAME}" -} - -jumpbox_keyvault_name = "{JUMPBOX_KEYVAULT_NAME}" -jumpbox_windows_vm_name = "{JUMPBOX_WINDOWS_VM_NAME}" -jumpbox_windows_vm_size = "{JUMPBOX_WINDOWS_VM_SIZE}" -jumpbox_windows_vm_publisher = "{JUMPBOX_WINDOWS_VM_PUBLISHER}" -jumpbox_windows_vm_offer = "{JUMPBOX_WINDOWS_VM_OFFER}" -jumpbox_windows_vm_sku = "{JUMPBOX_WINDOWS_VM_SKU}" -jumpbox_windows_vm_version = "{JUMPBOX_WINDOWS_VM_VERSION}" -jumpbox_linux_vm_name = "{JUMPBOX_LINUX_VM_NAME}" -jumpbox_linux_vm_size = "{JUMPBOX_LINUX_VM_SIZE}" -jumpbox_linux_vm_publisher = "{JUMPBOX_LINUX_VM_PUBLISHER}" -jumpbox_linux_vm_offer = "{JUMPBOX_LINUX_VM_OFFER}" -jumpbox_linux_vm_sku = "{JUMPBOX_LINUX_VM_SKU}" -jumpbox_linux_vm_version = "{JUMPBOX_LINUX_VM_VERSION}" - -################################# -# Tier 0 Configuration -################################# - -tier0_subid = "{TIER0_SUBID}" -tier0_rgname = "{TIER0_RGNAME}" -tier0_vnetname = "{TIER0_VNETNAME}" - -tier0_vnet_address_space = ["{TIER0_VNET_ADDRESS_SPACE}"] - -tier0_subnets = { - "{TIER0_SUBNETVM_NAME}" = { - name = "{TIER0_SUBNETVM_NAME}" - address_prefixes = ["{TIER0_SUBNETVM_ADDRESSPREFIXLIST}"] - service_endpoints = ["{TIER0_SUBNETVM_SERVICEENDPOINTLIST}"] - - enforce_private_link_endpoint_network_policies = {TIER0_SUBNETVM_ENABLEPRIVATELINKENDPOINT} - enforce_private_link_service_network_policies = {TIER0_SUBNETVM_ENABLEPRIVATELINKSERVICE} - - nsg_name = "{TIER0_SUBNETVM_NSGNAME}" - nsg_rules = { - "allow_ssh" = { - name = "allow_ssh" - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "" - } - "allow_rdp" = { - name = "allow_rdp" - priority = "200" - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "" - } - } - - routetable_name = "{TIER0_SUBNETVM_RTNAME}" - } -} - -################################# -# Tier 1 Network configuration section -################################# - -tier1_subid = "{TIER1_SUBID}" -tier1_rgname = "{TIER1_RGNAME}" -tier1_vnetname = "{TIER1_VNETNAME}" -mlz_lawsname = "{MLZ_LAWSNAME} -create_sentinel = "{CREATE_SENTINEL}" - -tier1_vnet_address_space = ["{TIER1_VNET_ADDRESS_SPACE}"] - -tier1_subnets = { - "{TIER1_SUBNETVM_NAME}" = { - name = "{TIER1_SUBNETVM_NAME}" - address_prefixes = ["{TIER1_SUBNETVM_ADDRESSPREFIXLIST}"] - service_endpoints = ["{TIER1_SUBNETVM_SERVICEENDPOINTLIST}"] - - enforce_private_link_endpoint_network_policies = {TIER1_SUBNETVM_ENABLEPRIVATELINKENDPOINT} - enforce_private_link_service_network_policies = {TIER1_SUBNETVM_ENABLEPRIVATELINKSERVICE} - - nsg_name = "{TIER1_SUBNETVM_NSGNAME}" - nsg_rules = { - "allow_ssh" = { - name = "allow_ssh" - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "" - } - "allow_rdp" = { - name = "allow_rdp" - priority = "200" - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "" - } - } - - routetable_name = "{TIER1_SUBNETVM_RTNAME}" - } -} - -################################# -# Tier 2 Network configuration section -################################# - -tier2_subid = "{TIER2_SUBID}" -tier2_rgname = "{TIER2_RGNAME}" -tier2_vnetname = "{TIER2_VNETNAME}" - -tier2_vnet_address_space = ["{TIER2_VNET_ADDRESS_SPACE}"] - -tier2_subnets = { - "{TIER2_SUBNETVM_NAME}" = { - name = "{TIER2_SUBNETVM_NAME}" - address_prefixes = ["{TIER2_SUBNETVM_ADDRESSPREFIXLIST}"] - service_endpoints = ["{TIER2_SUBNETVM_SERVICEENDPOINTLIST}"] - - enforce_private_link_endpoint_network_policies = {TIER2_SUBNETVM_ENABLEPRIVATELINKENDPOINT} - enforce_private_link_service_network_policies = {TIER2_SUBNETVM_ENABLEPRIVATELINKSERVICE} - - nsg_name = "{TIER2_SUBNETVM_NSGNAME}" - nsg_rules = { - "allow_ssh" = { - name = "allow_ssh" - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "" - } - "allow_rdp" = { - name = "allow_rdp" - priority = "200" - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "" - } - } - - routetable_name = "{TIER2_SUBNETVM_RTNAME}" - } -} diff --git a/src/terraform/mlz/output.tf b/src/terraform/mlz/output.tf deleted file mode 100644 index e55bed72c..000000000 --- a/src/terraform/mlz/output.tf +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -output "laws_name" { - description = "LAWS Name" - value = azurerm_log_analytics_workspace.laws.name -} - -output "laws_rgname" { - description = "Resource Group for Laws" - value = azurerm_log_analytics_workspace.laws.resource_group_name -} - -output "firewall_private_ip" { - description = "Firewall private IP" - value = module.firewall.firewall_private_ip -} diff --git a/src/terraform/mlz/outputs.tf b/src/terraform/mlz/outputs.tf new file mode 100644 index 000000000..c1e1282da --- /dev/null +++ b/src/terraform/mlz/outputs.tf @@ -0,0 +1,37 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +output "hub_subid" { + description = "Subscription ID where the Hub Resource Group is provisioned" + value = var.hub_subid +} + +output "hub_rgname" { + description = "The Hub Resource Group name" + value = azurerm_resource_group.hub.name +} + +output "hub_vnetname" { + description = "The Hub Virtual Network name" + value = module.hub-network.virtual_network_name +} + +output "firewall_private_ip" { + description = "Firewall private IP" + value = module.firewall.firewall_private_ip +} + +output "tier1_subid" { + description = "Subscription ID where the Tier 1 Resource Group is provisioned" + value = coalesce(var.tier1_subid, var.hub_subid) +} + +output "laws_name" { + description = "LAWS Name" + value = azurerm_log_analytics_workspace.laws.name +} + +output "laws_rgname" { + description = "Resource Group for Laws" + value = azurerm_log_analytics_workspace.laws.resource_group_name +} diff --git a/src/terraform/mlz/variables.tf b/src/terraform/mlz/variables.tf index 0a128bbbb..902b08833 100644 --- a/src/terraform/mlz/variables.tf +++ b/src/terraform/mlz/variables.tf @@ -5,24 +5,28 @@ # Global Configuration ################################# -variable "tf_environment" { +variable "environment" { description = "The Terraform backend environment e.g. public or usgovernment" + type = string + default = "public" } -variable "deploymentname" { - description = "A name for the deployment" +variable "metadata_host" { + description = "The metadata host for the Azure Cloud e.g. management.azure.com" + type = string + default = "management.azure.com" } -variable "mlz_location" { +variable "location" { description = "The Azure region for most Mission LZ resources" + type = string + default = "East US" } -variable "mlz_metadatahost" { - description = "The metadata host for the Azure Cloud e.g. management.azure.com" -} - -variable "mlz_objectid" { - description = "The account to deploy with" +variable "deploymentname" { + description = "A name for the deployment" + type = string + default = "" } ################################# @@ -31,20 +35,25 @@ variable "mlz_objectid" { variable "hub_subid" { description = "Subscription ID for the deployment" + type = string } variable "hub_rgname" { description = "Resource Group for the deployment" + type = string + default = "hub-rg" } variable "hub_vnetname" { description = "Virtual Network Name for the deployment" + type = string + default = "hub-vnet" } variable "hub_vnet_address_space" { description = "The address space to be used for the virtual network." - default = ["10.0.100.0/24"] type = list(string) + default = ["10.0.100.0/24"] } ################################# @@ -53,44 +62,50 @@ variable "hub_vnet_address_space" { variable "hub_client_address_space" { description = "The address space to be used for the Firewall virtual network." - default = "10.0.100.0/26" type = string + default = "10.0.100.0/26" } variable "hub_management_address_space" { description = "The address space to be used for the Firewall virtual network subnet used for management traffic." - default = "10.0.100.64/26" type = string + default = "10.0.100.64/26" } variable "firewall_name" { description = "Name of the Hub Firewall" - default = "mlzFirewall" + type = string + default = "firewall" } variable "firewall_policy_name" { description = "Name of the firewall policy to apply to the hub firewall" - default = "firewallpolicy" + type = string + default = "firewall-policy" } variable "client_ipconfig_name" { description = "The name of the Firewall Client IP Configuration" - default = "mlzFWClientIpCfg" + type = string + default = "firewall-client-ip-config" } variable "client_publicip_name" { description = "The name of the Firewall Client Public IP" - default = "mlzFWClientPip" + type = string + default = "firewall-client-public-ip" } variable "management_ipconfig_name" { description = "The name of the Firewall Management IP Configuration" - default = "mlzFWMgmtIpCfg" + type = string + default = "firewall-management-ip-config" } variable "management_publicip_name" { description = "The name of the Firewall Management Public IP" - default = "mlzFWMgmtPip" + type = string + default = "firewall-management-public-ip" } ################################# @@ -105,26 +120,26 @@ variable "create_bastion_jumpbox" { variable "bastion_host_name" { description = "The name of the Bastion Host" - default = "mlzBastionHost" type = string + default = "bastionHost" } variable "bastion_address_space" { description = "The address space to be used for the Bastion Host subnet (must be /27 or larger)." - default = "10.0.100.128/27" type = string + default = "10.0.100.128/27" } variable "bastion_public_ip_name" { description = "The name of the Bastion Host Public IP" - default = "mlzBastionHostPip" type = string + default = "bastionHostPublicIPAddress" } variable "bastion_ipconfig_name" { description = "The name of the Bastion Host IP Configuration" - default = "mlzBastionHostIpCfg" type = string + default = "bastionHostIPConfiguration" } ################################# @@ -157,14 +172,14 @@ variable "jumpbox_subnet" { routetable_name = string }) default = { - name = "mlzJumpboxSubnet" + name = "jumpbox-subnet" address_prefixes = ["10.0.100.160/27"] service_endpoints = ["Microsoft.Storage"] enforce_private_link_endpoint_network_policies = false enforce_private_link_service_network_policies = false - nsg_name = "mlzJumpboxSubnetNsg" + nsg_name = "jumpbox-subnet-nsg" nsg_rules = { "allow_ssh" = { name = "allow_ssh" @@ -190,86 +205,86 @@ variable "jumpbox_subnet" { } } - routetable_name = "mlzJumpboxSubnetRt" + routetable_name = "jumpbox-routetable" } } variable "jumpbox_keyvault_name" { description = "The name of the jumpbox virtual machine keyvault" - default = "mlzJumpboxVmKv" type = string + default = "jumpboxKeyvault" } variable "jumpbox_windows_vm_name" { description = "The name of the Windows jumpbox virtual machine" - default = "mlzJumpboxWindowsVm" type = string + default = "jumpboxWindowsVm" } variable "jumpbox_windows_vm_size" { description = "The size of the Windows jumpbox virtual machine" - default = "Standard_DS1_v2" type = string + default = "Standard_DS1_v2" } variable "jumpbox_windows_vm_publisher" { description = "The publisher of the Windows jumpbox virtual machine source image" - default = "MicrosoftWindowsServer" type = string + default = "MicrosoftWindowsServer" } variable "jumpbox_windows_vm_offer" { description = "The offer of the Windows jumpbox virtual machine source image" - default = "WindowsServer" type = string + default = "WindowsServer" } variable "jumpbox_windows_vm_sku" { description = "The SKU of the Windows jumpbox virtual machine source image" - default = "2019-datacenter-gensecond" type = string + default = "2019-datacenter-gensecond" } variable "jumpbox_windows_vm_version" { description = "The version of the Windows jumpbox virtual machine source image" - default = "latest" type = string + default = "latest" } variable "jumpbox_linux_vm_name" { description = "The name of the Linux jumpbox virtual machine" - default = "mlzJumpboxLinuxVm" type = string + default = "jumpboxLinuxVm" } variable "jumpbox_linux_vm_size" { description = "The size of the Linux jumpbox virtual machine" - default = "Standard_DS1_v2" type = string + default = "Standard_DS1_v2" } variable "jumpbox_linux_vm_publisher" { description = "The publisher of the Linux jumpbox virtual machine source image" - default = "Canonical" type = string + default = "Canonical" } variable "jumpbox_linux_vm_offer" { description = "The offer of the Linux jumpbox virtual machine source image" - default = "UbuntuServer" type = string + default = "UbuntuServer" } variable "jumpbox_linux_vm_sku" { description = "The SKU of the Linux jumpbox virtual machine source image" - default = "18.04-LTS" type = string + default = "18.04-LTS" } variable "jumpbox_linux_vm_version" { description = "The version of the Linux jumpbox virtual machine source image" - default = "latest" type = string + default = "latest" } ################################# @@ -278,14 +293,20 @@ variable "jumpbox_linux_vm_version" { variable "tier0_subid" { description = "Subscription ID for the deployment" + type = string + default = "" } variable "tier0_rgname" { description = "Resource Group for the deployment" + type = string + default = "identity-rg" } variable "tier0_vnetname" { description = "Virtual Network Name for the deployment" + type = string + default = "identity-vnet" } variable "tier0_vnet_address_space" { @@ -320,15 +341,15 @@ variable "tier0_subnets" { routetable_name = string })) default = { - "tier0vms" = { - name = "tier0vms" + "identitySubnet" = { + name = "identitySubnet" address_prefixes = ["10.0.110.0/27"] service_endpoints = ["Microsoft.Storage"] enforce_private_link_endpoint_network_policies = false enforce_private_link_service_network_policies = false - nsg_name = "tier0vmsnsg" + nsg_name = "identitySubnetNsg" nsg_rules = { "allow_ssh" = { name = "allow_ssh" @@ -354,7 +375,7 @@ variable "tier0_subnets" { } } - routetable_name = "tier0vmsrt" + routetable_name = "identityRouteTable" } } } @@ -365,18 +386,26 @@ variable "tier0_subnets" { variable "tier1_subid" { description = "Subscription ID for the deployment" + type = string + default = "" } variable "tier1_rgname" { description = "Resource Group for the deployment" + type = string + default = "operations-rg" } variable "tier1_vnetname" { description = "Virtual Network Name for the deployment" + type = string + default = "operations-vnet" } -variable "mlz_lawsname" { +variable "log_analytics_workspace_name" { description = "Log Analytics Workspace Name for the deployment" + type = string + default = "" } variable "create_sentinel" { @@ -417,15 +446,15 @@ variable "tier1_subnets" { routetable_name = string })) default = { - "tier1vms" = { - name = "tier1vms" + "operationsSubnet" = { + name = "operationsSubnet" address_prefixes = ["10.0.115.0/27"] service_endpoints = ["Microsoft.Storage"] enforce_private_link_endpoint_network_policies = false enforce_private_link_service_network_policies = false - nsg_name = "tier1vmsnsg" + nsg_name = "operationsSubnetNsg" nsg_rules = { "allow_ssh" = { name = "allow_ssh" @@ -451,7 +480,7 @@ variable "tier1_subnets" { } } - routetable_name = "tier1vmsrt" + routetable_name = "operationsRouteTable" } } } @@ -462,14 +491,20 @@ variable "tier1_subnets" { variable "tier2_subid" { description = "Subscription ID for the deployment" + type = string + default = "" } variable "tier2_rgname" { description = "Resource Group for the deployment" + type = string + default = "sharedServices-rg" } variable "tier2_vnetname" { description = "Virtual Network Name for the deployment" + type = string + default = "sharedServices-vnet" } variable "tier2_vnet_address_space" { @@ -504,15 +539,15 @@ variable "tier2_subnets" { routetable_name = string })) default = { - "tier2vms" = { - name = "tier2vms" + "sharedServicesSubnet" = { + name = "sharedServicesSubnet" address_prefixes = ["10.0.120.0/27"] service_endpoints = ["Microsoft.Storage"] enforce_private_link_endpoint_network_policies = false enforce_private_link_service_network_policies = false - nsg_name = "tier2vmsnsg" + nsg_name = "sharedServicesSubnetNsg" nsg_rules = { "allow_ssh" = { name = "allow_ssh" @@ -538,7 +573,7 @@ variable "tier2_subnets" { } } - routetable_name = "tier2vmsrt" + routetable_name = "sharedServicesRouteTable" } } } diff --git a/src/terraform/modules/subnet/main.tf b/src/terraform/modules/subnet/main.tf index b09553ed7..dee90276a 100644 --- a/src/terraform/modules/subnet/main.tf +++ b/src/terraform/modules/subnet/main.tf @@ -91,7 +91,7 @@ resource "azurerm_monitor_diagnostic_setting" "nsg" { resource "azurerm_network_watcher_flow_log" "nsgfl" { depends_on = [azurerm_network_security_rule.nsgrules, azurerm_network_security_group.nsg] - network_watcher_name = "NetworkWatcher_${var.location}" + network_watcher_name = "NetworkWatcher_${replace(var.location, " ", "")}" resource_group_name = "NetworkWatcherRG" network_security_group_id = azurerm_network_security_group.nsg.id diff --git a/src/terraform/tier3/main.tf b/src/terraform/tier3/main.tf index f85ec2fb7..fae3145ff 100644 --- a/src/terraform/tier3/main.tf +++ b/src/terraform/tier3/main.tf @@ -13,8 +13,8 @@ terraform { } provider "azurerm" { - environment = var.tf_environment - metadata_host = var.mlz_metadatahost + environment = var.environment + metadata_host = var.metadata_host subscription_id = var.hub_subid features { @@ -29,8 +29,8 @@ provider "azurerm" { provider "azurerm" { alias = "hub" - environment = var.tf_environment - metadata_host = var.mlz_metadatahost + environment = var.environment + metadata_host = var.metadata_host subscription_id = var.hub_subid features { @@ -45,8 +45,8 @@ provider "azurerm" { provider "azurerm" { alias = "tier1" - environment = var.tf_environment - metadata_host = var.mlz_metadatahost + environment = var.environment + metadata_host = var.metadata_host subscription_id = var.tier1_subid features { @@ -61,8 +61,8 @@ provider "azurerm" { provider "azurerm" { alias = "tier3" - environment = var.tf_environment - metadata_host = var.mlz_metadatahost + environment = var.environment + metadata_host = var.metadata_host subscription_id = var.tier3_subid features { @@ -75,6 +75,14 @@ provider "azurerm" { } } +################################ +### GLOBAL VARIABLES ### +################################ + +locals { + deploymentname_default = "mlz-tier3-${formatdate("YYYYMMDD'T'hhmmssZ", timestamp())}" +} + ################################ ### STAGE 0: Scaffolding ### ################################ @@ -82,11 +90,11 @@ provider "azurerm" { resource "azurerm_resource_group" "tier3" { provider = azurerm.tier3 - location = var.mlz_location + location = var.location name = var.tier3_rgname tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } @@ -97,8 +105,8 @@ resource "azurerm_resource_group" "tier3" { data "azurerm_log_analytics_workspace" "laws" { provider = azurerm.tier1 - name = var.laws_name.value - resource_group_name = var.laws_rgname.value + name = var.laws_name + resource_group_name = var.laws_rgname } ################################ @@ -110,7 +118,6 @@ data "azurerm_virtual_network" "hub" { resource_group_name = var.hub_rgname } - module "spoke-network-t3" { providers = { azurerm = azurerm.tier3 } depends_on = [azurerm_resource_group.tier3] @@ -118,9 +125,9 @@ module "spoke-network-t3" { location = azurerm_resource_group.tier3.location - firewall_private_ip = var.firewall_private_ip.value + firewall_private_ip = var.firewall_private_ip - laws_location = var.mlz_location + laws_location = var.location laws_workspace_id = data.azurerm_log_analytics_workspace.laws.workspace_id laws_resource_id = data.azurerm_log_analytics_workspace.laws.id @@ -130,7 +137,7 @@ module "spoke-network-t3" { subnets = var.tier3_subnets tags = { - DeploymentName = var.deploymentname + DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } diff --git a/src/terraform/tier3/minimum.tfvars.sample b/src/terraform/tier3/minimum.tfvars.sample deleted file mode 100644 index 2abc2498e..000000000 --- a/src/terraform/tier3/minimum.tfvars.sample +++ /dev/null @@ -1,15 +0,0 @@ -tf_environment = "" -deploymentname = "" -mlz_location = "" -mlz_metadatahost = "" - - -hub_subid = "" -hub_rgname = "" -hub_vnetname = "" -laws_name = "" -laws_rgname = "" -tier1_subid = "" -tier3_subid = "" -tier3_rgname = "" -tier3_vnetname = "" diff --git a/src/terraform/tier3/output.tf b/src/terraform/tier3/outputs.tf similarity index 100% rename from src/terraform/tier3/output.tf rename to src/terraform/tier3/outputs.tf diff --git a/src/terraform/tier3/tier3.tfvars.sample b/src/terraform/tier3/tier3.tfvars.sample deleted file mode 100644 index eaf43bbf1..000000000 --- a/src/terraform/tier3/tier3.tfvars.sample +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -################################# -# Global Configuration -################################# - -tf_environment = "{TF_ENVIRONMENT}" -deploymentname = "{DEPLOYMENTNAME}" -mlz_location = "{MLZ_LOCATION}" -mlz_metadatahost = "{MLZ_METADATAHOST}" -mlz_objectid = "{MLZ_OBJECTID}" - -################################# -# Hub Configuration -################################# - - -hub_subid = "{HUB_SUBID}" -hub_rgname = "{HUB_RGNAME}" -hub_vnetname = "{HUB_VNETNAME}" -firewall_private_ip = "{FIREWALL_PRIVATE_IP}" - -################################# -# Tier 1 Network configuration section -################################# - -tier1_subid = "{TIER1_SUBID}" -laws_name = "{LAWS_NAME}" -laws_rgname = "{LAWS_RGNAME}" - -################################# -# Tier 3 Network configuration section -################################# - -tier3_subid = "{TIER3_SUBID}" -tier3_rgname = "{TIER3_RGNAME}" -tier3_vnetname = "{TIER3_VNETNAME}" - -tier3_vnet_address_space = ["{TIER3_VNET_ADDRESS_SPACE}"] - -subnets = { - "{TIER3_SUBNETVM_NAME}" = { - name = "{TIER3_SUBNETVM_NAME}" - address_prefixes = ["{TIER3_SUBNETVM_ADDRESSPREFIXLIST}"] - service_endpoints = ["{TIER3_SUBNETVM_SERVICEENDPOINTLIST}"] - - enforce_private_link_endpoint_network_policies = {TIER3_SUBNETVM_ENABLEPRIVATELINKENDPOINT} - enforce_private_link_service_network_policies = {TIER3_SUBNETVM_ENABLEPRIVATELINKSERVICE} - - nsg_name = "{TIER3_SUBNETVM_NSGNAME}" - nsg_rules = { - "allow_ssh" = { - name = "allow_ssh" - priority = "100" - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "" - } - "allow_rdp" = { - name = "allow_rdp" - priority = "200" - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "" - } - } - - routetable_name = "{TIER3_SUBNETVM_RTNAME}" - } -} diff --git a/src/terraform/tier3/variables.tf b/src/terraform/tier3/variables.tf index 568fe611c..5f22d23f6 100644 --- a/src/terraform/tier3/variables.tf +++ b/src/terraform/tier3/variables.tf @@ -4,24 +4,28 @@ # Global Configuration ################################# -variable "tf_environment" { +variable "environment" { description = "The Terraform backend environment e.g. public or usgovernment" + type = string + default = "public" } -variable "deploymentname" { - description = "A name for the deployment" +variable "metadata_host" { + description = "The metadata host for the Azure Cloud e.g. management.azure.com" + type = string + default = "management.azure.com" } -variable "mlz_location" { +variable "location" { description = "The Azure region for most Mission LZ resources" + type = string + default = "East US" } -variable "mlz_metadatahost" { - description = "The metadata host for the Azure Cloud e.g. management.azure.com" -} - -variable "mlz_objectid" { - description = "The account to deploy with" +variable "deploymentname" { + description = "A name for the deployment" + type = string + default = "" } ################################# @@ -29,19 +33,23 @@ variable "mlz_objectid" { ################################# variable "hub_subid" { - description = "Subscription ID for the deployment" + description = "Subscription ID for the Hub deployment" + type = string } variable "hub_rgname" { - description = "Resource Group for the deployment" + description = "Resource Group for the Hub deployment" + type = string } variable "hub_vnetname" { - description = "Virtual Network Name for the deployment" + description = "Virtual Network Name for the Hub deployment" + type = string } variable "firewall_private_ip" { description = "Firewall IP to bind network to" + type = string } ################################# @@ -49,30 +57,38 @@ variable "firewall_private_ip" { ################################# variable "tier1_subid" { - description = "Subscription ID for the deployment" + description = "Subscription ID for the Tier 1 deployment" + type = string } variable "laws_name" { description = "Log Analytics Workspace Name for the deployment" + type = string } variable "laws_rgname" { - description = "The RG that laws was deployed to." + description = "The resource group that Log Analytics Workspace was deployed to" + type = string } ################################# # Tier 3 Configuration ################################# variable "tier3_subid" { - description = "Subscription ID for the deployment" + description = "Subscription ID for this Tier 3 deployment" + type = string } variable "tier3_rgname" { - description = "Resource Group for the deployment" + description = "Resource Group for this Tier 3 deployment" + type = string + default = "tier3-rg" } variable "tier3_vnetname" { - description = "Virtual Network Name for the deployment" + description = "Virtual Network Name for this Tier 3 deployment" + type = string + default = "tier3-vnet" } variable "tier3_vnet_address_space" { @@ -107,15 +123,15 @@ variable "tier3_subnets" { routetable_name = string })) default = { - "tier3vms" = { - name = "tier3vms" + "tier3subnet" = { + name = "tier3Subnet" address_prefixes = ["10.0.125.0/27"] service_endpoints = ["Microsoft.Storage"] enforce_private_link_endpoint_network_policies = false enforce_private_link_service_network_policies = false - nsg_name = "tier3vmsnsg" + nsg_name = "tier3SubnetNsg" nsg_rules = { "allow_ssh" = { name = "allow_ssh" @@ -141,7 +157,7 @@ variable "tier3_subnets" { } } - routetable_name = "tier3vmsrt" + routetable_name = "tier3RouteTable" } } }