diff --git a/README.md b/README.md index 550bce431..7c99ca6f3 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Mission Landing Zone addresses a narrowly scoped, specific need for a [Secure Cl - Implements SCCA controls following Microsoft's [SACA](https://aka.ms/saca) implementation guidance - Deployable in Azure commercial, Azure Government, Azure Government Secret, and Azure Government Top Secret clouds - A simple solution with low configuration and narrow scope -- Written as [Bicep](./src/bicep/README.md) and [Terraform](./src/terraform/README.md) templates +- Written as [Bicep](./src/bicep/) and [Terraform](./src/terraform/) templates Mission Landing Zone is the right solution when: @@ -82,6 +82,8 @@ You must have [Owner RBAC permissions](https://docs.microsoft.com/en-us/azure/ro > Don't have Azure CLI? Here's how to get started with Azure Cloud Shell in your browser: +For more detailed deployment instructions, see our deployment guides for [Bicep](docs/deployment-guide-bicep.md) and [Terraform](docs/deployment-guide-terraform.md). + ## Scope Mission LZ has the following scope: diff --git a/docs/command-line-deployment.md b/docs/command-line-deployment.md deleted file mode 100644 index 10611c4e9..000000000 --- a/docs/command-line-deployment.md +++ /dev/null @@ -1,25 +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](./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/deployment-guide-bicep.md b/docs/deployment-guide-bicep.md new file mode 100644 index 000000000..476064899 --- /dev/null +++ b/docs/deployment-guide-bicep.md @@ -0,0 +1,433 @@ +# Mission LZ Deployment Guide for Bicep + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Planning](#planning) +- [Deployment](#deployment) +- [Cleanup](#cleanup) +- [Development Setup](#development-setup) +- [See Also](#see-also) + +This guide describes how to deploy Mission Landing Zone using the Bicep template at [src/bicep/mlz.bicep](../src/bicep). The template can be deployed using the Azure Portal, the Azure CLI, or PowerShell. Supported clouds include the Azure Cloud (commercial Azure), Azure US Government, Azure Secret, and Azure Top Secret. + +MLZ also provides the ARM template compiled from the Bicep file at [src/bicep/mlz.json](../src/bicep/mlz.json). + +MLZ has only one required parameter and provides sensible defaults for the rest, allowing for simple deployments that specify only the parameters that need to differ from the defaults. See the [README.md](../src/bicep/README.md) document in the `src/bicep` folder for a complete list of parameters. + +Below is an example of an Azure CLI deployment that uses all the defaults, and sets the `resourcePrefix` parameter, which is the only required parameter. + +```BASH +az deployment sub create \ + --name myMlzDeployment \ + --location eastus \ + --template-file ./mlz.bicep \ + --parameters resourcePrefix=myMlz +``` + +## Prerequisites + +- One or more Azure subscriptions 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) +- For deployments in the Azure Portal you need access to the portal in the cloud you want to deploy to, such as [https://portal.azure.com](https://portal.azure.com) or [https://portal.azure.us](https://portal.azure.us). +- For deployments in BASH or a Windows shell, then a terminal instance with the AZ CLI installed is required. For example, [Azure Cloud Shell](https://docs.microsoft.com/en-us/azure/cloud-shell/overview), the MLZ [development container](../.devcontainer/README.md), or a command shell on your local machine with the [AZ CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) installed. +- For PowerShell deployments you need a PowerShell terminal with the [Azure Az PowerShell module](https://docs.microsoft.com/en-us/powershell/azure/what-is-azure-powershell) installed. + +> NOTE: The AZ CLI will automatically install the Bicep tools when a command is run that needs them, or you can manually install them following the [instructions here.](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/install#azure-cli) + +## Planning + +### Decide on a Resource Prefix + +Resource Groups and resource names are derived from the required parameter `resourcePrefix`. Pick a unqiue resource prefix that is 3-10 alphanumeric characters in length without whitespaces. + +### One Subscription or Multiple + +MLZ can deploy to a single subscription or multiple subscriptions. A test and evaluation deployment may deploy everything to a single subscription, and a production deployment may place each tier into its own subscription. + +The optional parameters related to subscriptions are below. They default to the subscription used for deployment. + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`hubSubscriptionId` | Deployment subscription | Subscription containing the firewall and network hub +`identitySubscriptionId` | Deployment subscription | Tier 0 for identity solutions +`operationsSubscriptionId` | Deployment subscription | Tier 1 for network operations and security tools +`sharedServicesSubscriptionId` | Deployment subscription | Tier 2 for shared services + +### Networking + +The following parameters affect networking. + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`hubVirtualNetworkAddressPrefix` | '10.0.100.0/24' | The CIDR Virtual Network Address Prefix for the Hub Virtual Network. +`hubSubnetAddressPrefix` | '10.0.100.128/27' | The CIDR Subnet Address Prefix for the default Hub subnet. It must be in the Hub Virtual Network space. +`firewallClientSubnetAddressPrefix` | '10.0.100.0/26' | The CIDR Subnet Address Prefix for the Azure Firewall Subnet. It must be in the Hub Virtual Network space. It must be /26. +`firewallManagementSubnetAddressPrefix` | '10.0.100.64/26' | The CIDR Subnet Address Prefix for the Azure Firewall Management Subnet. It must be in the Hub Virtual Network space. It must be /26. +`identityVirtualNetworkAddressPrefix` | '10.0.110.0/26' | The CIDR Virtual Network Address Prefix for the Identity Virtual Network. +`identitySubnetAddressPrefix` | '10.0.110.0/27' | The CIDR Subnet Address Prefix for the default Identity subnet. It must be in the Identity Virtual Network space. +`operationsVirtualNetworkAddressPrefix` | '10.0.115.0/26' | The CIDR Virtual Network Address Prefix for the Operations Virtual Network. +`operationsSubnetAddressPrefix` | '10.0.115.0/27' | The CIDR Subnet Address Prefix for the default Operations subnet. It must be in the Operations Virtual Network space. +`sharedServicesVirtualNetworkAddressPrefix` | '10.0.120.0/26' | The CIDR Virtual Network Address Prefix for the Shared Services Virtual Network. +`sharedServicesSubnetAddressPrefix` | '10.0.120.0/27' | The CIDR Subnet Address Prefix for the default Shared Services subnet. It must be in the Shared Services Virtual Network space. + +### Optional Features + +MLZ has optional features that can be enabled by setting parameters on the deployment. + +#### Azure Policy Initiatives: NIST, IL5, CMMC + +To include one of the built in Azure policy initiatives for NIST 800-53, CMMC Level 3 or DoD IL5 compliance add the `deployPolicy=true` parameter with `policy` assigned to one of the following: `NIST`, `IL5`, or `CMMC`. + +The result will be a policy assignment created for each resource group deployed by MLZ that can be viewed in the 'Compliance' view of Azure Policy in the Azure Portal. + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`deployPolicy` | 'false' | When set to "true", deploys the Azure Policy set defined at by the parameter "policy" to the resource groups generated in the deployment. It defaults to "false". +`policy` | 'NIST' | [NIST/IL5/CMMC] Built-in policy assignments to assign, it defaults to "NIST". IL5 is only available for AzureUsGovernment and will switch to NIST if tried in AzureCloud. + +Under the [src/bicep/modules/policies](../src/bicep/modules/policies) directory are JSON files named for the initiatives with default parameters (except for a Log Analytics workspace ID value `` that we substitute at deployment time -- any other parameter can be modified as needed). + +#### Azure Security Center (Microsoft Defender for Cloud) + +By default [Azure Security Center](https://docs.microsoft.com/en-us/azure/defender-for-cloud/defender-for-cloud-introduction) offers a free set of monitoring capabilities that are enabled via an Azure policy when you first set up a subscription and view the Azure Security Center portal blade. + +Azure Security Center offers a standard/defender sku which enables a greater depth of awareness including more recomendations and threat analytics. You can enable this higher depth level of security in MLZ by setting the parameter `deployASC` during deployment. In addition you can include the `emailSecurityContact` parameter to set a contact email for alerts. + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`deployASC` | 'false' | When set to "true", enables Azure Security Center for the subscriptions used in the deployment. It defaults to "false". +`emailSecurityContact` | '' | Email address of the contact, in the form of john@doe.com + +#### Azure Sentinel + +[Sentinel](https://docs.microsoft.com/en-us/azure/sentinel/overview) is a scalable, cloud-native, security information and event management (SIEM) and security orchestration, automation, and response (SOAR) solution. Sentinel can be enabled by setting the `deploySentinel=true` parameter. + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`deploySentinel` | 'false' | When set to "true", enables Microsoft Sentinel within the Log Analytics Workspace created in this deployment. It defaults to "false". + +#### Remote access with a Bastion Host + +If you want to remotely access the network and the resources you've deployed you can use [Azure Bastion](https://docs.microsoft.com/en-us/azure/bastion/) to remotely access virtual machines within the network without exposing them via Public IP Addresses. + +Deploy a Linux and Windows virtual machine as jumpboxes into the network without a Public IP Address using Azure Bastion Host by providing values for these parameters: + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`deployRemoteAccess` | 'false' | When set to "true", provisions Azure Bastion Host and virtual machine jumpboxes. It defaults to "false". +`windowsVmAdminPassword` | new guid | The administrator password the Windows Virtual Machine to Azure Bastion remote into. It must be > 12 characters in length. See [password requirements for creating a Windows VM](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/faq#what-are-the-password-requirements-when-creating-a-vm-). +`linuxVmAuthenticationType` | 'password' | [sshPublicKey/password] The authentication type for the Linux Virtual Machine to Azure Bastion remote into. It defaults to "password". +`linuxVmAdminPasswordOrKey` | new guid | The administrator password or public SSH key for the Linux Virtual Machine to Azure Bastion remote into. See [password requirements for creating a Linux VM](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/faq#what-are-the-password-requirements-when-creating-a-vm-). +`windowsVmAdminUsername` | 'azureuser' | The administrator username for the Linux Virtual Machine to Azure Bastion remote into. It defaults to "azureuser". +`linuxVmAdminUsername` | 'azureuser' | The administrator username for the Linux Virtual Machine to Azure Bastion remote into. It defaults to "azureuser". + +#### Azure Firewall Premium + +By default, MLZ deploys **[Azure Firewall Premium](https://docs.microsoft.com/en-us/azure/firewall/premium-features). Not all regions support Azure Firewall Premium.** Check here to [see if the region you're deploying to supports Azure Firewall Premium](https://docs.microsoft.com/en-us/azure/firewall/premium-features#supported-regions). If necessary you can set a different firewall SKU or location. + +You can manually specify which SKU of Azure Firewall to use for your deployment by specifying the `firewallSkuTier` parameter. This parameter only accepts values of `Standard` or `Premium`. + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`firewallSkuTier` | 'Premium' | [Standard/Premium] The SKU for Azure Firewall. It defaults to "Premium". + +If you'd like to specify a different region to deploy your resources into, change the location of the deployment. For example, when using the AZ CLI set the deployment command's `--location` argument. + +### Naming Conventions + +By default, Mission LZ resources are named according to a naming convention that uses the mandatory `resourcePrefix` parameter and the optional `resourceSuffix` parameter (that is defaulted to `mlz`). + +#### Default Naming Convention Example + +Let's look at an example using `--parameters resourcePrefix=FOO` and `--parameters resourceSuffix=BAR` + +In `mlz.bicep` you will find a variable titled `namingConvention`: + +```bicep +var namingConvention = '${toLower(resourcePrefix)}-${resourceToken}-${nameToken}-${toLower(resourceSuffix)}' +# this generates a value of: foo-${resourceToken}-${nameToken}-bar +``` + +This naming convention uses Bicep's `replace()` function to substitute resource abbreviations for `resourceToken` and resource names for `nameToken`. + +For example, when naming the Hub Resource Group, first the `resourceToken` is substituted with the recommended abbreviation `rg`: + +```bicep +var resourceGroupNamingConvention = replace(namingConvention, resourceToken, 'rg') +# this generates a value of: foo-rg-${nameToken}-bar +``` + +Then, the `nameToken` is substituted with the Mission LZ name `hub`: + +```bicep +var hubResourceGroupName = replace(resourceGroupNamingConvention, nameToken, 'hub') +# this generates a value of: foo-rg-hub-bar +``` + +Finally, the `hubResourceGroupName` is assigned to the resource group `name` parameter: + +```bicep +params: { + name: hubResourceGroupName # this is the calculated value 'foo-rg-hub-bar' + location: location + tags: calculatedTags +} +``` + +#### Modifying the Naming Convention + +You can modify this naming convention to suit your needs. + +In `mlz.bicep` you can modify the root naming convention. This is the default convention: + +```bicep +var namingConvention = '${toLower(resourcePrefix)}-${resourceToken}-${nameToken}-${toLower(resourceSuffix)}' +``` + +Say you did not want to use the `resourceSuffix` value, but instead wanted to add your own token to the naming convention like `team`: + +First, you added the new parameter `team`: + +```bicep +@allowedValues([ + 'admin' + 'marketing' + 'sales' +]) +param team +``` + +Then, you modified the naming convention to allow for mixed case `resourcePrefix` values and your new `team` value (while retaining the token identifiers `resourceToken` and `nameToken`): + +```bicep +var namingConvention = '${resourcePrefix}-${team}-${resourceToken}-${nameToken}' +``` + +Now, given a `--parameters resourcePrefix=FOO` and `--parameters team=sales` the generated Hub Resource Group Name would be: + +```bicep +params: { + name: hubResourceGroupName # this is the calculated value 'FOO-sales-rg-hub' + location: location + tags: calculatedTags +} +``` + +### Planning for Workloads + +MLZ allows for deploying one or many workloads that are peered to the hub network. Each workload can be in its own subscription or multiple workloads may be combined into a single subscription. + +A separate Bicep template is provided for deploying an empty workload. It deploys a virtual network, a route table, a network security group, a storage account (for logs), and a network peering to the hub network. The template is at [src/bicep/examples/newWorkload](../src/bicep/examples/newWorkload). You can use this template as a starting point to create and customize specific workload deployments. + +The `newWorkload` template contains defaults for IP address ranges, but additional workloads will require planning for additional ranges. The following parameters affect `newWorkload` networking: + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`virtualNetworkAddressPrefix` | '10.0.125.0/26' | The address prefix for the network spoke vnet. +`subnetAddressPrefix` | '10.0.125.0/27' | The subnet address prefix for the network spoke vnet. + +## Deployment + +Mission Landing Zone can be deployed using the Azure Portal or with command-line tools provided with the AZ CLI or PowerShell. + +### Deploy Using the Azure Portal + +The Azure Portal can be used to deploy Mission Landing Zone. The buttons below invoke an Azure Portal input form that maps user input values to the MLZ ARM template that was compiled from the Bicep template. + + + +| Azure Commercial | Azure Government | +| :--- | :--- | +| [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fform%2Fmlz.portal.json) | [![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fform%2Fmlz.portal.json) | + + +### Command Line Deployment Using the Azure CLI or PowerShell + +Use the AZ CLI command `az deployment sub` to deploy MLZ across one or many subscriptions or use the PowerShell cmdlet `New-AzSubscriptionDeployment`. + +#### Single Subscription Deployment + +To deploy Mission LZ into a single subscription, give your deployment a name and a location and specify the `./mlz.bicep` template file. + +```BASH +# AZ CLI +az deployment sub create \ + --name myMlzDeployment \ + --location eastus \ + --template-file ./mlz.bicep \ + --parameters resourcePrefix="myMlz" +``` + +```PowerShell +# PowerShell +New-AzSubscriptionDeployment ` + -Name myMlzDeployment ` + -Location 'eastus' ` + -TemplateFile .\mlz.bicep ` + -resourcePrefix 'myMlz' +``` + +#### Multiple Subscription Deployment + +Deployment to multiple subscriptions requires specifying the subscription IDs for each tier: + +```BASH +# AZ CLI +az deployment sub create \ + --subscription $deploymentSubscription \ + --location eastus \ + --name multiSubscriptionTest \ + --template-file ./mlz.bicep \ + --parameters \ + resourcePrefix='myMlz' \ + hubSubscriptionId=$hubSubscriptionId \ + identitySubscriptionId=$identitySubscriptionId \ + operationsSubscriptionId=$operationsSubscriptionId \ + sharedServicesSubscriptionId=$sharedServicesSubscriptionId +``` + +```PowerShell +# PowerShell +New-AzSubscriptionDeployment ` + -Name myMlzDeployment ` + -Location 'eastus' ` + -TemplateFile .\mlz.bicep ` + -resourcePrefix "myMlz" ` + -hubSubscriptionId $hubSubscriptionId ` + -identitySubscriptionId $identitySubscriptionId ` + -operationsSubscriptionId $operationsSubscriptionId ` + -sharedServicesSubscriptionId $sharedServicesSubscriptionId +``` + +#### Deploying to Other Clouds + +When deploying to another cloud, like Azure US Government, first set the cloud and log in. + +Logging into `AzureUSGovernment`: + +```BASH +# AZ CLI +az cloud set -n AzureUsGovernment +az login +``` + +```PowerShell +# PowerShell +Connect-AzAccount -Environment AzureUSGovernment +``` + +...and supply a different value for the deployment `--location` argument: + +```BASH +# AZ CLI +az deployment sub create \ + --name myMlzDeployment \ + --location usgovvirginia \ + --template-file ./mlz.bicep \ + --parameters resourcePrefix=myMlz +``` + +```PowerShell +# PowerShell +New-AzSubscriptionDeployment ` + -Name myMlzDeployment ` + -Location 'usgovvirginia' ` + -TemplateFile .\mlz.bicep ` + -resourcePrefix 'myMlz' +``` + +#### Air-Gapped Clouds + +For air-gapped clouds it may be convenient to transfer and deploy the compiled ARM template instead of the Bicep template if the Bicep CLI tools are not available or if it is desirable to transfer only one file into the air gap. + +The ARM template is at [src/bicep/mlz.json](../src/bicep/mlz.json). The AZ CLI command for deploying the ARM template is the same as for deploying Bicep: use `az deployment sub create` and supply `mlz.json` as the template file name instead of `mlz.bicep`. + +#### Reference Deployment Output + +After you've deployed Mission Landing Zone you can integrate additional services or infrastructure. Bicep templates, the Azure CLI, and JMESpath queries allow you to retrieve outputs from a deployment and pass them as parameters into another deployment. + +You can use the `az deployment sub show` command with a `--query` argument to retrieve information about the resources you deployed. In PowerShell use the `Get-AzSubscriptionDeployment` cmdlet. + +In this example, MLZ was deployed using a deployment name of `myMissionLandingZone`. (The deployment name is the `name` parameter you set on `az deployment sub create` or `New-AzSubscriptionDeployment`.) + +When an MLZ deployment is complete, you can see all the resources provisioned in that deployment by querying the `outputs` property: + +```BASH +# AZ CLI +az deployment sub show \ + --name "myMissionLandingZone" \ + --query "properties.outputs" +``` + +```PowerShell +# PowerShell +(Get-AzSubscriptionDeployment -Name myMissionLandingZone).outputs | ConvertTo-Json +``` + +If you need a single property value you can retrieve it like this: + +```BASH +# AZ CLI +az deployment sub show \ + --name "myMissionLandingZone" \ + --query "properties.outputs.firewallPrivateIPAddress.value" +``` + +```PowerShell +# PowerShell +(Get-AzSubscriptionDeployment -Name myMissionLandingZone).outputs.firewallPrivateIPAddress +``` + +If you want to export the data for use by other Bicep deployments, like the [shared variable file pattern](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/patterns-shared-variable-file), you can export the outputs to a json file. + +```BASH +# AZ CLI +az deployment sub show \ + --name "myMissionLandingZone" \ + --query "properties.outputs" > ./deploymentVariables.json +``` + +```PowerShell +# PowerShell +(Get-AzSubscriptionDeployment -Name myMissionLandingZone).outputs ` + | ConvertTo-Json ` + | Out-File -FilePath .\deploymentVariables.json +``` + +## Cleanup + +The Bicep/ARM deployment of Mission Landing Zone can be deleted with two steps: + +1. Delete all resource groups. +1. Delete the diagnostic settings deployed at the subscription level. + +> NOTE: If you deploy and delete Mission Landing Zone in the same subscription multiple times without deleting the subscription-level diagnostic settings, the sixth deployment will fail. Azure has a limit of five diagnostic settings per subscription. The error will be similar to this: `"The limit of 5 diagnostic settings was reached."` + +To delete the diagnostic settings from the Azure Portal: choose the subscription blade, then Activity log in the left panel. At the top of the Activity log screen click the Diagnostics settings button. From there you can click the Edit setting link and delete the diagnostic setting. + +To delete the diagnotic settings in script, use the AZ CLI or PowerShell. An AZ CLI example is below: + +```BASH +# View diagnostic settings in the current subscription +az monitor diagnostic-settings subscription list --query value[] --output table + +# Delete a diagnostic setting +az monitor diagnostic-settings subscription delete --name +``` + +## Development Setup + +If you want to develop with Bicep you'll need these: + +1. Install the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli#install). +1. If using Visual Studio Code, install the [Bicep extension](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/install#vs-code-and-bicep-extension). + +## See Also + +[Bicep documentation](https://aka.ms/bicep/) + +[`az deployment` documentation](https://docs.microsoft.com/en-us/cli/azure/deployment?view=azure-cli-latest) + +[JMESPath queries](https://jmespath.org/) + +[Azure Az PowerShell module](https://docs.microsoft.com/en-us/powershell/azure/what-is-azure-powershell) diff --git a/docs/deployment-guide-terraform.md b/docs/deployment-guide-terraform.md new file mode 100644 index 000000000..f863c91c0 --- /dev/null +++ b/docs/deployment-guide-terraform.md @@ -0,0 +1,444 @@ +# Mission LZ Deployment Guide for Terraform + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Planning](#planning) +- [Deployment](#deployment) +- [Cleanup](#cleanup) +- [Development Setup](#development-setup) +- [See Also](#see-also) + +This guide describes how to deploy Mission Landing Zone using the [Terraform](https://www.terraform.io/) template at [src/terraform/mlz](../src/terraform/mlz). + +To get started with Terraform on Azure check out their [tutorial](https://learn.hashicorp.com/collections/terraform/azure-get-started/). + +Below is an example of a Terraform deployment that uses all the defaults. + +```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 +``` + +## Prerequisites + +- 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) + + +> NOTE: Azure Cloud Shell is often our preferred place to deploy from because the AZ CLI and Terraform are already installed. However, sometimes Cloud Shell has different versions of the dependencies from what we have tested and verified, and sometimes there have been bugs in the Terraform Azure RM provider or the AZ CLI that only appear in Cloud Shell. If you are deploying from Azure Cloud Shell and see something unexpected, try the [development container](../.devcontainer) or deploy from your machine using locally installed AZ CLI and Terraform. We welcome all feedback and [contributions](../CONTRIBUTING.md), so if you see something that doesn't make sense, please [create an issue](https://github.com/Azure/missionlz/issues/new/choose) or open a [discussion thread](https://github.com/Azure/missionlz/discussions). + + +## Planning + +### Decide on a Resource Prefix + +Resource Groups and resource names are derived from the `resourcePrefix` parameter, which defaults to 'mlz'. Pick a unqiue resource prefix that is 3-10 alphanumeric characters in length without whitespaces. + +### One Subscription or Multiple + +MLZ can deploy to a single subscription or multiple subscriptions. A test and evaluation deployment may deploy everything to a single subscription, and a production deployment may place each tier into its own subscription. + +The optional parameters related to subscriptions are below. At least one subscription is required. + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`hub_subid` | '' | Subscription ID for the Hub deployment +`tier0_subid` | value of hub_subid | Subscription ID for tier 0 +`tier1_subid` | value of hub_subid | Subscription ID for tier 1 +`tier2_subid` | value of hub_subid | Subscription ID for tier 2 + +### Networking + +The following parameters affect networking addresses. To override the defaults edit the variables file at [`src/terraform/mlz/variables.tf`](../src/terraform/mlz/variables.tf). + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`hub_vnet_address_space` | `["10.0.100.0/24"]` | The address space to be used for the virtual network +`hub_client_address_space` | `"10.0.100.0/26"` | The address space to be used for the Firewall virtual network +`hub_management_address_space` | `"10.0.100.64/26"` | The address space to be used for the Firewall virtual network subnet used for management traffic +`tier0_vnet_address_space` | `["10.0.110.0/26"]` | VNet prefix for tier 0 +`tier0_subnets.address_prefixes` | `["10.0.110.0/27"]` | Subnet prefix for tier 0 +`tier1_vnet_address_space` | `["10.0.115.0/26"]` | VNet prefix for tier 1 +`tier1_subnets.address_prefixes` | `["10.0.115.0/27"]` | Subnet prefix for tier 1 +`tier2_vnet_address_space` | `["10.0.120.0/26"]` | VNet prefix for tier 2 +`tier2_subnets.address_prefixes` | `["10.0.120.0/27"]` | Subnet prefix for tier 2 + +### Optional Features + +### Assigning Azure Policy + +This template supports assigning NIST 800-53 policies. See the [policies documentation](./policies.md) for more information. + +You can enable this by providing a `true` value to the `create_policy_assignment` variable. + +At `apply` time: + +```plaintext +terraform apply -var="create_policy_assignment=true" +``` + +Or, by updating `src/terraform/mlz/variables.tf`: + +```terraform +variable "create_policy_assignment" { + description = "Assign Policy to deployed resources?" + type = bool + default = true +} +``` + +### Planning for Workloads + +MLZ allows for deploying one or many workloads that are peered to the hub network. Each workload can be in its own subscription or multiple workloads may be combined into a single subscription. + +A separate Terraform template is provided for deploying an empty workload `src/terraform/tier3`. You can use this template as a starting point to create and customize specific workload deployments. + +The following parameters affect newWorkload networking. To override the defaults edit the variables file at [`src/terraform/tier3/variables.tf`](../src/terraform/tier3/variables.tf). + +Parameter name | Default Value | Description +-------------- | ------------- | ----------- +`tier3_vnet_address_space` | `["10.0.125.0/26"]` | Address space prefix for tier 3 +`tier3_subnets.address_prefixes` | `["10.0.125.0/27"]` | Subnet prefix for tier 3 + +## Deployment + +### Login to Azure CLI + +Log in using the Azure CLI. + +```BASH +az login +``` + +If you are deploying to another cloud, such as Azure Government, set the cloud name before logging in. + + ```BASH + az cloud set -n AzureUSGovernment + az login + ``` + +### Terraform init + +Before provisioning any Azure resources with Terraform you must [initialize a working directory](https://www.terraform.io/docs/cli/commands/init.html/). + +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`](https://www.terraform.io/docs/cli/commands/apply.html) to provision the resources described in `mlz/main.tf` and its referenced modules at `mlz/modules/*`. + +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`](https://www.terraform.io/docs/cli/commands/plan.html) and then prompt you for your approval before taking action. + +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. + +### 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}" +``` + +### Deploy New Workloads + +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. + +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 + ``` + +### Deploy with a Service Principal + +If you are using a Service Principal to deploy Azure resources with Terraform, [some additional configuration is required](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret/). + +Using a Service Principal will require [updating the resource providers](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret#configuring-the-service-principal-in-terraform/) for `mlz/main.tf`. + +```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" +} +``` + +### Deploy 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](../src/terraform/mlz/variables.tf) or [tier3/variables.tf](../src/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: + +### Terraform Providers + +The [development container definition](../.devcontainer/Dockerfile) downloads the required Terraform plugin providers during the container build so that the container can be transported to an air-gapped network. + +The container 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 [development container](../.devcontainer) 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) + +## Cleanup + +If you want to delete an MLZ deployment you can use [`terraform destroy`](https://www.terraform.io/docs/cli/commands/destroy.html). If you have deployed more than one Terraform template, e.g., if you have deployed `mlz/main.tf` and then `tier3/main.tf`, run the `terraform destroy` commands in the reverse order that you applied them. For example: + +```bash +# Deploy core MLZ resources +cd src/terraform/mlz +terraform apply + +# Deploy a tier 3 spoke network +cd ../tier3 +terraform apply + +# Reverse order to destroy: +# Destroy the tier 3 spoke network (still in the src/terraform/tier3 folder) +terraform destroy + +# Destroy core MLZ resources +cd ../mlz +terraform destroy +``` + +Running `terraform destroy` for `mlz/main.tf` looks like this: + +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. + +## Development Setup + +For development of the Mission Landing Zone Terraform templates we recommend using the development container because it has the necessary dependencies already installed. To get started follow the [guidance for using the development container](../.devcontainer/README.md). + +## See Also + +[Terraform](https://www.terraform.io/) + +[Terraform Tutorial](https://learn.hashicorp.com/collections/terraform/azure-get-started/) + +[Developing in a container](https://code.visualstudio.com/docs/remote/containers) using Visual Studio Code diff --git a/docs/getting-started.md b/docs/getting-started.md deleted file mode 100644 index 5c712437d..000000000 --- a/docs/getting-started.md +++ /dev/null @@ -1,45 +0,0 @@ -# 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 [Development Container docs](../.devcontainer/README.md) for how to configure your workstation. - -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 required tools and how 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/docs/images/custom_template_deployment.gif b/docs/images/custom_template_deployment.gif deleted file mode 100644 index 11c6594f2..000000000 Binary files a/docs/images/custom_template_deployment.gif and /dev/null differ diff --git a/docs/images/missionlz_as_of_july2021.jpg b/docs/images/missionlz_as_of_july2021.jpg deleted file mode 100644 index bff443cea..000000000 Binary files a/docs/images/missionlz_as_of_july2021.jpg and /dev/null differ diff --git a/docs/images/missionlz_as_of_may2021.png b/docs/images/missionlz_as_of_may2021.png deleted file mode 100644 index 4cc28b276..000000000 Binary files a/docs/images/missionlz_as_of_may2021.png and /dev/null differ diff --git a/docs/workload-deployment.md b/docs/workload-deployment.md deleted file mode 100644 index 844d68eaf..000000000 --- a/docs/workload-deployment.md +++ /dev/null @@ -1,21 +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. - -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 cdf65685d..8f7770785 100644 --- a/src/bicep/README.md +++ b/src/bicep/README.md @@ -1,447 +1,130 @@ -# Mission LZ Bicep - -## Deployment - -### Prerequisites - -You can deploy with the Azure Portal, the Azure CLI, or with both in a Azure Commercial, Azure for Government, or Air-Gapped Clouds. But first, you'll need these pre-requisites: - -1. 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) -1. A BASH or PowerShell terminal where you can run the Azure CLI. For example, [Azure Cloud Shell](https://docs.microsoft.com/en-us/azure/cloud-shell/overview), the MLZ [development container](../../.devcontainer/README.md), or a command shell on your local machine with the [AZ CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) installed. - -> NOTE: The AZ CLI will automatically install the Bicep tools when a command is run that needs them, or you can manually install them following the [instructions here.](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/install#azure-cli) - -#### Decide on a Resource Prefix - -Resource Groups and resource names are derived from the mandatory parameter `resourcePrefix`. - -Pick a unqiue resource prefix that is 3-10 alphanumeric characters in length without whitespaces. - -#### Pick your deployment options - -- Are you deploying into a cloud other than `AzureCloud` like say `AzureUsGovernment`? See [Deploying to Other Clouds](#Deploying-to-Other-Clouds). - -- Want to add Azure Policies to this deployment? See [Adding Azure Policy](#Adding-Azure-Policy) to add policies like DoD IL5, NIST 800-53, CMMC Level 3, or how to apply your own. - -- Want to remotely access the network without exposing it via Public IP Addresses? See [Adding Remote Access via Bastion Host](#Adding-Remote-Access-via-Bastion-Host) to add virtual machines inside the network that you can access from an authenticated session in the Azure Portal with Azure Bastion. - -- By default, this template deploys **[Azure Firewall Premium](https://docs.microsoft.com/en-us/azure/firewall/premium-features)**. - - - **Not all regions support Azure Firewall Premium.** Check here to [see if the region you're deploying to supports Azure Firewall Premium](https://docs.microsoft.com/en-us/azure/firewall/premium-features#supported-regions). If this doesn't fit your needs: - - See [Setting the Firewall SKU](#Setting-the-Firewall-SKU) for steps on how to use the Standard SKU instead. - - See [Setting the Firewall Location](#Setting-the-Firewall-Location) for steps on how to deploy into a different region. - -- Review the default [Naming Convention](#Naming-Conventions) or apply your own - - - By default, Mission LZ creates resources with a naming convention - - See [Naming Convention](#Naming-Conventions) to see what that convention is and how to provide your own to suit your needs - -#### Know where to find your deployment output - -After a deployment is complete, you can refer to the provisioned resources programmaticaly with the Azure CLI. See [Reference Deployment Output](#Reference-Deployment-Output) for steps on how to use `az deployment` subcommands and JMESPath to query for specific properties. - -### Azure Portal - -The Azure Portal can be used to deploy Mission Landing Zone. - - - -| Azure Commercial | Azure Government | -| :--- | :--- | -| [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fform%2Fmlz.portal.json) | [![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fform%2Fmlz.portal.json) | - - -### Azure CLI - -If you are not using the Azure Portal to deploy, you can deploy with the Azure CLI. - -Use `az deployment sub` to deploy MLZ across one or many subscriptions. (See `az deployment sub create --help` for more information.) - -#### Single subscription deployment - -To deploy Mission LZ into a single subscription, give your deployment a name and a location and specify the `./mlz.bicep` template file (replacing `mlz.bicep` with `mlz.json` if disconnected from the internet or do not have an installation of [Bicep](https://aka.ms/bicep) available): - -```plaintext -az deployment sub create \ - --name myMlzDeployment \ - --location eastus \ - --template-file ./mlz.bicep \ - --parameters resourcePrefix="myMlz" -``` - -The only required Bicep/ARM parameter is `resourcePrefix` (a unique alphanumeric string 3-10 characters in length), which is used to to generate names for your resource groups and resources: - -#### Multiple subscription deployment - -Deployment to multiple subscriptions requires specifying the `--parameters` flag and passing `key=value` arguments: - -```plaintext -az deployment sub create \ - --subscription $deploymentSubscription \ - --location eastus \ - --name multiSubscriptionTest \ - --template-file ./mlz.bicep \ - --parameters \ - resourcePrefix="myMlz" \ - hubSubscriptionId=$hubSubscriptionId \ - identitySubscriptionId=$identitySubscriptionId \ - operationsSubscriptionId=$operationsSubscriptionId \ - sharedServicesSubscriptionId=$sharedServicesSubscriptionId -``` - -When deploying to multiple subscriptions, you must have at least [Contributor RBAC permissions](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#all) to those subscriptions. - -#### Deploying to Other Clouds - -If I'm deploying to another cloud, say Azure Government, I will first login to that cloud... - -Logging into `AzureUsGovernment`: - -```plaintext -az cloud set -n AzureUsGovernment -az login -``` - -...and supply a different value for the deployment `--location` argument: - -```plaintext -az deployment sub create \ - --name myMlzDeployment \ - --location usgovvirginia \ - --template-file ./mlz.bicep -``` - -And if I need to deploy into multiple subscriptions, I would pass the relevant subscription IDs as `parameters` as described in [Multiple subscription deployment](#Multiple-subscription-deployment). - -### Air-Gapped Clouds - -#### Air-Gapped Clouds Deployment with Azure CLI - -If I were in an offline environment that didn't have a Bicep installation available (like an air-gapped cloud), I could always deploy the `az bicep build` output ARM template **`mlz.json`**: - -```plaintext -az cloud set -n - -az deployment sub create \ - --subscription $deploymentSubscription \ - --location \ - --name multisubtest \ - --template-file ./mlz.json \ - --parameters \ - hubSubscriptionId=$hubSubscriptionId \ - identitySubscriptionId=$identitySubscriptionId \ - operationsSubscriptionId=$operationsSubscriptionId \ - sharedServicesSubscriptionId=$sharedServicesSubscriptionId -``` - -## Adding Azure Policy - -To include one of the built in Azure policy initiatives for NIST 800-53, CMMC Level 3 or DoD IL5 compliance add the `deployPolicy=true` parameter with `policy` assigned to one of the following: `NIST`, `IL5`, or `CMMC`. - -For example, deploying with MLZ: - -```plaintext -az deployment sub create \ - --location eastus \ - --template-file mlz.bicep \ - --parameters deployPolicy=true \ - --parameters policy= -``` - -Or, apply policy to a resource group after deploying MLZ: - -```plaintext -az deployment group create \ - --resource-group \ - --name \ - --template-file ./src/bicep/modules/policyAssignment.bicep \ - --parameters builtInAssignment= logAnalyticsWorkspaceName= \ - --parameters logAnalyticsWorkspaceName= \ - --parameters logAnalyticsWorkspaceResourceGroupName= -``` - -The result will be a policy assignment created for each resource group deployed by MLZ that can be viewed in the 'Compliance' view of Azure Policy in the Azure Portal. - -Under the [modules/policies](modules/policies) directory are JSON files named for the initiatives with default parameters (except for a Log Analytics workspace ID value `` that we substitute at deployment time -- any other parameter can be modified as needed). - -## Adding Azure Security Center - -By default [Azure Security Center](https://docs.microsoft.com/en-us/azure/security-center/security-center-introduction) offers a free set of monitoring capabilities that are enabled via an Azure policy when your first set up a subscription and view Azure Security Center portal blade. - -Azure Security Center offers a standard/defender sku which enables a greater depth of awareness including more reccomendations and threat analytics. You can enable this higher depth level of security in MLZ by setting the parameter `deployASC` during deployment. In addition you can include the `emailSecurityContact` parameter to set a contact email for alerts. - -```plaintext -az deployment sub create \ - --location eastus \ - --template-file mlz.bicep \ - --parameters policy= \ - --parameters deployASC=true \ - --parameters emailSecurityContact= -``` - -## Adding Remote Access via Bastion Host - -Want to remotely access the network and the resources you've deployed into it? You can use [Azure Bastion](https://docs.microsoft.com/en-us/azure/bastion/) to remotely access virtual machines within the network without exposing them via Public IP Addresses. - -To deploy a virtual machine as a jumpbox into the network without a Public IP Address using Azure Bastion Host, provide two parameters `deployRemoteAccess=true` and `linuxVmAdminPasswordOrKey=` and `windowsVmAdminPassword=` to the deployment. A quick and easy way to generate a secure password from the .devcontainer is the command `openssl rand -base64 14`. - -```plaintext -my_password=$(openssl rand -base64 14) - -az deployment sub create \ - --name "myRemoteAccessDeployment" \ - --location "eastus" \ - --template-file "src/bicep/mlz.bicep" \ - --parameters deployRemoteAccess="true" \ - --parameters linuxVmAdminPasswordOrKey="$my_password" \ - --parameters windowsVmAdminPassword="$my_password" -``` - -Then, once you've deployed the virtual machines and Bastion Host, use these docs to connect with the provided password: - -The default username is set to `azureuser`. - -### Using an SSH Key with Remote Access via Bastion Host - -If you have a key pair you'd like to use for SSH connections to the Linux virtual machine that is deployed with `deployRemoteAccess=true`, specify the `linuxVmAuthenticationType` parameter to `sshPublicKey` like so: - -```plaintext -my_sshkey=$(cat ~/.ssh/id_rsa.pub) # or, however you source your public key -my_password=$(openssl rand -base64 14) - -az deployment sub create \ - --name "myRemoteAccessDeployment" \ - --location "eastus" \ - --template-file "src/bicep/mlz.bicep" \ - --parameters deployRemoteAccess="true" \ - --parameters linuxVmAuthenticationType="sshPublicKey" \ - --parameters linuxVmAdminPasswordOrKey="$my_sshkey" \ - --parameters windowsVmAdminPassword="$my_password" -``` - -For more information on generating a public/private key pair see . - -Then, once you've deployed the virtual machines and Bastion Host, use these docs to connect with an SSH Key: - -The default username is set to `azureuser`. - -## Configuring the Firewall - -### Setting the Firewall SKU - -By default, this template deploys [Azure Firewall Premium](https://docs.microsoft.com/en-us/azure/firewall/premium-features). - -Not all regions support Azure Firewall Premium. Check here to [see if the region you're deploying to supports Azure Firewall Premium](https://docs.microsoft.com/en-us/azure/firewall/premium-features#supported-regions). - -You can manually specify which SKU of Azure Firewall to use for your deployment by specifying the `firewallSkuTier` parameter. This parameter only accepts values of `Standard` or `Premium`: - -```plaintext -az deployment sub create \ - --name "myFirewallStandardDeployment" \ - --location "eastus" \ - --template-file "src/bicep/mlz.bicep" \ - --parameters firewallSkuTier="Standard" -``` - -### Setting the Firewall Location - -If you'd like to specify a different region to deploy your resources into, just change the location of the deployment in the `az deployment sub create` command's `--location` argument: - -```plaintext -az deployment sub create \ - --name "SouthCentralUsDeployment" \ - --location "South Central US" \ - --template-file "src/bicep/mlz.bicep" -``` - -### Reference Deployment Output - -After you've deployed Mission Landing Zone you'll probably want to integrate additional services or infrastructure. - -You can use the `az deployment sub show` command with a `--query` argument to retrieve information about the resources you deployed. - -Before giving the next steps a try, it's probably a good idea to [review the Azure CLI's documentation on querying with JMESPath](https://docs.microsoft.com/en-us/cli/azure/query-azure-cli). - -First off, let's say you deployed Mission Landing Zone with a deployment name of `myMissionLandingZone`: - -```plaintext -az deployment sub create \ - --name "myMissionLandingZone" \ - --location "East US" \ - --template-file "src/bicep/mlz.bicep" -``` - -Once it's complete, you could see all the resources provisioned in that deployment by querying the `properties.outputResources` property: - -```plaintext -az deployment sub show \ - --name "myMissionLandingZone" \ - --query "properties.outputResources" -``` - -That's a lot of resources. Thankfully, the template produces outputs for just the things you _probably_ need at `properties.outputs`: - -```plaintext -az deployment sub show \ - --name "myMissionLandingZone" \ - --query "properties.outputs" -``` - -For example, if you need just the Firewall Private IP address you could retrieve it like this: - -```plaintext -az deployment sub show \ - --name "myMissionLandingZone" \ - --query "properties.outputs.firewallPrivateIPAddress.value" -``` - -Or, if you need just the Log Analytics Workspace that performs central logging you could retrieve it like this: - -```plaintext -az deployment sub show \ - --name "myMissionLandingZone" \ - --query "properties.outputs.logAnalyticsWorkspaceResourceId.value" -``` - -Or, say you wanted to deploy resources into the Identity spoke. You could retrieve information about the Identity spoke by querying it from the `properties.outputs.spokes` array like this: - -```plaintext -az deployment sub show \ - --name "myMissionLandingZone" \ - --query "properties.outputs.spokes.value[?name=='identity']" -``` - -Which would return an output similar to: - -```json -[ - { - "name": "identity", - "networkSecurityGroupName": "identity-nsg", - "networkSecurityGroupResourceId": ".../providers/Microsoft.Network/networkSecurityGroups/identity-nsg", - "resourceGroupId": ".../resourceGroups/mlz-identity", - "resourceGroupName": "mlz-identity", - "subnetAddressPrefix": "10.0.110.0/27", - "subnetName": "identity-subnet", - "subscriptionId": "", - "virtualNetworkName": "identity-vnet", - "virtualNetworkResourceId": ".../providers/Microsoft.Network/virtualNetworks/identity-vnet" - } -] -``` - -Bicep templates, the Azure CLI, and JMESpath queries allows you to manually, or in an automated fashion, compose infrastructure incrementally and pass output from one template as input to another. - -Read more about `az deployment` at: [https://docs.microsoft.com](https://docs.microsoft.com/en-us/cli/azure/deployment?view=azure-cli-latest) - -Read more about JMESPath queries at: - -## Naming Conventions - -By default, Mission LZ resources are named according to a naming convention that uses the mandatory `resourcePrefix` parameter and the optional `resourceSuffix` parameter (that is defaulted to `mlz`). - -### Default Naming Convention Example - -Let's look at an example using `--parameters resourcePrefix=FOO` and `--parameters resourceSuffix=BAR` - -- In `mlz.bicep` you will find a variable titled `namingConvention`: - - ```bicep - var namingConvention = '${toLower(resourcePrefix)}-${resourceToken}-${nameToken}-${toLower(resourceSuffix)}' - # this generates a value of: foo-${resourceToken}-${nameToken}-bar - ``` - -- This naming convention uses Bicep's `replace()` function to substitute resource abbreviations for `resourceToken` and resource names for `nameToken`. - -- For example, when naming the Hub Resource Group, first the `resourceToken` is substituted with the recommended abbreviation `rg`: - - ```bicep - var resourceGroupNamingConvention = replace(namingConvention, resourceToken, 'rg') - # this generates a value of: foo-rg-${nameToken}-bar - ``` - -- Then, the `nameToken` is substituted with the Mission LZ name `hub`: - - ```bicep - var hubResourceGroupName = replace(resourceGroupNamingConvention, nameToken, 'hub') - # this generates a value of: foo-rg-hub-bar - ``` - -- Finally, the `hubResourceGroupName` is assigned to the resource group `name` parameter: - - ```bicep - params: { - name: hubResourceGroupName # this is the calculated value 'foo-rg-hub-bar' - location: location - tags: calculatedTags - } - ``` - -### Modifying The Naming Convention - -You can modify this naming convention to suit your needs. - -- In `mlz.bicep` you can modify the root naming convention. This is the default convention: - - ```bicep - var namingConvention = '${toLower(resourcePrefix)}-${resourceToken}-${nameToken}-${toLower(resourceSuffix)}' - ``` - -- Say you did not want to use the `resourceSuffix` value, but instead wanted to add your own token to the naming convention like `team`: - -- First, you added the new parameter `team`: - - ```bicep - @allowedValues([ - 'admin' - 'marketing' - 'sales' - ]) - param team - ``` - -- Then, you modified the naming convention to allow for mixed case `resourcePrefix` values and your new `team` value (while retaining the token identifiers `resourceToken` and `nameToken`): - - ```bicep - var namingConvention = '${resourcePrefix}-${team}-${resourceToken}-${nameToken}' - ``` - -- Now, given a `--parameters resourcePrefix=FOO` and `--parameters team=sales` the generated Hub Resource Group Name would be: - - ```plaintext - params: { - name: hubResourceGroupName # this is the calculated value 'FOO-sales-rg-hub' - location: location - tags: calculatedTags - } - ``` - -## Cleanup - -The Bicep/ARM deployment of Mission Landing Zone can be deleted with two steps: - -1. Delete all resource groups. -1. Delete the diagnostic settings deployed at the subscription level. - -> NOTE: If you deploy and delete Mission Landing Zone in the same subscription multiple times without deleting the subscription-level diagnostic settings, the sixth deployment will fail. Azure has a limit of five diagnostic settings per subscription. The error will be similar to this: `"The limit of 5 diagnostic settings was reached."` - -To delete the diagnostic settings from the Azure Portal: choose the subscription blade, then Activity log in the left panel. At the top of the Activity log screen click the Diagnostics settings button. From there you can click the Edit setting link and delete the diagnostic setting. - -To delete the diagnotic settings in script, use the AZ CLI or PowerShell. An AZ CLI example is below: - -```BASH -# View diagnostic settings in the current subscription -az monitor diagnostic-settings subscription list --query value[] --output table - -# Delete a diagnostic setting -az monitor diagnostic-settings subscription delete --name -``` - -## Development Pre-requisites - -If you want to develop with Bicep you'll need these: - -1. Install Azure CLI -1. Install Bicep - -However, you don't need to develop with Bicep to deploy the compiled `mlz.json` in this repository. +# Mission Landing Zone Bicep Template + +This folder contains the Bicep template `mlz.bicep` for deploying Mission Landing Zone. See the [Deployment Guide for Bicep](../../docs/deployment-guide-bicep.md) for detailed instructions on how to use the template. + +## Parameters + + +Parameter name | Required | Description +-------------- | -------- | ----------- +`resourcePrefix` | Yes | A prefix, 3-10 alphanumeric characters without whitespace, used to prefix resources and generate uniqueness for resources with globally unique naming requirements like Storage Accounts and Log Analytics Workspaces +`resourceSuffix` | No | A suffix, 3 to 6 characters in length, to append to resource names (e.g. "dev", "test", "prod", "mlz"). It defaults to "mlz". +`hubSubscriptionId` | No | The subscription ID for the Hub Network and resources. It defaults to the deployment subscription. +`identitySubscriptionId` | No | The subscription ID for the Identity Network and resources. It defaults to the deployment subscription. +`operationsSubscriptionId` | No | The subscription ID for the Operations Network and resources. It defaults to the deployment subscription. +`sharedServicesSubscriptionId` | No | The subscription ID for the Shared Services Network and resources. It defaults to the deployment subscription. +`location` | No | The region to deploy resources into. It defaults to the deployment location. +`deploymentNameSuffix` | No | A suffix to use for naming deployments uniquely. It defaults to the Bicep resolution of the "utcNow()" function. +`tags` | No | A string dictionary of tags to add to deployed resources. See https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources?tabs=json#arm-templates for valid settings. +`hubVirtualNetworkAddressPrefix` | No | The CIDR Virtual Network Address Prefix for the Hub Virtual Network. +`hubSubnetAddressPrefix` | No | The CIDR Subnet Address Prefix for the default Hub subnet. It must be in the Hub Virtual Network space. +`firewallClientSubnetAddressPrefix` | No | The CIDR Subnet Address Prefix for the Azure Firewall Subnet. It must be in the Hub Virtual Network space. It must be /26. +`firewallManagementSubnetAddressPrefix` | No | The CIDR Subnet Address Prefix for the Azure Firewall Management Subnet. It must be in the Hub Virtual Network space. It must be /26. +`identityVirtualNetworkAddressPrefix` | No | The CIDR Virtual Network Address Prefix for the Identity Virtual Network. +`identitySubnetAddressPrefix` | No | The CIDR Subnet Address Prefix for the default Identity subnet. It must be in the Identity Virtual Network space. +`operationsVirtualNetworkAddressPrefix` | No | The CIDR Virtual Network Address Prefix for the Operations Virtual Network. +`operationsSubnetAddressPrefix` | No | The CIDR Subnet Address Prefix for the default Operations subnet. It must be in the Operations Virtual Network space. +`sharedServicesVirtualNetworkAddressPrefix` | No | The CIDR Virtual Network Address Prefix for the Shared Services Virtual Network. +`sharedServicesSubnetAddressPrefix` | No | The CIDR Subnet Address Prefix for the default Shared Services subnet. It must be in the Shared Services Virtual Network space. +`firewallSkuTier` | No | [Standard/Premium] The SKU for Azure Firewall. It defaults to "Premium". +`firewallThreatIntelMode` | No | [Alert/Deny/Off] The Azure Firewall Threat Intelligence Rule triggered logging behavior. Valid values are "Alert", "Deny", or "Off". The default value is "Alert". +`firewallIntrusionDetectionMode` | No | [Alert/Deny/Off] The Azure Firewall Intrusion Detection mode. Valid values are "Alert", "Deny", or "Off". The default value is "Alert". +`firewallDiagnosticsLogs` | No | An array of Firewall Diagnostic Logs categories to collect. See "https://docs.microsoft.com/en-us/azure/firewall/firewall-diagnostics#enable-diagnostic-logging-through-the-azure-portal" for valid values. +`firewallDiagnosticsMetrics` | No | An array of Firewall Diagnostic Metrics categories to collect. See "https://docs.microsoft.com/en-us/azure/firewall/firewall-diagnostics#enable-diagnostic-logging-through-the-azure-portal" for valid values. +`firewallClientSubnetServiceEndpoints` | No | An array of Service Endpoints to enable for the Azure Firewall Client Subnet. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-service-endpoints-overview for valid settings. +`firewallClientPublicIPAddressAvailabilityZones` | No | An array of Azure Firewall Public IP Address Availability Zones. It defaults to empty, or "No-Zone", because Availability Zones are not available in every cloud. See https://docs.microsoft.com/en-us/azure/virtual-network/ip-services/public-ip-addresses#sku for valid settings. +`firewallManagementSubnetServiceEndpoints` | No | An array of Service Endpoints to enable for the Azure Firewall Management Subnet. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-service-endpoints-overview for valid settings. +`firewallManagementPublicIPAddressAvailabilityZones` | No | An array of Azure Firewall Public IP Address Availability Zones. It defaults to empty, or "No-Zone", because Availability Zones are not available in every cloud. See https://docs.microsoft.com/en-us/azure/virtual-network/ip-services/public-ip-addresses#sku for valid settings. +`publicIPAddressDiagnosticsLogs` | No | An array of Public IP Address Diagnostic Logs for the Azure Firewall. See https://docs.microsoft.com/en-us/azure/ddos-protection/diagnostic-logging?tabs=DDoSProtectionNotifications#configure-ddos-diagnostic-logs for valid settings. +`publicIPAddressDiagnosticsMetrics` | No | An array of Public IP Address Diagnostic Metrics for the Azure Firewall. See https://docs.microsoft.com/en-us/azure/ddos-protection/diagnostic-logging?tabs=DDoSProtectionNotifications for valid settings. +`hubVirtualNetworkDiagnosticsLogs` | No | An array of Network Diagnostic Logs to enable for the Hub Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#logs for valid settings. +`hubVirtualNetworkDiagnosticsMetrics` | No | An array of Network Diagnostic Metrics to enable for the Hub Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#metrics for valid settings. +`hubNetworkSecurityGroupRules` | No | An array of Network Security Group Rules to apply to the Hub Virtual Network. See https://docs.microsoft.com/en-us/azure/templates/microsoft.network/networksecuritygroups/securityrules?tabs=bicep#securityrulepropertiesformat for valid settings. +`hubNetworkSecurityGroupDiagnosticsLogs` | No | An array of Network Security Group diagnostic logs to apply to the Hub Virtual Network. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-nsg-manage-log#log-categories for valid settings. +`hubNetworkSecurityGroupDiagnosticsMetrics` | No | An array of Network Security Group Metrics to apply to enable for the Hub Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#metrics for valid settings. +`hubSubnetServiceEndpoints` | No | An array of Service Endpoints to enable for the Hub subnet. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-service-endpoints-overview for valid settings. +`identityVirtualNetworkDiagnosticsLogs` | No | An array of Network Diagnostic Logs to enable for the Identity Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#logs for valid settings. +`identityVirtualNetworkDiagnosticsMetrics` | No | An array of Network Diagnostic Metrics to enable for the Identity Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#metrics for valid settings. +`identityNetworkSecurityGroupRules` | No | An array of Network Security Group Rules to apply to the Identity Virtual Network. See https://docs.microsoft.com/en-us/azure/templates/microsoft.network/networksecuritygroups/securityrules?tabs=bicep#securityrulepropertiesformat for valid settings. +`identityNetworkSecurityGroupDiagnosticsLogs` | No | An array of Network Security Group diagnostic logs to apply to the Identity Virtual Network. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-nsg-manage-log#log-categories for valid settings. +`identityNetworkSecurityGroupDiagnosticsMetrics` | No | An array of Network Security Group Metrics to apply to enable for the Identity Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#metrics for valid settings. +`identitySubnetServiceEndpoints` | No | An array of Service Endpoints to enable for the Identity subnet. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-service-endpoints-overview for valid settings. +`operationsVirtualNetworkDiagnosticsLogs` | No | An array of Network Diagnostic Logs to enable for the Operations Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#logs for valid settings. +`operationsVirtualNetworkDiagnosticsMetrics` | No | An array of Network Diagnostic Metrics to enable for the Operations Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#metrics for valid settings. +`operationsNetworkSecurityGroupRules` | No | An array of Network Security Group rules to apply to the Operations Virtual Network. See https://docs.microsoft.com/en-us/azure/templates/microsoft.network/networksecuritygroups/securityrules?tabs=bicep#securityrulepropertiesformat for valid settings. +`operationsNetworkSecurityGroupDiagnosticsLogs` | No | An array of Network Security Group diagnostic logs to apply to the Operations Virtual Network. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-nsg-manage-log#log-categories for valid settings. +`operationsNetworkSecurityGroupDiagnosticsMetrics` | No | An array of Network Security Group Diagnostic Metrics to enable for the Operations Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#metrics for valid settings. +`operationsSubnetServiceEndpoints` | No | An array of Service Endpoints to enable for the Operations subnet. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-service-endpoints-overview for valid settings. +`sharedServicesVirtualNetworkDiagnosticsLogs` | No | An array of Network Diagnostic Logs to enable for the SharedServices Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#logs for valid settings. +`sharedServicesVirtualNetworkDiagnosticsMetrics` | No | An array of Network Diagnostic Metrics to enable for the SharedServices Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#metrics for valid settings. +`sharedServicesNetworkSecurityGroupRules` | No | An array of Network Security Group rules to apply to the SharedServices Virtual Network. See https://docs.microsoft.com/en-us/azure/templates/microsoft.network/networksecuritygroups/securityrules?tabs=bicep#securityrulepropertiesformat for valid settings. +`sharedServicesNetworkSecurityGroupDiagnosticsLogs` | No | An array of Network Security Group diagnostic logs to apply to the SharedServices Virtual Network. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-nsg-manage-log#log-categories for valid settings. +`sharedServicesNetworkSecurityGroupDiagnosticsMetrics` | No | An array of Network Security Group Diagnostic Metrics to enable for the SharedServices Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#metrics for valid settings. +`sharedServicesSubnetServiceEndpoints` | No | An array of Service Endpoints to enable for the SharedServices subnet. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-service-endpoints-overview for valid settings. +`deploySentinel` | No | When set to "true", enables Microsoft Sentinel within the Log Analytics Workspace created in this deployment. It defaults to "false". +`logAnalyticsWorkspaceCappingDailyQuotaGb` | No | The daily quota for Log Analytics Workspace logs in Gigabytes. It defaults to "-1" for no quota. +`logAnalyticsWorkspaceRetentionInDays` | No | The number of days to retain Log Analytics Workspace logs. It defaults to "30". +`logAnalyticsWorkspaceSkuName` | No | [Free/Standard/Premium/PerNode/PerGB2018/Standalone] The SKU for the Log Analytics Workspace. It defaults to "PerGB2018". See https://docs.microsoft.com/en-us/azure/azure-monitor/logs/resource-manager-workspace for valid settings. +`logStorageSkuName` | No | The Storage Account SKU to use for log storage. It defaults to "Standard_GRS". See https://docs.microsoft.com/en-us/rest/api/storagerp/srp_sku_types for valid settings. +`deployRemoteAccess` | No | When set to "true", provisions Azure Bastion Host and virtual machine jumpboxes. It defaults to "false". +`bastionHostSubnetAddressPrefix` | No | The CIDR Subnet Address Prefix for the Azure Bastion Subnet. It must be in the Hub Virtual Network space "hubVirtualNetworkAddressPrefix" parameter value. It must be /27 or larger. +`bastionHostPublicIPAddressAvailabilityZones` | No | The Azure Bastion Public IP Address Availability Zones. It defaults to "No-Zone" because Availability Zones are not available in every cloud. See https://docs.microsoft.com/en-us/azure/virtual-network/ip-services/public-ip-addresses#sku for valid settings. +`linuxVmAdminUsername` | No | The administrator username for the Linux Virtual Machine to Azure Bastion remote into. It defaults to "azureuser". +`linuxVmAuthenticationType` | No | [sshPublicKey/password] The authentication type for the Linux Virtual Machine to Azure Bastion remote into. It defaults to "password". +`linuxVmAdminPasswordOrKey` | No | The administrator password or public SSH key for the Linux Virtual Machine to Azure Bastion remote into. See https://docs.microsoft.com/en-us/azure/virtual-machines/linux/faq#what-are-the-password-requirements-when-creating-a-vm- for password requirements. +`linuxVmSize` | No | The size of the Linux Virtual Machine to Azure Bastion remote into. It defaults to "Standard_B2s". +`linuxVmOsDiskCreateOption` | No | The disk creation option of the Linux Virtual Machine to Azure Bastion remote into. It defaults to "FromImage". +`linuxVmOsDiskType` | No | The disk type of the Linux Virtual Machine to Azure Bastion remote into. It defaults to "Standard_LRS". +`linuxVmImagePublisher` | No | The image publisher of the Linux Virtual Machine to Azure Bastion remote into. It defaults to "Canonical". +`linuxVmImageOffer` | No | The image offer of the Linux Virtual Machine to Azure Bastion remote into. It defaults to "UbuntuServer". +`linuxVmImageSku` | No | The image SKU of the Linux Virtual Machine to Azure Bastion remote into. It defaults to "18.04-LTS". +`linuxVmImageVersion` | No | The image version of the Linux Virtual Machine to Azure Bastion remote into. It defaults to "latest". +`linuxNetworkInterfacePrivateIPAddressAllocationMethod` | No | [Static/Dynamic] The public IP Address allocation method for the Linux virtual machine. It defaults to "Dynamic". +`windowsVmAdminUsername` | No | The administrator username for the Windows Virtual Machine to Azure Bastion remote into. It defaults to "azureuser". +`windowsVmAdminPassword` | No | The administrator password the Windows Virtual Machine to Azure Bastion remote into. It must be > 12 characters in length. See https://docs.microsoft.com/en-us/azure/virtual-machines/windows/faq#what-are-the-password-requirements-when-creating-a-vm- for password requirements. +`windowsVmSize` | No | The size of the Windows Virtual Machine to Azure Bastion remote into. It defaults to "Standard_DS1_v2". +`windowsVmPublisher` | No | The publisher of the Windows Virtual Machine to Azure Bastion remote into. It defaults to "MicrosoftWindowsServer". +`windowsVmOffer` | No | The offer of the Windows Virtual Machine to Azure Bastion remote into. It defaults to "WindowsServer". +`windowsVmSku` | No | The SKU of the Windows Virtual Machine to Azure Bastion remote into. It defaults to "2019-datacenter". +`windowsVmVersion` | No | The version of the Windows Virtual Machine to Azure Bastion remote into. It defaults to "latest". +`windowsVmCreateOption` | No | The disk creation option of the Windows Virtual Machine to Azure Bastion remote into. It defaults to "FromImage". +`windowsVmStorageAccountType` | No | The storage account type of the Windows Virtual Machine to Azure Bastion remote into. It defaults to "StandardSSD_LRS". +`windowsNetworkInterfacePrivateIPAddressAllocationMethod` | No | [Static/Dynamic] The public IP Address allocation method for the Windows virtual machine. It defaults to "Dynamic". +`deployPolicy` | No | When set to "true", deploys the Azure Policy set defined at by the parameter "policy" to the resource groups generated in the deployment. It defaults to "false". +`policy` | No | [NIST/IL5/CMMC] Built-in policy assignments to assign, it defaults to "NIST". IL5 is only available for AzureUsGovernment and will switch to NIST if tried in AzureCloud. +`deployASC` | No | When set to "true", enables Azure Security Center for the subscriptions used in the deployment. It defaults to "false". +`emailSecurityContact` | No | Email address of the contact, in the form of john@doe.com + + +## Outputs + +You can use the AZ CLI or PowerShell to retrieve the output values from a deployment, or you can use the Azure Portal to view the output values. See the [Referencing Deployment Output section](../../docs/deployment-guide-bicep.md#reference-deployment-output) in the Deployment Guide for Bicep. + +When the output is saved as a json document from the Azure CLI, these are the paths in the document to all the values. (The `[0..2]` notation indicates an array with three elements.) + +```plaintext +firewallPrivateIPAddress.value +hub.value.networkSecurityGroupName +hub.value.networkSecurityGroupResourceId +hub.value.resourceGroupName +hub.value.resourceGroupResourceId +hub.value.subnetAddressPrefix +hub.value.subnetName +hub.value.subnetResourceId +hub.value.subscriptionId +hub.value.virtualNetworkName +hub.value.virtualNetworkResourceId +logAnalyticsWorkspaceName.value +logAnalyticsWorkspaceResourceId.value +mlzResourcePrefix.value +spokes.value[0..2].name +spokes.value[0..2].networkSecurityGroupName +spokes.value[0..2].networkSecurityGroupResourceId +spokes.value[0..2].resourceGroupId +spokes.value[0..2].resourceGroupName +spokes.value[0..2].subnetAddressPrefix +spokes.value[0..2].subnetName +spokes.value[0..2].subnetResourceId +spokes.value[0..2].subscriptionId +spokes.value[0..2].virtualNetworkName +spokes.value[0..2].virtualNetworkResourceId diff --git a/src/bicep/examples/newWorkload/newWorkload.bicep b/src/bicep/examples/newWorkload/newWorkload.bicep index c0885604e..c11f69198 100644 --- a/src/bicep/examples/newWorkload/newWorkload.bicep +++ b/src/bicep/examples/newWorkload/newWorkload.bicep @@ -20,6 +20,8 @@ param logAnalyticsWorkspaceResourceId string = mlzDeploymentVariables.logAnalyti param firewallPrivateIPAddress string = mlzDeploymentVariables.firewallPrivateIPAddress.Value param virtualNetworkName string = '${workloadName}-vnet' + +@description('The address prefix for the network spoke vnet.') param virtualNetworkAddressPrefix string = '10.0.125.0/26' param virtualNetworkDiagnosticsLogs array = [] param virtualNetworkDiagnosticsMetrics array = [] @@ -39,6 +41,8 @@ param networkSecurityGroupDiagnosticsLogs array = [ param networkSecurityGroupDiagnosticsMetrics array = [] param subnetName string = '${workloadName}-subnet' + +@description('The subnet address prefix for the network spoke vnet.') param subnetAddressPrefix string = '10.0.125.0/27' param subnetServiceEndpoints array = [] diff --git a/src/terraform/README.md b/src/terraform/README.md index d498bad13..3168f238b 100644 --- a/src/terraform/README.md +++ b/src/terraform/README.md @@ -1,385 +1,3 @@ -# Mission LZ Terraform +# Mission Landing Zone Terraform Template -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) - - -> NOTE: Azure Cloud Shell is often our preferred place to deploy from because the AZ CLI and Terraform are already installed. However, sometimes Cloud Shell has different versions of the dependencies from what we have tested and verified, and sometimes there have been bugs in the Terraform Azure RM provider or the AZ CLI that only appear in Cloud Shell. If you are deploying from Azure Cloud Shell and see something unexpected, try the [development container](../../.devcontainer/README.md) or deploy from your machine using locally installed AZ CLI and Terraform. We welcome all feedback and [contributions](../../CONTRIBUTING.md), so if you see something that doesn't make sense, please [create an issue](../../issues/new/choose) or open a [discussion thread](../../discussions). - - -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. - -Looking to assign Azure Policy? This template supports assigning NIST 800-53 policies. See the [policies documentation](../../docs/policies.md) for more information. - -### 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. - -## Assigning Azure Policy - -This template supports assigning NIST 800-53 policies. See the [policies documentation](../../docs/policies.md) for more information. - -You can enable this by providing a `true` value to the `create_policy_assignment` variable. - -At `apply` time: - -```plaintext -terraform apply -var="create_policy_assignment=true" -``` - -Or, by updating `src/terraform/mlz/variables.tf`: - -```terraform -variable "create_policy_assignment" { - description = "Assign Policy to deployed resources?" - type = bool - default = true -} -``` - -## 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. - -The container 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: +This folder contains the Terraform templates for deploying Mission Landing Zone. See the [Deployment Guide for Terraform](../../docs/deployment-guide-terraform.md) for detailed instructions on how to use the templates. diff --git a/src/terraform/mlz/variables.tf b/src/terraform/mlz/variables.tf index 4f3c3984f..9b967d9ad 100644 --- a/src/terraform/mlz/variables.tf +++ b/src/terraform/mlz/variables.tf @@ -24,7 +24,7 @@ variable "location" { } variable "resourcePrefix" { - description = "A name for the deployment. It defaults to dev." + description = "A name for the deployment. It defaults to mlz." type = string default = "mlz" }