diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 2beac7116..7962d112b 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -6,15 +6,15 @@ FROM ubuntu:20.04 ENV DEBIAN_FRONTEND=noninteractive # Terraform, providers and tflint versions -ARG TERRAFORM_VERSION=1.0.3 -ARG AZURERM_VERSION=2.69.0 +ARG TERRAFORM_VERSION=1.0.6 +ARG AZURERM_VERSION=2.76.0 ARG RANDOM_VERSION=3.1.0 ARG TIME_VERSION=0.7.2 -ARG TFLINT_VERSION=0.30.0 -ARG TFLINT_AZURERM=0.11.0 +ARG TFLINT_VERSION=0.32.1 +ARG TFLINT_AZURERM=0.13.1 # Azure CLI version -ARG AZURE_CLI_VERSION=2.26.1-1~focal +ARG AZURE_CLI_VERSION=2.28.0-1~focal # Update distro (software-properties-common installs the add-apt-repository command) RUN apt-get update \ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..5a7bc9b44 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# This group is the default set of reviewers for PRs to main. +@Azure/mission-lz-reviewers \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/issue.md b/.github/ISSUE_TEMPLATE/backlog_item.md similarity index 83% rename from .github/ISSUE_TEMPLATE/issue.md rename to .github/ISSUE_TEMPLATE/backlog_item.md index 5d9cad24b..5dcaae855 100644 --- a/.github/ISSUE_TEMPLATE/issue.md +++ b/.github/ISSUE_TEMPLATE/backlog_item.md @@ -1,6 +1,6 @@ --- -name: Issue -about: Use issues for planned work +name: Backlog item +about: Use backlog items for planned work title: '' labels: '' assignees: '' @@ -15,4 +15,4 @@ assignees: '' **Acceptance Criteria** - -- +- diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md deleted file mode 100644 index ff9288fba..000000000 --- a/.github/ISSUE_TEMPLATE/enhancement.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Enhancement -about: Suggest an idea for this project -title: '' -labels: enhancement -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore index 1dded9f04..ecfd17ea9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + # Terraform artifacts *.tfvars *.terraform @@ -9,48 +10,13 @@ terraform-provider-azurerm_v* terraform-provider-random_v* *.terraform.lock.hcl -# Setup config variables file -mlz.config -saca-hub.tfvars.json -tier-0.tfvars.json -tier-1.tfvars.json -tier-2.tfvars.json -globals.tfvars.json -*.tfvars.json -!*.orig.tfvars.json +# Terraform logs +crash.log -# Bash artifacts -*.vars +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* +*plan* +*.plan* # Mac files .DS_Store - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ -**/Properties/launchSettings.json - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc -**/.idea/ -**/config_output/ -**/exec_output - -# ignore generated output -**/generated-configurations/* -mlz.zip -mlz.tar diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f631d9fbc..3ee28babb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,8 +51,8 @@ These roles demonstrate how we think about doing the work. A single person can o ### Artifacts -- Product backlog: The product backlog is defined using GitHub issues. Issue templates are in the repo for Issues (new development) and bugs. Backlog items (issues and bugs) are grouped into releases and prioritized within each release. See the [product owner process](#product-owner-process) for more details. -- Monthly releases: Each release is defined using a GitHub project. One release is finished each month. We plan major themes for each release, but the actual content of a finished release depends on what is accomplished using our Kanban process. +- Product backlog: The product backlog is defined using GitHub issues. [Issue templates](.github/ISSUE_TEMPLATE) are in the repo for [backlog items (new development) and bugs](https://github.com/Azure/missionlz/issues/new/choose). Issues are grouped into releases and prioritized within each release. See the [product owner process](#product-owner-process) for more details. +- Monthly releases: Each release is defined using a GitHub project. GitHub projects are visible on the [Projects](https://github.com/Azure/missionlz/projects) tab of the GitHub site. One release is finished each month. We plan major themes for each release, but the actual content of a finished release depends on what is accomplished using our Kanban process. - Software increment: Each change to the software is implemented as a git commit to the main branch. GitHub pull requests are used to define and review each commit to main as a squashed merge (all changes combined into a single commit.) See the [development process](#development-process) for more details. ### Events @@ -64,9 +64,9 @@ These roles demonstrate how we think about doing the work. A single person can o ### Development Process -#### Select an Issue +#### Select a Backlog Item -Team members select issues to develop. More than one member can work on a single issue, and pair programming and other collaboration is encouraged. Generally, issues that have higher priority should be done before lower priority issues, but any issue may be selected from the backlog by any team member. +Team members select backlog items or bugs to develop. More than one member can work on a single issue, and pair programming and other collaboration is encouraged. Generally, issues that have higher priority should be done before lower priority issues, but any issue may be selected from the backlog by any team member. #### Create a Branch @@ -86,9 +86,11 @@ Multiple PRs can be created for an issue, but there is usually a single pull req A draft PR can be used to request feedback from the team. +A [`CODEOWNERS`](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners) file defines the set of default reviewers for PRs to main. + #### Review Other PRs -When PRs are requested, review each change and run full test deployment, specifically focused on the areas that have changed. Provide comments and feedback directly related to the PR. +When PRs are requested, review each change and run a full test deployment, specifically focused on the areas that have changed. Provide comments and feedback directly related to the PR. #### Ensure Quality @@ -98,24 +100,20 @@ The main branch is always production quality. The PR reviewer is responsible for #### Product Backlog -The backlog is defined in the form of GitHub issues, including bugs and regular issues. Any team member or external stakeholder can author a backlog item. The product owner is responsible for ensuring that all backlog items in a release meet the standards of being ready for development. The standards include: +The backlog is defined in the form of GitHub issues, including bugs and backlog items. Any team member or external stakeholder can author a backlog item. The product owner is responsible for ensuring that all backlog items in a release meet the standards of being ready for development. The standards include: - A clear title -- A concise benefit/result/outcome that defines the benefit someone would receive when the issue is completed. +- A concise benefit/result/outcome that defines the benefit someone would receive when the issue is completed - An optional tag that defines who will benefit from the issue being completed -- A detailed description that contains more context and may contain implementation details. -- A full list of acceptance criteria that clearly define when the issue is complete. -- Scope that is as small as possible and is also a complete and useful new feature for a stakeholder. +- A detailed description that contains more context and may contain implementation details +- A full list of acceptance criteria that clearly define when the issue is complete +- Scope that is as small as possible and is also a complete and useful new feature for a stakeholder #### Triage The product owner is responsible for ensuring that each issue is fully triaged and is either closed or added to a release backlog. Triage with the team primarily happens at the weekly planning meeting and can also happen via GitHub as comments within an issue. -When new issues are added to the GitHub issues list, the product owner makes sure that a `needs triage` label is added so that the issue will be discussed in the next planning meeting. - -#### Release Definition - -The product owner defines the releases in the form of GitHub projects. One release is defined per month. Each release has one or more themes. The themes are reviewed and agreed upon by the team during the weekly planning meeting. +When new issues are added to the GitHub issues list, the product owner ensures that a `needs triage` label is added so that the issue will be discussed in the next planning meeting. #### Weekly Planning Meeting @@ -128,10 +126,14 @@ The product owner sets the agenda for the meeting. The agenda includes: #### Backlog Prioritization -The product owner is responsible for ensuring that the backlog items are prioritized within each release. Setting priority is a collaborative effort by the team. Priority is defined by the stack rank order of the "To do" column in a release. +The product owner is responsible for ensuring that the backlog items are prioritized within each release. Setting priority is a collaborative effort by the team and usually happens during the weekly planning meeting. Priority is defined by the stack rank order of the "To do" column in a release. #### Architecture The product owner is responsible for ensuring that enough architecture documentation exists for the development team and stakeholders. Developing the architecture is a collaborative effort with the rest of the team. Any team member may contribute to the architecture, and some issues may be added to the backlog for discovery and testing in order to determine the elements of the architecture. +#### Release Definition + +The product owner defines the releases in the form of GitHub projects. One release is defined per month. Each release has one or more themes. The themes are reviewed and agreed upon by the team during the weekly planning meeting. + **Thank You!** - Your contributions to open source, large or small, make projects like this possible. Thank you for taking the time to contribute. diff --git a/docs/images/20210419_missionlz_as_of_Aug2021_Policy.png b/docs/images/20210419_missionlz_as_of_Aug2021_Policy.png new file mode 100644 index 000000000..cb1a816a2 Binary files /dev/null and b/docs/images/20210419_missionlz_as_of_Aug2021_Policy.png differ diff --git a/docs/images/missionlz_as_of_july2021.jpg b/docs/images/missionlz_as_of_july2021.jpg new file mode 100644 index 000000000..bff443cea Binary files /dev/null and b/docs/images/missionlz_as_of_july2021.jpg differ diff --git a/docs/policies.md b/docs/policies.md new file mode 100644 index 000000000..7d45dc681 --- /dev/null +++ b/docs/policies.md @@ -0,0 +1,92 @@ +# Mission Landing Zone Regulatory Compliance - NIST Policies + +As part of Mission Landing Zone (MLZ) it's been a goal to ensure deployments have the tools and resources available that allow it to be compliant with most regulations across industries. This does not mean that workloads are compliant, but it does mean that the technologies in use can be compliant. This is caused by not only the varying number of compliance bodies involved and and the regulations they mandate but also caused by the decisions required by how and what controls are followed. + +For the purposes of this documentation we created an example method in which the MLZ deployment can be audited for current National Institute of Standards and Technology (NIST) controls and requirements using [Azure Policies built in initiative](https://docs.microsoft.com/en-us/azure/governance/policy/samples/nist-sp-800-53-r4) for NIST 800-53. _Note: this is focused on NIST controls that have built in policies in Azure clouds._ + +![Policy and the MLZ deployment footprint](images/20210419_missionlz_as_of_Aug2021_Policy.png) + +## Known Issues + +Currently there are a set of known issues with this approach. The first and somewhat important detail is that these policies are based on built in policies available in the different Azure environments. There are some variances currently between clouds. This will always happen when separate isolated environments have different deployment cycles but also can be based on preview testing versus generally available components in one cloud environment versus another. + +A secondary issue comes from the method in which the assignment is deployed. This results in 'out of band' requirements for customers. In particular, the current built-in NIST initiative has a couple policies attached that modify and/or deploy if a resource doesn't exist. Example, VM extensions for guest policy configuration would be deployed if they don't exist in the VM. These types of policies require a managed identity be created that the Policy engine can use to take these actions. This managed identity must have contributor access to the resources but deploying as a contributor and not owner limits the ability. The terraform MLZ deployment as it is today using service principles with contributor rights cannot make this role assignment but the managed identity is created. This is by design for security purposes. + +The final note is that these are audits based on NIST controls and recommendations that will require out of band work. As an example, storage account redundancy and encryption will require a decision process on what MLZ is using as temporary storage for logs versus requirements for the workloads. For example, encryption can be accomplished with multiple key models, which one is required for what category of data? + +## Deploying + +Deploying policy assignments for NIST along with a standard deployment of MLZ is simple and described below. This example will add a separate assignment of the built in NIST initiative per resource group in the deployment. + +### Deploying with Bicep + +To include one of the built in Azure policy initiatives for NIST 800-53, CMMC Level 3 or DoD IL5 compliance add the parameter with one of the following, NIST, IL5 or CMMC. For example: + +```plaintext +az deployment sub create \ + --location eastus \ + --template-file mlz.bicep \ + --parameters policy= +``` + +Or, you can apply policy 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= +``` + +### Deploying with Terraform + +By default, the Terraform implementaiton at `src/terraform/mlz/main.tf` will assign the NIST 800-53 policies. You can disable this by providing a `false` value to the `create_policy_assignment` variable: + +```plaintext +cd src/terraform/mlz +terraform init +terraform apply -var="create_policy_assignment=false" +``` + +After the resources are deployed, you will need to go into go into each assignment and retrieve the managed identity and modify its role access to contributor scoped to the associated resource group. This is due to the initiative including modify and deploy policies that act on resources, like deploying the require policy guest configuration extensions to VMs. + +## Modifying + +### Modifying with Bicep + +The project stores well-known policies at [src/bicep/modules/policies](../src/bicep/modules/policies) where 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). + +### Modifying with Terraform + +This project uses a custom terraform module called 'policy-assignments'. This can be modified for adding additional initiatives if desired. The module deployments retrieve their parameter values from a local json file stored in the module directory named 'nist-parameter-values' and named after the cloud environment they are deploying to, public or usgovernment. + +Example parameters file snippet: + +```arm +{ + "listOfMembersToExcludeFromWindowsVMAdministratorsGroup": + { + "value": "admin" + }, + "listOfMembersToIncludeInWindowsVMAdministratorsGroup": + { + "value": "azureuser" + }, + "logAnalyticsWorkspaceIdforVMReporting": + { + "value": ${jsonencode(laws_instance_id)} + }, + "IncludeArcMachines": + { + "value": "true" + } +``` + +In the above example the 'logAnalyticsWorkspaceIdforVMReporting' is retrieved from the running terraform deployment variables. This could be modified to use a central logging workspace if desired. + +## What's Next + +While this is only a start, the NIST controls included in the built-in initiatives are a good start to understanding requirements on top of MLZ for compliance. In the near future the hopes are for this to be expanded with additional built-in initiatives as well as offering an option to create your own initiative and custom policies. Potential additions will be server baselines, IL compliances, and custom policies. diff --git a/src/bicep/README.md b/src/bicep/README.md index 263fc0941..9650f2096 100644 --- a/src/bicep/README.md +++ b/src/bicep/README.md @@ -1,51 +1,43 @@ # MLZ Bicep -## 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 Bicep to deploy the compiled `mlz.json` in this repository. - ## Deployment ### Deployment Pre-requisites -You can deploy with the Azure Portal, the Azure CLI, or with both in an Air-Gapped Cloud. But first, you'll need these pre-requisites: +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 -1. Contributor RBAC permissions to that subscription +1. At least one Azure Subscription +1. At least [Contributor RBAC permissions](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#all) to that subscription -### Azure Portal +Are you deploying into a cloud other than `AzureCloud` like say `AzureUsGovernment`? See [Deploying to Other Clouds](#Deploying-to-Other-Clouds). -#### AzureCloud +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. -[![Deploy To Azure](../../docs/images/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fazure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json) +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. -#### AzureUSGovernment +### Azure CLI -[![Deploy To Azure US Gov](../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fazure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json) +Use `az deployment sub` to deploy MLZ across 1:M subscriptions (and `az deployment sub create --help` for more information). -### Azure CLI +#### Single subscription deployment -Use `az deployment sub` to deploy MLZ across 1:M subscriptions (and `az deployment sub create --help` for more information): +This is the minimum command necessary to deploy Mission LZ (replacing `mlz.bicep` with `mlz.json` if I'm disconnected from the internet or do not have an installation of [Bicep](https://aka.ms/bicep) available): ```plaintext -# az bicep install - -# the minimum needed to deploy (deployment will occur in your default subscription): az deployment sub create \ --location eastus \ - --name test \ --template-file ./mlz.bicep +``` + +#### Multiple subscription deployment -# to deploy into multiple subscriptions specify the `--parameters` flag and pass `key=value` arguments: +I can deploy into multiple subscriptions by specifying the `--parameters` flag and passing `key=value` arguments: + +```plaintext az deployment sub create \ --subscription $deploymentSubscription \ --location eastus \ - --name multisubtest \ + --name multiSubscriptionTest \ --template-file ./mlz.bicep \ --parameters \ hubSubscriptionId=$hubSubscriptionId \ @@ -54,30 +46,48 @@ az deployment sub create \ 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 -Supply a different deployment `--location` or override variables with the `--parameters` options: +If I'm deploying to another cloud, say Azure Government, I will first login to that cloud... + +Logging into `AzureUsGovernment`: ```plaintext -# if I were deploying into AzureUSGovernment for example: az cloud set -n AzureUsGovernment +az login +``` + +...and supply a different value for the deployment `--location` argument: + +```plaintext az deployment sub create \ - --subscription $deploymentSubscription \ --location usgovvirginia \ - --name multisubtest \ - --template-file ./mlz.bicep \ - --parameters \ - hubSubscriptionId=$hubSubscriptionId \ - identitySubscriptionId=$identitySubscriptionId \ - operationsSubscriptionId=$operationsSubscriptionId \ - sharedServicesSubscriptionId=$sharedServicesSubscriptionId + --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). + +### Azure Portal + +You can also deploy Mission LZ from the Azure Portal. The compiled JSON ARM template of `mlz.bicep` can be executed from the Custom Deployment feature. + +There is work in progress to provide a more elegant user-interface, but today, with the compiled output of `mlz.bicep`, you can set the deployment subscription and a deployment region and click 'Create' to start deployment. + +#### AzureCloud + +[![Deploy To Azure](../../docs/images/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fmlz.json) + +#### AzureUSGovernment + +[![Deploy To Azure US Gov](../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fmlz.json) + ### Air-Gapped Clouds -#### Manually upload and deploy from Portal +#### Air-Gapped Clouds Deployment from the Azure Portal -1. Save `mlz.json` to disk: +1. Save `mlz.json` to disk: 1. Create a deployment using the 'Custom Deployment' feature: or 1. Click 'Build your own template in the editor' 1. Click 'Load file' @@ -87,18 +97,16 @@ az deployment sub create \ Check out this GIF in the docs to see a visual explanation: [../../docs/images/custom_template_deployment.gif](../../docs/images/custom_template_deployment.gif) -#### Deploy with Azure CLI +#### Air-Gapped Clouds Deployment with Azure CLI -If I were in an environment that didn't have a bicep installation available (like an air-gapped cloud), I could always deploy the `az bicep build` generated ARM template `mlz.json`: +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 bicep build -f ./mlz.bicep --outfile mlz.json - -az cloud set -n AzureUsGovernment +az cloud set -n az deployment sub create \ --subscription $deploymentSubscription \ - --location usgovvirginia \ + --location \ --name multisubtest \ --template-file ./mlz.json \ --parameters \ @@ -131,12 +139,14 @@ az deployment group create \ --parameters logAnalyticsWorkspaceResourceGroupName= ``` -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). - 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 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 @@ -151,6 +161,8 @@ az deployment sub create \ --parameters windowsVmAdminPassword="$my_password" ``` +Then, once you've deployed the virtual machines and Bastion Host, use these docs to connect with the provided password: + ### 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: @@ -171,4 +183,13 @@ az deployment sub create \ For more information on generating a public/private key pair see . -Then, once you've deployed the virtual machine and Bastion Host, use these docs to connect: +Then, once you've deployed the virtual machines and Bastion Host, use these docs to connect with an SSH Key: + +## 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. diff --git a/src/bicep/examples/newWorkload/README.md b/src/bicep/examples/newWorkload/README.md index f2e915e7a..9c7c12af7 100644 --- a/src/bicep/examples/newWorkload/README.md +++ b/src/bicep/examples/newWorkload/README.md @@ -117,7 +117,7 @@ az deployment sub create \ Or, completely experimentally, try the Portal: #### AzureCloud -[![Deploy To Azure](../../../../docs/images/deploytoazure.svg?sanitze=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fazure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fexamples%2FnewWorkload%2FnewWorkload.json) +[![Deploy To Azure](../../../../docs/images/deploytoazure.svg?sanitze=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fexamples%2FnewWorkload%2FnewWorkload.json) #### AzureUSGovernment -[![Deploy To Azure US Gov](../../../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fazure%2Fmissionlz%2Fbicep%2Fexamples%2FnewWorkload%2FnewWorkload.json) +[![Deploy To Azure US Gov](../../../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fexamples%2FnewWorkload%2FnewWorkload.json) diff --git a/src/bicep/examples/remoteAccess/README.md b/src/bicep/examples/remoteAccess/README.md index 1c0e73cd1..d1243497c 100644 --- a/src/bicep/examples/remoteAccess/README.md +++ b/src/bicep/examples/remoteAccess/README.md @@ -114,8 +114,8 @@ Or, completely experimentally, try the Portal: ### AzureCloud -[![Deploy To Azure](../../../../docs/images/deploytoazure.svg?sanitze=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fglennmusa%2Fmissionlz%2Fglennmusa%2Fbicep%2Fsrc%2Fbicep%2Fexamples%2FremoteAccess%2Fmain.json) +[![Deploy To Azure](../../../../docs/images/deploytoazure.svg?sanitze=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fexamples%2FremoteAccess%2Fmain.json) ### AzureUSGovernment -[![Deploy To Azure US Gov](../../../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fglennmusa%2Fmissionlz%2Fglennmusa%2Fbicep%2Fexamples%2FremoteAccess%2Fmain.json) +[![Deploy To Azure US Gov](../../../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fexamples%2FremoteAccess%2Fmain.json) diff --git a/src/bicep/mlz.bicep b/src/bicep/mlz.bicep index 83834a705..6683fbd7c 100644 --- a/src/bicep/mlz.bicep +++ b/src/bicep/mlz.bicep @@ -255,7 +255,7 @@ module sharedServicesVirtualNetworkPeering './modules/spokeNetworkPeering.bicep' //// policy module hubPolicyAssignment './modules/policyAssignment.bicep' = { - name: 'assign-policy-${hubResourceGroupName}' + name: 'assign-policy-hub-${nowUtc}' scope: resourceGroup(hubSubscriptionId, hubResourceGroupName) params: { builtInAssignment: policy @@ -266,7 +266,7 @@ module hubPolicyAssignment './modules/policyAssignment.bicep' = { } module operationsPolicyAssignment './modules/policyAssignment.bicep' = { - name: 'assign-policy-${operationsResourceGroupName}' + name: 'assign-policy-operations-${nowUtc}' scope: resourceGroup(operationsSubscriptionId, operationsResourceGroupName) params: { builtInAssignment: policy @@ -277,7 +277,7 @@ module operationsPolicyAssignment './modules/policyAssignment.bicep' = { } module sharedServicesPolicyAssignment './modules/policyAssignment.bicep' = { - name: 'assign-policy-${sharedServicesResourceGroupName}' + name: 'assign-policy-sharedServices-${nowUtc}' scope: resourceGroup(sharedServicesSubscriptionId, sharedServicesResourceGroupName) params: { builtInAssignment: policy @@ -288,7 +288,7 @@ module sharedServicesPolicyAssignment './modules/policyAssignment.bicep' = { } module identityPolicyAssignment './modules/policyAssignment.bicep' = { - name: 'assign-policy-${identityResourceGroupName}' + name: 'assign-policy-identity-${nowUtc}' scope: resourceGroup(identitySubscriptionId, identityResourceGroupName) params: { builtInAssignment: policy @@ -299,7 +299,7 @@ module identityPolicyAssignment './modules/policyAssignment.bicep' = { } module hubSubscriptionCreateActivityLogging './modules/centralLogging.bicep' = { - name: 'deploy-hub-sub-activity-logging' + name: 'activity-logs-hub-${nowUtc}' scope: subscription(hubSubscriptionId) params: { diagnosticSettingName: 'log-hub-sub-activity-to-${logAnalyticsWorkspace.outputs.name}' @@ -308,7 +308,7 @@ module hubSubscriptionCreateActivityLogging './modules/centralLogging.bicep' = { } module operationsSubscriptionCreateActivityLogging './modules/centralLogging.bicep' = if(hubSubscriptionId != operationsSubscriptionId) { - name: 'deploy-operations-sub-activity-logging' + name: 'activity-logs-operations-${nowUtc}' scope: subscription(operationsSubscriptionId) params: { diagnosticSettingName: 'log-operations-sub-activity-to-${logAnalyticsWorkspace.outputs.name}' @@ -317,7 +317,7 @@ module operationsSubscriptionCreateActivityLogging './modules/centralLogging.bic } module identitySubscriptionCreateActivityLogging './modules/centralLogging.bicep' = if(hubSubscriptionId != identitySubscriptionId) { - name: 'deploy-identity-sub-activity-logging' + name: 'activity-logs-identity-${nowUtc}' scope: subscription(identitySubscriptionId) params: { diagnosticSettingName: 'log-identity-sub-activity-to-${logAnalyticsWorkspace.outputs.name}' @@ -326,7 +326,7 @@ module identitySubscriptionCreateActivityLogging './modules/centralLogging.bicep } module sharedServicesSubscriptionCreateActivityLogging './modules/centralLogging.bicep' = if(hubSubscriptionId != sharedServicesSubscriptionId) { - name: 'deploy-sharedServices-sub-activity-logging' + name: 'activity-logs-sharedServices-${nowUtc}' scope: subscription(sharedServicesSubscriptionId) params: { diagnosticSettingName: 'log-sharedServices-sub-activity-to-${logAnalyticsWorkspace.outputs.name}' diff --git a/src/bicep/mlz.json b/src/bicep/mlz.json index 55ea44937..9036170b4 100644 --- a/src/bicep/mlz.json +++ b/src/bicep/mlz.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.4.613.9944", - "templateHash": "11713630127386255235" + "templateHash": "10197699490604004243" } }, "parameters": { @@ -4475,7 +4475,7 @@ { "type": "Microsoft.Resources/deployments", "apiVersion": "2019-10-01", - "name": "[format('assign-policy-{0}', parameters('hubResourceGroupName'))]", + "name": "[format('assign-policy-hub-{0}', parameters('nowUtc'))]", "subscriptionId": "[parameters('hubSubscriptionId')]", "resourceGroup": "[parameters('hubResourceGroupName')]", "properties": { @@ -4553,7 +4553,7 @@ { "type": "Microsoft.Resources/deployments", "apiVersion": "2019-10-01", - "name": "[format('assign-policy-{0}', parameters('operationsResourceGroupName'))]", + "name": "[format('assign-policy-operations-{0}', parameters('nowUtc'))]", "subscriptionId": "[parameters('operationsSubscriptionId')]", "resourceGroup": "[parameters('operationsResourceGroupName')]", "properties": { @@ -4631,7 +4631,7 @@ { "type": "Microsoft.Resources/deployments", "apiVersion": "2019-10-01", - "name": "[format('assign-policy-{0}', parameters('sharedServicesResourceGroupName'))]", + "name": "[format('assign-policy-sharedServices-{0}', parameters('nowUtc'))]", "subscriptionId": "[parameters('sharedServicesSubscriptionId')]", "resourceGroup": "[parameters('sharedServicesResourceGroupName')]", "properties": { @@ -4709,7 +4709,7 @@ { "type": "Microsoft.Resources/deployments", "apiVersion": "2019-10-01", - "name": "[format('assign-policy-{0}', parameters('identityResourceGroupName'))]", + "name": "[format('assign-policy-identity-{0}', parameters('nowUtc'))]", "subscriptionId": "[parameters('identitySubscriptionId')]", "resourceGroup": "[parameters('identityResourceGroupName')]", "properties": { @@ -4787,7 +4787,7 @@ { "type": "Microsoft.Resources/deployments", "apiVersion": "2019-10-01", - "name": "deploy-hub-sub-activity-logging", + "name": "[format('activity-logs-hub-{0}', parameters('nowUtc'))]", "subscriptionId": "[parameters('hubSubscriptionId')]", "location": "[deployment().location]", "properties": { @@ -4876,7 +4876,7 @@ "condition": "[not(equals(parameters('hubSubscriptionId'), parameters('operationsSubscriptionId')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2019-10-01", - "name": "deploy-operations-sub-activity-logging", + "name": "[format('activity-logs-operations-{0}', parameters('nowUtc'))]", "subscriptionId": "[parameters('operationsSubscriptionId')]", "location": "[deployment().location]", "properties": { @@ -4965,7 +4965,7 @@ "condition": "[not(equals(parameters('hubSubscriptionId'), parameters('identitySubscriptionId')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2019-10-01", - "name": "deploy-identity-sub-activity-logging", + "name": "[format('activity-logs-identity-{0}', parameters('nowUtc'))]", "subscriptionId": "[parameters('identitySubscriptionId')]", "location": "[deployment().location]", "properties": { @@ -5054,7 +5054,7 @@ "condition": "[not(equals(parameters('hubSubscriptionId'), parameters('sharedServicesSubscriptionId')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2019-10-01", - "name": "deploy-sharedServices-sub-activity-logging", + "name": "[format('activity-logs-sharedServices-{0}', parameters('nowUtc'))]", "subscriptionId": "[parameters('sharedServicesSubscriptionId')]", "location": "[deployment().location]", "properties": { diff --git a/src/bicep/ui/README.md b/src/bicep/ui/README.md index 3fe7c3f0a..80c8abe62 100644 --- a/src/bicep/ui/README.md +++ b/src/bicep/ui/README.md @@ -2,6 +2,6 @@ This folder contains a UI template to be executed against an mlz.json file generated from the bicep modules of MLZ. This file is intented for use as a quickstart only. -[![Deploy To Azure](../../../docs/images/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fui%2Fmlz-portal.json) +[![Deploy To Azure](../../../docs/images/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fui%2Fmlz-portal.json) -[![Deploy To Azure Gov](../../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fui%2Fmlz-portal.json) \ No newline at end of file +[![Deploy To Azure Gov](../../../docs/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fbicep%2Fsrc%2Fbicep%2Fmlz.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fui%2Fmlz-portal.json) \ No newline at end of file diff --git a/src/terraform/mlz/main.tf b/src/terraform/mlz/main.tf index 7e99bff05..45dc9b7fa 100644 --- a/src/terraform/mlz/main.tf +++ b/src/terraform/mlz/main.tf @@ -3,11 +3,11 @@ terraform { backend "local" {} - required_version = "= 1.0.3" + required_version = ">= 1.0.3" required_providers { azurerm = { source = "hashicorp/azurerm" - version = "= 2.69.0" + version = "= 2.76.0" } random = { source = "hashicorp/random" @@ -502,3 +502,55 @@ module "jumpbox" { DeploymentName = coalesce(var.deploymentname, local.deploymentname_default) } } + +##################################### +### STAGE 4: Compliance example ### +##################################### + +module "hub-policy-assignment" { + count = var.create_policy_assignment ? 1 : 0 + + providers = { azurerm = azurerm.hub } + source = "../modules/policy-assignments" + depends_on = [azurerm_resource_group.hub, azurerm_log_analytics_workspace.laws] + resource_group_name = azurerm_resource_group.hub.name + laws_instance_id = azurerm_log_analytics_workspace.laws.workspace_id + environment = var.environment # Example "usgovernment" + log_analytics_workspace_resource_id = azurerm_log_analytics_workspace.laws.id +} + +module "tier0-policy-assignment" { + count = var.create_policy_assignment ? 1 : 0 + + providers = { azurerm = azurerm.tier0 } + source = "../modules/policy-assignments" + depends_on = [azurerm_resource_group.tier0, azurerm_log_analytics_workspace.laws] + resource_group_name = azurerm_resource_group.tier0.name + laws_instance_id = azurerm_log_analytics_workspace.laws.workspace_id + environment = var.environment # Example "usgovernment" + log_analytics_workspace_resource_id = azurerm_log_analytics_workspace.laws.id +} + +module "tier1-policy-assignment" { + count = var.create_policy_assignment ? 1 : 0 + + providers = { azurerm = azurerm.tier1 } + source = "../modules/policy-assignments" + depends_on = [azurerm_resource_group.tier1, azurerm_log_analytics_workspace.laws] + resource_group_name = azurerm_resource_group.tier1.name + laws_instance_id = azurerm_log_analytics_workspace.laws.workspace_id + environment = var.environment # Example "usgovernment" + log_analytics_workspace_resource_id = azurerm_log_analytics_workspace.laws.id +} + +module "tier2-policy-assignment" { + count = var.create_policy_assignment ? 1 : 0 + + providers = { azurerm = azurerm.tier2 } + source = "../modules/policy-assignments" + depends_on = [azurerm_resource_group.tier2, azurerm_log_analytics_workspace.laws] + resource_group_name = azurerm_resource_group.tier2.name + laws_instance_id = azurerm_log_analytics_workspace.laws.workspace_id + environment = var.environment # Example "usgovernment" + log_analytics_workspace_resource_id = azurerm_log_analytics_workspace.laws.id +} diff --git a/src/terraform/mlz/variables.tf b/src/terraform/mlz/variables.tf index 902b08833..f3ba172b3 100644 --- a/src/terraform/mlz/variables.tf +++ b/src/terraform/mlz/variables.tf @@ -34,7 +34,7 @@ variable "deploymentname" { ################################# variable "hub_subid" { - description = "Subscription ID for the deployment" + description = "Subscription ID for the Hub deployment" type = string } @@ -287,6 +287,16 @@ variable "jumpbox_linux_vm_version" { default = "latest" } +################################ +# Policy Configuration +################################ + +variable "create_policy_assignment" { + description = "Assign Policy to deployed resources?" + type = bool + default = true +} + ################################# # Tier 0 Configuration ################################# diff --git a/src/terraform/modules/bastion/output.tf b/src/terraform/modules/bastion/outputs.tf similarity index 100% rename from src/terraform/modules/bastion/output.tf rename to src/terraform/modules/bastion/outputs.tf diff --git a/src/terraform/modules/bastion/variables.tf b/src/terraform/modules/bastion/variables.tf index f5034252a..21af31447 100644 --- a/src/terraform/modules/bastion/variables.tf +++ b/src/terraform/modules/bastion/variables.tf @@ -32,5 +32,6 @@ variable "ipconfig_name" { } variable "tags" { - type = map(string) + description = "A mapping of tags which should be assigned to the resource." + type = map(string) } diff --git a/src/terraform/modules/firewall/output.tf b/src/terraform/modules/firewall/outputs.tf similarity index 100% rename from src/terraform/modules/firewall/output.tf rename to src/terraform/modules/firewall/outputs.tf diff --git a/src/terraform/modules/firewall/variables.tf b/src/terraform/modules/firewall/variables.tf index 3b213a345..bf77c6282 100644 --- a/src/terraform/modules/firewall/variables.tf +++ b/src/terraform/modules/firewall/variables.tf @@ -3,66 +3,82 @@ variable "sub_id" { description = "The subscription ID to deploy the Firewall into" + type = string } variable "location" { description = "The location/region to keep all your network resources. To get the list of all locations with table format from azure cli, run 'az account list-locations -o table'" + type = string } variable "resource_group_name" { description = "A container that holds related resources for an Azure solution" + type = string } variable "vnet_name" { description = "The name of the Firewall virtual network" + type = string } variable "vnet_address_space" { description = "The address space to be used for the Firewall virtual network" + type = list(string) } variable "firewall_sku" { description = "The SKU for Azure Firewall" + type = string } variable "client_address_space" { description = "The address space to be used for the Firewall subnets" + type = string } variable "firewall_client_subnet_name" { description = "The name of the Firewall client traffic subnet" + type = string } variable "firewall_management_subnet_name" { description = "The name of the Firewall management traffic subnet" + type = string } variable "firewall_name" { description = "The name of the Firewall" + type = string } variable "firewall_policy_name" { description = "The name of the firewall policy" + type = string } variable "client_ipconfig_name" { description = "The name of the Firewall Client IP Configuration" + type = string } variable "client_publicip_name" { description = "The name of the Firewall Client Public IP" + type = string } variable "management_ipconfig_name" { description = "The name of the Firewall Management IP Configuration" + type = string } variable "management_publicip_name" { description = "The name of the Firewall Management Public IP" + type = string } variable "log_analytics_workspace_resource_id" { description = "The resource id of the Log Analytics Workspace" + type = string } variable "tags" { diff --git a/src/terraform/modules/hub/output.tf b/src/terraform/modules/hub/outputs.tf similarity index 69% rename from src/terraform/modules/hub/output.tf rename to src/terraform/modules/hub/outputs.tf index 3af755247..78b0bb59c 100644 --- a/src/terraform/modules/hub/output.tf +++ b/src/terraform/modules/hub/outputs.tf @@ -26,21 +26,26 @@ output "virtual_network_id" { } output "firewall_client_subnet_name" { - value = azurerm_subnet.fw_client.name + description = "Firewall client subnet name." + value = azurerm_subnet.fw_client.name } output "firewall_management_subnet_name" { - value = azurerm_subnet.fw_mgmt.name + description = "Firewall management subnet name." + value = azurerm_subnet.fw_mgmt.name } output "firewall_client_subnet_id" { - value = azurerm_subnet.fw_client.id + description = "Firewall client subnet ID." + value = azurerm_subnet.fw_client.id } output "firewall_mgmt_subnet_id" { - value = azurerm_subnet.fw_mgmt.id + description = "Firewall management subnet ID." + value = azurerm_subnet.fw_mgmt.id } output "log_analytics_storage_id" { - value = module.hub-network.log_analytics_storage_id + description = "Log Analytics Storage ID." + value = module.hub-network.log_analytics_storage_id } diff --git a/src/terraform/modules/hub/variables.tf b/src/terraform/modules/hub/variables.tf index 9204de755..6b221c3d7 100644 --- a/src/terraform/modules/hub/variables.tf +++ b/src/terraform/modules/hub/variables.tf @@ -3,14 +3,17 @@ variable "resource_group_name" { description = "A container that holds related resources for an Azure solution" + type = string } variable "location" { description = "The location/region to keep all your network resources. To get the list of all locations with table format from azure cli, run 'az account list-locations -o table'" + type = string } variable "vnet_name" { description = "The name of the virtual network" + type = string } variable "vnet_address_space" { diff --git a/src/terraform/modules/jumpbox/output.tf b/src/terraform/modules/jumpbox/outputs.tf similarity index 100% rename from src/terraform/modules/jumpbox/output.tf rename to src/terraform/modules/jumpbox/outputs.tf diff --git a/src/terraform/modules/linux-virtual-machine/output.tf b/src/terraform/modules/linux-virtual-machine/outputs.tf similarity index 100% rename from src/terraform/modules/linux-virtual-machine/output.tf rename to src/terraform/modules/linux-virtual-machine/outputs.tf diff --git a/src/terraform/modules/linux-virtual-machine/variable.tf b/src/terraform/modules/linux-virtual-machine/variables.tf similarity index 98% rename from src/terraform/modules/linux-virtual-machine/variable.tf rename to src/terraform/modules/linux-virtual-machine/variables.tf index 6e2883436..a77ad52e8 100644 --- a/src/terraform/modules/linux-virtual-machine/variable.tf +++ b/src/terraform/modules/linux-virtual-machine/variables.tf @@ -34,6 +34,7 @@ variable "admin_username" { variable "admin_password" { description = "The admin password of the virtual machine" type = string + sensitive = true } variable "publisher" { diff --git a/src/terraform/modules/policy-assignments/main.tf b/src/terraform/modules/policy-assignments/main.tf new file mode 100644 index 000000000..305ba7bd8 --- /dev/null +++ b/src/terraform/modules/policy-assignments/main.tf @@ -0,0 +1,20 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +data "azurerm_resource_group" "rg" { + name = var.resource_group_name +} + +resource "azurerm_resource_group_policy_assignment" "policy_assign" { + name = "NIST Assignment - ${data.azurerm_resource_group.rg.name}" + resource_group_id = data.azurerm_resource_group.rg.id + policy_definition_id = var.policy_id + location = data.azurerm_resource_group.rg.location + identity { + type = "SystemAssigned" + } + # Define parameters for value template file directed to environment + parameters = templatefile("${path.module}/nist-parameter-values/${var.environment}.json.tmpl", { + laws_instance_id = var.laws_instance_id + }) +} diff --git a/src/terraform/modules/policy-assignments/nist-parameter-values/public.json.tmpl b/src/terraform/modules/policy-assignments/nist-parameter-values/public.json.tmpl new file mode 100644 index 000000000..df80a22c6 --- /dev/null +++ b/src/terraform/modules/policy-assignments/nist-parameter-values/public.json.tmpl @@ -0,0 +1,34 @@ +{ + "listOfMembersToExcludeFromWindowsVMAdministratorsGroup": + { + "value": "admin" + }, + "listOfMembersToIncludeInWindowsVMAdministratorsGroup": + { + "value": "azureuser" + }, + "logAnalyticsWorkspaceIdforVMReporting": + { + "value": ${jsonencode(laws_instance_id)} + }, + "IncludeArcMachines": + { + "value": "true" + }, + "MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112": + { + "value": "1.2" + }, + "NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40": + { + "value": "Compliant" + }, + "requiredRetentionDays": + { + "value": "365" + }, + "resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6": + { + "value": "NetworkWatcherRG" + } +} \ No newline at end of file diff --git a/src/terraform/modules/policy-assignments/nist-parameter-values/usgovernment.json.tmpl b/src/terraform/modules/policy-assignments/nist-parameter-values/usgovernment.json.tmpl new file mode 100644 index 000000000..957c53ccb --- /dev/null +++ b/src/terraform/modules/policy-assignments/nist-parameter-values/usgovernment.json.tmpl @@ -0,0 +1,34 @@ +{ + "listOfMembersToExcludeFromWindowsVMAdministratorsGroup": + { + "value": "admin" + }, + "listOfMembersToIncludeInWindowsVMAdministratorsGroup": + { + "value": "azureuser" + }, + "logAnalyticsWorkspaceIdforVMReporting": + { + "value": ${jsonencode(laws_instance_id)} + }, + "IncludeArcMachines": + { + "value": "true" + }, + "MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112": + { + "value": "1.2" + }, + "NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40": + { + "value": "Compliant" + }, + "requiredRetentionDays": + { + "value": "365" + }, + "resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6": + { + "value": "NetworkWatcherRG" + } +} \ No newline at end of file diff --git a/src/terraform/modules/windows-virtual-machine/output.tf b/src/terraform/modules/policy-assignments/outputs.tf similarity index 100% rename from src/terraform/modules/windows-virtual-machine/output.tf rename to src/terraform/modules/policy-assignments/outputs.tf diff --git a/src/terraform/modules/policy-assignments/variables.tf b/src/terraform/modules/policy-assignments/variables.tf new file mode 100644 index 000000000..613c49737 --- /dev/null +++ b/src/terraform/modules/policy-assignments/variables.tf @@ -0,0 +1,30 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +variable "policy_id" { + description = "The Azure policy ID for the NIST 800-53 R4 policy initiative." + type = string + default = "/providers/Microsoft.Authorization/policySetDefinitions/cf25b9c1-bd23-4eb6-bd2c-f4f3ac644a5f" +} + +variable "resource_group_name" { + description = "Resource group name for policy assignment." + type = string +} + +variable "environment" { + description = "The Terraform backend environment e.g. public or usgovernment. It defaults to public." + type = string + default = "public" +} + +variable "laws_instance_id" { + description = "The log analytics workspace ID which will be provided to the underlying policy rules via the policy parameters." + type = string +} + +# Full resource ID used if enabling activity diagnostic logging +variable "log_analytics_workspace_resource_id" { + description = "The resource id of the Log Analytics Workspace" + type = string +} diff --git a/src/terraform/modules/spoke/output.tf b/src/terraform/modules/spoke/outputs.tf similarity index 100% rename from src/terraform/modules/spoke/output.tf rename to src/terraform/modules/spoke/outputs.tf diff --git a/src/terraform/modules/spoke/variables.tf b/src/terraform/modules/spoke/variables.tf index f26371dca..a069db3d0 100644 --- a/src/terraform/modules/spoke/variables.tf +++ b/src/terraform/modules/spoke/variables.tf @@ -3,30 +3,37 @@ variable "location" { description = "The region for spoke network deployment" + type = string } variable "laws_location" { description = "Log Analytics Workspace location" + type = string } variable "laws_workspace_id" { description = "Log Analytics Workspace workspace ID" + type = string } variable "laws_resource_id" { description = "Log Analytics Workspace Azure Resource ID" + type = string } variable "firewall_private_ip" { description = "Private IP of the Firewall" + type = string } variable "spoke_rgname" { description = "Resource Group for the spoke network deployment" + type = string } variable "spoke_vnetname" { description = "Virtual Network Name for the spoke network deployment" + type = string } ################################# @@ -65,5 +72,6 @@ variable "subnets" { } variable "tags" { - type = map(string) + description = "A map of tags to add to all resources" + type = map(string) } diff --git a/src/terraform/modules/subnet/output.tf b/src/terraform/modules/subnet/outputs.tf similarity index 100% rename from src/terraform/modules/subnet/output.tf rename to src/terraform/modules/subnet/outputs.tf diff --git a/src/terraform/modules/subnet/variables.tf b/src/terraform/modules/subnet/variables.tf index 8c04fd503..6b39c3831 100644 --- a/src/terraform/modules/subnet/variables.tf +++ b/src/terraform/modules/subnet/variables.tf @@ -47,11 +47,23 @@ variable "nsg_name" { } variable "tags" { - type = map(string) + description = "A map of tags to add to all resources" + type = map(string) } variable "nsg_rules" { description = "A collection of azurerm_network_security_rule" + type = map(object({ + name = string + priority = string + direction = string + access = string + protocol = string + source_port_range = string + destination_port_range = string + source_address_prefix = string + destination_address_prefix = string + })) } variable "routetable_name" { @@ -66,21 +78,26 @@ variable "firewall_ip_address" { variable "log_analytics_storage_id" { description = "The id of the storage account that stores log analytics diagnostic logs" + type = string } variable "log_analytics_workspace_id" { description = "The id of the log analytics workspace" + type = string } variable "log_analytics_workspace_location" { description = "The location of the log analytics workspace" + type = string } variable "log_analytics_workspace_resource_id" { description = "The resource id of the log analytics workspace" + type = string } variable "flow_log_retention_in_days" { description = "The number of days to retain flow log data" default = "7" + type = number } diff --git a/src/terraform/modules/virtual-network/output.tf b/src/terraform/modules/virtual-network/outputs.tf similarity index 99% rename from src/terraform/modules/virtual-network/output.tf rename to src/terraform/modules/virtual-network/outputs.tf index ca15ea06a..7c68bc9ad 100644 --- a/src/terraform/modules/virtual-network/output.tf +++ b/src/terraform/modules/virtual-network/outputs.tf @@ -1,5 +1,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + output "resource_group_name" { description = "The name of the resource group in which resources are created" value = data.azurerm_resource_group.rg.name diff --git a/src/terraform/modules/virtual-network/variables.tf b/src/terraform/modules/virtual-network/variables.tf index daa30a642..52f61b639 100644 --- a/src/terraform/modules/virtual-network/variables.tf +++ b/src/terraform/modules/virtual-network/variables.tf @@ -3,22 +3,27 @@ variable "location" { description = "The location/region to keep all your network resources. To get the list of all locations with table format from azure cli, run 'az account list-locations -o table'" + type = string } variable "resource_group_name" { description = "A container that holds related resources for an Azure solution" + type = string } variable "vnet_name" { description = "The name of the virtual network" + type = string } variable "vnet_address_space" { description = "The address space to be used for the virtual network" + type = list(string) } variable "log_analytics_workspace_resource_id" { description = "The resource ID of the Log Analytics Workspace to log events from the virtual network" + type = string } variable "tags" { diff --git a/src/terraform/modules/windows-virtual-machine/outputs.tf b/src/terraform/modules/windows-virtual-machine/outputs.tf new file mode 100644 index 000000000..e69de29bb diff --git a/src/terraform/modules/windows-virtual-machine/variables.tf b/src/terraform/modules/windows-virtual-machine/variables.tf index 6e2883436..a77ad52e8 100644 --- a/src/terraform/modules/windows-virtual-machine/variables.tf +++ b/src/terraform/modules/windows-virtual-machine/variables.tf @@ -34,6 +34,7 @@ variable "admin_username" { variable "admin_password" { description = "The admin password of the virtual machine" type = string + sensitive = true } variable "publisher" { diff --git a/src/terraform/tier3/main.tf b/src/terraform/tier3/main.tf index fae3145ff..8c41b50ad 100644 --- a/src/terraform/tier3/main.tf +++ b/src/terraform/tier3/main.tf @@ -3,11 +3,11 @@ terraform { backend "local" {} - required_version = "= 1.0.3" + required_version = ">= 1.0.3" required_providers { azurerm = { source = "hashicorp/azurerm" - version = "= 2.69.0" + version = "= 2.76.0" } } }