Adding LZ secure_vnet_dmz and crafting doc

This commit is contained in:
Arnaud Lheureux 2020-02-28 03:19:04 +00:00
Родитель a1430b5d91
Коммит 889a533526
37 изменённых файлов: 2304 добавлений и 0 удалений

Двоичные данные
_pictures/dmz/dmz-private.png Normal file

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

После

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

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

@ -0,0 +1,307 @@
# How to create your first landing zone in 10 easy steps (part 1)
Coding a landing zone can be a bit intimidating, the white page syndrome can kick-in and you might feel there are too much things to do, so here is my process in creating a landing zone.
## Step 1. Start with the diagram
First thing to know: what are you trying to achieve?
For this article, we are going to take a reference architecture that is published on the Azure Architecture Center, the [Network DMZ between Azure and an on-premises datacenter](https://docs.microsoft.com/en-gb/azure/architecture/reference-architectures/dmz/secure-vnet-dmz).
The architecture looks like this overall:
![DMZ](../../_pictures/dmz/dmz-private.png)
## Step 2. Identify the non-functional requirements
Above are the functional requirements (what your customer wants, and what you think about first) you have to keep in mind all the non-functional requirements. In order to expedite this, I will rely on CAF foundations landing zones, which will set that automatically for me.
You can find the reference of this landing zone [here](../../landingzones/landingzone_caf_foundations/readme.md) and below is the diagram of the components we use:
![Foundations blueprint overview](../../_pictures/caf_foundations/foundations_overall.png)
## Step 3. Do the parts inventory
In the development of the landing zone, my next step is to do the inventory of components that I need. For this case, looking at the diagram, I will need:
- public ip
- site-to-site gateway
- route objects
- azure firewall
- virtual network
- nsg
- subnets
- internal load balancer
- VM
- resource groups
- Azure Bastion (as a replacement of the management subnet, maybe)
I can source those components from:
- From my private repo of components (on my GitHub repo, Azure DevOps, or any other git solution)
- From the [Terraform Registry](https://registry.terraform.io/modules/aztfmod)
- From a [blueprint I previously developped](https://github.com/aztfmod/blueprints)
- Directly from the azurerm [Terraform provider](https://www.terraform.io/docs/providers/azurerm/index.html)
Then I build the following matrix:
| Component | Source | Notes |
| -- | -- | -- |
| public ip | [module](https://registry.terraform.io/modules/aztfmod/caf-public-ip/azurerm/1.0.0) | Standard CAF module |
| site-to-site gateway | [Blueprint](https://github.com/aztfmod/landingzones/tree/master/landingzones/landingzone_vdc_demo) | I might want to reuse the private blueprint I created in another landing zone. |
| route objects | azurem provider | I dont seem to have a module ready to use, so will implement it from provider
| azure firewall | [module](https://registry.terraform.io/modules/aztfmod/caf-azure-firewall/azurerm/1.1.0) | Standard CAF module |
| virtual network | [module](https://registry.terraform.io/modules/aztfmod/caf-virtual-network/azurerm/1.0.0) | using this module allows me to setup Vnet, v-subnets, nsg and diasgnostics / network watcher. |
| nsg | [module](https://registry.terraform.io/modules/aztfmod/caf-virtual-network/azurerm/1.0.0) | using this module allows me to setup Vnet, v-subnets, nsg and diasgnostics / network watcher. |
| subnets | [module](https://registry.terraform.io/modules/aztfmod/caf-virtual-network/azurerm/1.0.0) | using this module allows me to setup Vnet, v-subnets, nsg and diasgnostics / network watcher. |
| internal load balancer | azurem provider | no module in registry
| VM | azurem provider or [module](https://registry.terraform.io/modules/aztfmod/caf-vm/azurerm/0.1.0) | not yet decided |
| azure bastion | [Blueprint](https://github.com/aztfmod/landingzones/tree/master/landingzones/landingzone_vdc_demo) | I might want to reuse the private blueprint I created in another landing zone. |
| resource groups | azurem provider | elementary component |
This list might not be exhaustive yet, but at least I know where to sort components for my first prototype.
### The decision factors
At first you might observe it's easier to use provider as it might handle more elementary objects, and you might find the modules a bit harder to integrate. This is expected. However, when you use a module, you usually leverage more consistency and more best-practices For instance in our scenario, using the azurerm provider, I would have to implement separately: virtual networks, NSG, subnets, and then the logging and analytics components, whereas when I'm leveraging the CAF module, I have all of that taken care of, as well as the logging and analytics, which are based on components that were set up in the caf_foundations landing zone.
## Step 4. Write your prototype
### Making it work once, then two, then many
My next logical step is to start Visual Studio Code and start my first implementation. If its the first time you are authoring a landing zone, you might want to be very iterative and make things work once, then refactor and optimize. The more code you will write, the better you will be and maybe less refactoring will be needed, but first lets start putting the components together.
After cloning the landingzones repo, since I will rely on "landingzone_caf_foundations", I can use the "landingzone_starter" as its a good model to start building on "landingzone_caf_foundations"
Let's open this landing zone and create our first files there:
1. prototype.tf: will contain my code, without much structure at first.
2. variables.tf: will contain my variables.
2. prototype.auto.tfvars: so that I interpolate my variables in a quick (and dirty) way.
Here is my first try:
```hcl
resource "azurerm_resource_group" "myresourcegroup" {
name = "caf-prototype-rg"
location = "Southeastasia"
tags = {
environment = "Dev"
country = "Thailand"
}
}
resource "azurerm_availability_set" "as1" {
name = "as1-web"
location = azurerm_resource_group.myresourcegroup.location
resource_group_name = azurerm_resource_group.myresourcegroup.name
tags = {
environment = "Production"
}
}
etc...
```
You can see that on this iteration, I'm not trying to be smart, I just want to make things work using the components I chose. I will use more variables in my next iteration, after I make the components works together.
Importantly at this stage I want to test:
1. The deployment is working as expected.
2. The life cycle is correct: I must be able to PLAN -> APPLY -> DESTROY. If any of those steps work, your code is not good enough and you must refactor.
At the end of this stage, I should have most of my components as a flat file on my environment, allowing me to check the components are deploying corretly, as expected, I can now work on my first refactoring.
### Standardizing with the lower levels
Next step, I want to make sure I leverage the lower level landing zones (ie: caf_foundations sets for me a couple of very good components, so I will check how to use them) and also to more complex structure like modules for virtual network, and more variables:
```hcl
resource "azurerm_resource_group" "rg_network" {
name = "caf-prototype-rg"
location = local.global_settings.location_map.region1
tags = local.global_settings.tags_hub
}
resource "azurerm_availability_set" "as1" {
name = "as1-web"
location = azurerm_resource_group.rg_network.location
resource_group_name = azurerm_resource_group.rg_network.name
tags = local.global_settings.tags_hub
}
module "core_network" {
source = "aztfmod/caf-virtual-network/azurerm"
version = "1.0.0"
convention = local.global_settings.convention
virtual_network_rg = azurerm_resource_group.rg_network.name
prefix = local.prefix
location = local.global_settings.location_map.region1
networking_object = var.shared_services_vnet
tags = local.global_settings.tags_hub
diagnostics_map = local.caf_foundations_accounting.diagnostics_map
log_analytics_workspace = local.caf_foundations_accounting.log_analytics_workspace
diagnostics_settings = var.shared_services_vnet.diagnostics
}
```
### Leveraging naming convention
I'm putting a little bit more CAF in the environment by using the [standard naming convention module](https://registry.terraform.io/modules/aztfmod/caf-naming/). This will allow names that I input into my environment to be formatted to the CAF recommended name convention. I will use here the "cafrandom" methodology which actually has been set in my caf_foundation landing zone. For that, I'm getting the value from: ```local.global_settings.convention``` I implemented it in the core_network module below, so the modules enforces it for me, but if I need to call it for my resource group, I would do it:
```hcl
module "caf_name_rg" {
source = "aztfmod/caf-naming/azurerm"
version = "~> 0.1.0"
name = var.networking_object.rg.name
type = "rg"
convention = local.global_settings.convention
}
resource "azurerm_resource_group" "rg_network" {
name = module.caf_name_rg.rg
location = local.global_settings.location_map.region1
tags = local.global_settings.tags_hub
}
```
We observed that many people stay at this stage, a very descriptive code, which is OK for one time usage, but is not very maintanable and not very DevOps friendly, so in the next step, we will move from something that works, to something that is usable in entreprise context
## Step 5. Structure your code and variables
Now that we have more experience on the components, we can see the reuse patterns and can create variables that will make it handy to customize this landing zones, like the availability sets, load balancers, etc.
### The variables
At this stage, we will remove all hard-coded values and put in variables anything that must change.
One of the very good aspects of Terraform 0.12 type of syntax is that you can create quite complex objects to describe configuration variables. When you are creating those objects, you haves multiple ways aggregate objects them:
- Group by components: create a variable that describes your resource groups, your availability sets, etc. The advantage of this approach is that its easy to iterate on the modules with a ```for_each``` instruction:
```hcl
load_balancers = {
lb1 = {
ame = "ilb-web"
frontend_name = "PrivateIPAddress-ilb-web"
tags = {
tier = "web"
}
}
lb2 = {
ame = "ilb-app"
frontend_name = "PrivateIPAddress-ilb-app"
tags = {
tier = "app"
}
}
lb3 = {
ame = "ilb-db"
frontend_name = "PrivateIPAddress-ilb-db"
tags = {
tier = "db"
}
}
}
````
- Group by services: thinking about personas that will be involved in managing the different objects and create functional objects: one to describe the web servers configuration, one to describe the application servers, and one to describe the database components.
```hcl
web_tier = {
as = {
name = "as1-web"
tags = {
tier = "web"
}
}
lb = {
name = "ilb-web"
frontend_name = "PrivateIPAddress-ilb-web"
tags = {
tier = "web"
}
}
}
```
For now, we don't know which one is better, I will take the second approach for this illustration.
### The code
Every time we suspect there is a bit of code we can reuse, we can create either a module (low complexity) or a blueprint (a bit more complex and composite). Most of time, you want those module to be developed and stored locally, and once you are more sure of the re-usability and the code quality, then you might want to generalize them in your repositories.
```hcl
resource "azurerm_resource_group" "rg_network" {
name = "${local.prefix}${var.resource_groups.CORE-NET.name}"
location = local.global_settings.location_map.region1
tags = local.global_settings.tags_hub
}
resource "azurerm_availability_set" "as_web" {
name = var.web_tier.as.name
location = azurerm_resource_group.rg_network.location
resource_group_name = azurerm_resource_group.rg_network.name
tags = merge(local.global_settings.tags_hub, var.web_tier.as.tags)
}
resource "azurerm_lb" "ilb_web" {
name = var.web_tier.lb.name
location = azurerm_resource_group.rg_network.location
resource_group_name = azurerm_resource_group.rg_network.name
tags = merge(local.global_settings.tags_hub, var.web_tier.lb.tags)
frontend_ip_configuration {
name = var.web_tier.lb.frontend_name
private_ip_address_allocation = "Dynamic"
subnet_id = lookup(module.mynetwork.vnet_subnets, "Web_tier", null)
}
}
```
My code is functional, but a bit flat, I will now regroup it's features and my criteria will be the reusability of the components: a core network plus a VPN transit together should be a common pattern - so lets put it together and try to have a blueprint.
My directory structure looks like this:
```
landingzone_secure_vnet_dmz
├── net_core
│ ├── bastion
│ ├── ddos_protection
│ ├── vpn_gateway
│ ├── dashboards
├── app_tiers
├── virtual_machines
├── rbac
├── etc...
```
The ```net_core``` will become responsible for all things networking in this environment, it will take all input variables and will generate the output that I will re-inject in other blueprints (subfolders):
```hcl
module "net_core" {
source = "./net_core"
global_settings = local.global_settings
prefix = local.prefix
location = local.global_settings.location_map["region1"]
caf_foundations_accounting = local.caf_foundations_accounting
core_networking = var.core_networking
rg_network = var.rg_network
}
```
The state of the code is stored as a landingzone stored here: [landingzone_secure_vnet_dmz](../../landingzones/landingzone_secure_vnet_dmz/)
I will soon publish part two of this article, discussing:
- Review the landing zones boundaries
- Review your resource groups, RBAC model
- Integrate the testing
- etc.
Start crafting and let me know your feedbacks!
[Back to summary](../README.md)

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

@ -0,0 +1,61 @@
# configuration for application sets
rg_app = {
web_tier = {
name = "-app-frontend"
}
app_tier = {
name = "-app-application"
}
db_tier = {
name = "-app-database"
}
}
web_tier = {
as = {
name = "as-web"
tags = {
tier = "web"
}
}
lb = {
name = "ilb-web"
frontend_name = "PrivateIPAddress-ilb-web"
tags = {
tier = "web"
}
}
}
app_tier = {
as = {
name = "as-app"
tags = {
tier = "app"
}
}
lb = {
name = "ilb-app"
frontend_name = "PrivateIPAddress-ilb-app"
tags = {
tier = "app"
}
}
}
db_tier = {
as = {
name = "as-db"
tags = {
tier = "db"
}
}
lb = {
name = "ilb-app"
frontend_name = "PrivateIPAddress-ilb-db"
tags = {
tier = "db"
}
}
}

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

@ -0,0 +1,79 @@
resource "azurerm_resource_group" "rg_appweb" {
name = "${local.prefix}${var.rg_app.web_tier.name}"
location = local.global_settings.location_map.region1
tags = local.global_settings.tags_hub
}
resource "azurerm_resource_group" "rg_appapp" {
name = "${local.prefix}${var.rg_app.app_tier.name}"
location = local.global_settings.location_map.region1
tags = local.global_settings.tags_hub
}
resource "azurerm_resource_group" "rg_appdb" {
name = "${local.prefix}${var.rg_app.db_tier.name}"
location = local.global_settings.location_map.region1
tags = local.global_settings.tags_hub
}
resource "azurerm_availability_set" "as_web" {
name = var.web_tier.as.name
location = azurerm_resource_group.rg_appweb.location
resource_group_name = azurerm_resource_group.rg_appweb.name
tags = merge(local.global_settings.tags_hub, var.web_tier.as.tags)
platform_fault_domain_count = 2
}
resource "azurerm_lb" "ilb_web" {
name = var.web_tier.lb.name
location = azurerm_resource_group.rg_appweb.location
resource_group_name = azurerm_resource_group.rg_appweb.name
tags = merge(local.global_settings.tags_hub, var.web_tier.lb.tags)
frontend_ip_configuration {
name = var.web_tier.lb.frontend_name
private_ip_address_allocation = "Dynamic"
subnet_id = lookup(module.net_core.core_network.vnet_subnets, "Web_tier", null)
}
}
resource "azurerm_availability_set" "as_app" {
name = "as1-app"
location = azurerm_resource_group.rg_appapp.location
resource_group_name = azurerm_resource_group.rg_appapp.name
tags = merge(local.global_settings.tags_hub, var.web_tier.as.tags)
platform_fault_domain_count = 2
}
resource "azurerm_lb" "ilb-app" {
name = "ilb-app"
location = azurerm_resource_group.rg_appapp.location
resource_group_name = azurerm_resource_group.rg_appapp.name
frontend_ip_configuration {
name = "PrivateIPAddress-ilb-app"
private_ip_address_allocation = "Dynamic"
subnet_id = lookup(module.net_core.core_network.vnet_subnets, "Business_tier", null)
}
}
resource "azurerm_availability_set" "as_db" {
name = "as1-db"
location = azurerm_resource_group.rg_appdb.location
resource_group_name = azurerm_resource_group.rg_appdb.name
tags = merge(local.global_settings.tags_hub, var.web_tier.as.tags)
platform_fault_domain_count = 2
}
resource "azurerm_lb" "ilb-db" {
name = "ilb-db"
location = azurerm_resource_group.rg_appdb.location
resource_group_name = azurerm_resource_group.rg_appdb.name
frontend_ip_configuration {
name = "PrivateIPAddress-ilb-db"
private_ip_address_allocation = "Dynamic"
subnet_id = lookup(module.net_core.core_network.vnet_subnets, "Data_tier", null)
}
}

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

@ -0,0 +1,26 @@
provider "azurerm" {
version = "=2.0"
features {}
}
terraform {
backend "azurerm" {
}
}
data "terraform_remote_state" "landingzone_caf_foundations" {
backend = "azurerm"
config = {
storage_account_name = var.lowerlevel_storage_account_name
container_name = var.workspace
key = "landingzone_caf_foundations.tfstate"
resource_group_name = var.lowerlevel_resource_group_name
}
}
locals {
prefix = data.terraform_remote_state.landingzone_caf_foundations.outputs.prefix
caf_foundations_accounting = data.terraform_remote_state.landingzone_caf_foundations.outputs.blueprint_foundations_accounting
caf_foundations_security = data.terraform_remote_state.landingzone_caf_foundations.outputs.blueprint_foundations_security
global_settings = data.terraform_remote_state.landingzone_caf_foundations.outputs.global_settings
}

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

@ -0,0 +1,39 @@
module "bastion_pip" {
source = "aztfmod/caf-public-ip/azurerm"
version = "1.0.0"
convention = var.global_settings.convention
name = var.bastion_config.ip_name
location = var.location
rg = var.rg
ip_addr = var.bastion_config.ip_addr
tags = var.tags
diagnostics_map = var.caf_foundations_accounting.diagnostics_map
log_analytics_workspace_id = var.caf_foundations_accounting.log_analytics_workspace.id
diagnostics_settings = var.bastion_config.ip_diags
}
resource "azurerm_bastion_host" "azurebastion" {
name = var.bastion_config.name
location = var.location
resource_group_name = var.rg
tags = var.tags
ip_configuration {
name = "bastionpipconfiguration"
subnet_id = var.subnet_id
public_ip_address_id = module.bastion_pip.id
}
}
module "diagnostics_bastion" {
source = "aztfmod/caf-diagnostics/azurerm"
version = "1.0.0"
name = azurerm_bastion_host.azurebastion.name
resource_id = azurerm_bastion_host.azurebastion.id
log_analytics_workspace_id = var.caf_foundations_accounting.log_analytics_workspace.id
diagnostics_map = var.caf_foundations_accounting.diagnostics_map
diag_object = var.bastion_config.diagnostics
}

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

@ -0,0 +1,4 @@
output "bastion" {
depends_on = [azurerm_bastion_host.azurebastion]
value = azurerm_bastion_host.azurebastion
}

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

@ -0,0 +1,36 @@
variable "location" {
}
variable "rg" {
}
variable "name" {
}
variable "tags" {
}
variable "subnet_id" {
}
variable "enable_bastion" {
}
variable "global_settings" {
}
variable "bastion_config" {
}
variable "caf_foundations_accounting" {
description = "caf_foundations_accounting settings"
}

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

@ -0,0 +1,182 @@
resource "azurerm_resource_group" "rg_network" {
name = "${var.prefix}${var.rg_network.CORE-NET.name}"
location = var.global_settings.location_map.region1
tags = var.global_settings.tags_hub
}
resource "azurerm_resource_group" "rg_transit" {
name = "${var.prefix}${var.rg_network.TRANSIT-NET.name}"
location = var.global_settings.location_map.region1
tags = var.global_settings.tags_hub
}
resource "azurerm_resource_group" "rg_edge" {
name = "${var.prefix}${var.rg_network.EDGE-NET.name}"
location = var.global_settings.location_map.region1
tags = var.global_settings.tags_hub
}
module "core_network" {
source = "aztfmod/caf-virtual-network/azurerm"
version = "1.1.0"
convention = var.global_settings.convention
virtual_network_rg = azurerm_resource_group.rg_network.name
prefix = var.prefix
location = var.global_settings.location_map.region1
networking_object = var.core_networking.shared_services_vnet
tags = var.global_settings.tags_hub
diagnostics_map = var.caf_foundations_accounting.diagnostics_map
log_analytics_workspace = var.caf_foundations_accounting.log_analytics_workspace
diagnostics_settings = var.core_networking.shared_services_vnet.diagnostics
}
module "az_firewall_ip" {
source = "aztfmod/caf-public-ip/azurerm"
version = "1.0.0"
convention = var.global_settings.convention
name = var.core_networking.ip_addr_config.ip_name
location = var.location
rg = azurerm_resource_group.rg_edge.name
ip_addr = var.core_networking.ip_addr_config
tags = var.global_settings.tags_hub
diagnostics_map = var.caf_foundations_accounting.diagnostics_map
log_analytics_workspace_id = var.caf_foundations_accounting.log_analytics_workspace.id
diagnostics_settings = var.core_networking.ip_addr_config.diagnostics
}
module "az_firewall" {
source = "aztfmod/caf-azure-firewall/azurerm"
version = "1.1.0"
convention = var.global_settings.convention
name = var.core_networking.az_fw_config.name
rg = azurerm_resource_group.rg_network.name
subnet_id = lookup(module.core_network.vnet_subnets, "AzureFirewallSubnet", null)
public_ip_id = module.az_firewall_ip.id
location = var.global_settings.location_map.region1
tags = var.global_settings.tags_hub
diagnostics_map = var.caf_foundations_accounting.diagnostics_map
la_workspace_id = var.caf_foundations_accounting.log_analytics_workspace.id
diagnostics_settings = var.core_networking.az_fw_config.diagnostics
}
module "firewall_dashboard" {
source = "./firewall_dashboard"
fw_id = module.az_firewall.id
pip_id = module.az_firewall_ip.id
location = var.location
rg = azurerm_resource_group.rg_network.name
name = basename(abspath(path.module))
tags = var.global_settings.tags_hub
}
module "firewall_rules" {
source = "./firewall_rules"
az_firewall_settings = module.az_firewall.az_firewall_config
}
# DDoS protection
module "ddos_protection_std" {
source = "./ddos_protection"
enable_ddos_standard = var.core_networking.enable_ddos_standard
name = var.core_networking.ddos_name
rg = azurerm_resource_group.rg_edge.name
location = var.location
tags = var.global_settings.tags_hub
}
# Please check Azure Bastion availability in the target region: https://azure.microsoft.com/en-us/global-infrastructure/services/?products=azure-bastion
module "bastion_host" {
source = "./bastion"
enable_bastion = var.core_networking.enable_bastion
name = var.core_networking.bastion_config.name
rg = azurerm_resource_group.rg_edge.name
subnet_id = lookup(module.core_network.vnet_subnets, "AzureBastionSubnet", null)
location = var.location
tags = local.tags
caf_foundations_accounting = var.caf_foundations_accounting
bastion_config = var.core_networking.bastion_config
global_settings = var.global_settings
}
# create the UDR object
module "user_route_web_to_az_firewall" {
source = "./udr"
route_name = var.core_networking.udr_web_to_az_firewall.route_name
route_resource_group = azurerm_resource_group.rg_network.name
location = var.location
route_prefix = var.core_networking.udr_web_to_az_firewall.prefix
route_nexthop_type = var.core_networking.udr_web_to_az_firewall.nexthop_type
route_nexthop_ip = module.az_firewall.az_firewall_config.az_ipconfig[0].private_ip_address
subnet_id = lookup(module.core_network.vnet_subnets, var.core_networking.udr_web_to_az_firewall.subnet_to_udr, null)
tags = local.tags
}
module "user_route_transit_to_az_firewall" {
source = "./udr"
route_name = var.core_networking.udr_transit_to_az_firewall.route_name
route_resource_group = azurerm_resource_group.rg_network.name
location = var.location
route_prefix = var.core_networking.udr_transit_to_az_firewall.prefix
route_nexthop_type = var.core_networking.udr_transit_to_az_firewall.nexthop_type
route_nexthop_ip = module.az_firewall.az_firewall_config.az_ipconfig[0].private_ip_address
subnet_id = lookup(module.core_network.vnet_subnets, var.core_networking.udr_transit_to_az_firewall.subnet_to_udr, null)
tags = local.tags
}
## VPN Gateway
module "vpn_pip" {
source = "aztfmod/caf-public-ip/azurerm"
version = "1.0.0"
convention = var.global_settings.convention
name = var.core_networking.gateway_config.pip.name
location = var.location
rg = azurerm_resource_group.rg_transit.name
ip_addr = var.core_networking.gateway_config.pip
tags = var.global_settings.tags_hub
diagnostics_map = var.caf_foundations_accounting.diagnostics_map
log_analytics_workspace_id = var.caf_foundations_accounting.log_analytics_workspace.id
diagnostics_settings = var.core_networking.gateway_config.pip.diagnostics
}
module "vpn_gateway" {
source = "./vpn_gateway"
provision_gateway = var.core_networking.provision_gateway
location = var.location
resource_group_name = azurerm_resource_group.rg_transit.name
tags = local.tags
gateway_config = var.core_networking.gateway_config
remote_network = var.core_networking.remote_network
remote_network_connect = var.core_networking.remote_network_connect
connection_name = var.core_networking.connection_name
public_ip_addr = module.vpn_pip.id
gateway_subnet = lookup(module.core_network.vnet_subnets, "GatewaySubnet", null)
diagnostics_map = var.core_networking.gateway_config.diagnostics
caf_foundations_accounting = var.caf_foundations_accounting
keyvaultid = module.keyvault_vpn.id
}
module "keyvault_vpn" {
source = "aztfmod/caf-keyvault/azurerm"
version = "1.0.0"
convention = var.global_settings.convention
rg = azurerm_resource_group.rg_transit.name
akv_config = var.core_networking.akv_config
prefix = var.prefix
location = var.location
tags = local.tags
log_analytics_workspace = var.caf_foundations_accounting.log_analytics_workspace
diagnostics_settings = var.core_networking.akv_config.diagnostics
diagnostics_map = var.caf_foundations_accounting.diagnostics_map
}

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

@ -0,0 +1,10 @@
## Cant be deleted or modified as per https://github.com/terraform-providers/terraform-provider-azurerm/issues/4059
resource "azurerm_network_ddos_protection_plan" "ddos_protection_plan" {
count = var.enable_ddos_standard ? 1 : 0
name = var.name
location = var.location
resource_group_name = var.rg
tags = var.tags
}

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

@ -0,0 +1,4 @@
output "ddos_protection" {
depends_on = [zurerm_network_ddos_protection_plan.ddos_protection_plan]
value = azurerm_network_ddos_protection_plan.ddos_protection_plan
}

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

@ -0,0 +1,19 @@
variable "location" {
description = "(Required) Define the region to be protected by DDoS protection"
}
variable "rg" {
description = "(Required) Define the resource group name where to deploy DDoS protection"
}
variable "name" {
description = "(Required) Name of DDoS protection"
}
variable "enable_ddos_standard" {
description = "(Required) Switch to enable DDoS protection standard"
}
variable "tags" {
description = "(Required) Tags of DDoS protection"
}

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

@ -0,0 +1,716 @@
{
"lenses": {
"0": {
"order": 0,
"parts": {
"0": {
"position": {
"x": 0,
"y": 0,
"colSpan": 16,
"rowSpan": 1
},
"metadata": {
"inputs": [],
"type": "Extension/HubsExtension/PartType/MarkdownPart",
"settings": {
"content": {
"settings": {
"content": "",
"title": "Edge Monitoring ",
"subtitle": ""
}
}
}
}
},
"1": {
"position": {
"x": 0,
"y": 1,
"colSpan": 8,
"rowSpan": 6
},
"metadata": {
"inputs": [
{
"name": "sharedTimeRange",
"isOptional": true
},
{
"name": "options",
"value": {
"chart": {
"metrics": [
{
"resourceMetadata": {
"id": "${fw_id}"
},
"name": "ApplicationRuleHit",
"aggregationType": 1,
"namespace": "microsoft.network/azurefirewalls",
"metricVisualization": {
"displayName": "Application rules hit count"
}
},
{
"resourceMetadata": {
"id": "${fw_id}"
},
"name": "DataProcessed",
"aggregationType": 1,
"namespace": "microsoft.network/azurefirewalls",
"metricVisualization": {
"displayName": "Data processed"
}
},
{
"resourceMetadata": {
"id": "${fw_id}"
},
"name": "FirewallHealth",
"aggregationType": 4,
"namespace": "microsoft.network/azurefirewalls",
"metricVisualization": {
"displayName": "Firewall health state"
}
},
{
"resourceMetadata": {
"id": "${fw_id}"
},
"name": "NetworkRuleHit",
"aggregationType": 1,
"namespace": "microsoft.network/azurefirewalls",
"metricVisualization": {
"displayName": "Network rules hit count"
}
},
{
"resourceMetadata": {
"id": "${fw_id}"
},
"name": "SNATPortUtilization",
"aggregationType": 4,
"namespace": "microsoft.network/azurefirewalls",
"metricVisualization": {
"displayName": "SNAT port utilization"
}
}
],
"title": "Sum Application rules hit count, Sum Data processed, and 3 other metrics for az-fw-arnaud",
"titleKind": 1,
"visualization": {
"chartType": 2,
"legendVisualization": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axisVisualization": {
"x": {
"isVisible": true,
"axisType": 2
},
"y": {
"isVisible": true,
"axisType": 1
}
}
}
},
"version": 2
},
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/MonitorChartPart",
"settings": {
"content": {
"options": {
"chart": {
"metrics": [
{
"resourceMetadata": {
"id": "${fw_id}"
},
"name": "ApplicationRuleHit",
"aggregationType": 1,
"namespace": "microsoft.network/azurefirewalls",
"metricVisualization": {
"displayName": "Application rules hit count"
}
},
{
"resourceMetadata": {
"id": "${fw_id}"
},
"name": "DataProcessed",
"aggregationType": 1,
"namespace": "microsoft.network/azurefirewalls",
"metricVisualization": {
"displayName": "Data processed"
}
},
{
"resourceMetadata": {
"id": "${fw_id}"
},
"name": "FirewallHealth",
"aggregationType": 4,
"namespace": "microsoft.network/azurefirewalls",
"metricVisualization": {
"displayName": "Firewall health state"
}
},
{
"resourceMetadata": {
"id": "${fw_id}"
},
"name": "NetworkRuleHit",
"aggregationType": 1,
"namespace": "microsoft.network/azurefirewalls",
"metricVisualization": {
"displayName": "Network rules hit count"
}
},
{
"resourceMetadata": {
"id": "${fw_id}"
},
"name": "SNATPortUtilization",
"aggregationType": 4,
"namespace": "microsoft.network/azurefirewalls",
"metricVisualization": {
"displayName": "SNAT port utilization"
}
}
],
"title": "Azure Firewall - Egress Overview",
"titleKind": 2,
"visualization": {
"chartType": 2,
"legendVisualization": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axisVisualization": {
"x": {
"isVisible": true,
"axisType": 2
},
"y": {
"isVisible": true,
"axisType": 1
}
},
"disablePinning": true
}
},
"version": 2
}
}
}
}
},
"2": {
"position": {
"x": 8,
"y": 1,
"colSpan": 8,
"rowSpan": 6
},
"metadata": {
"inputs": [
{
"name": "sharedTimeRange",
"isOptional": true
},
{
"name": "options",
"value": {
"chart": {
"metrics": [
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "ByteCount",
"aggregationType": 1,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Byte Count"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "PacketCount",
"aggregationType": 1,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Packet Count"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "SynCount",
"aggregationType": 1,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "SYN Count"
}
}
],
"title": "Public IP - Egress Overview",
"titleKind": 2,
"visualization": {
"chartType": 2,
"legendVisualization": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axisVisualization": {
"x": {
"isVisible": true,
"axisType": 2
},
"y": {
"isVisible": true,
"axisType": 1
}
}
}
},
"version": 2
},
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/MonitorChartPart",
"settings": {
"content": {
"options": {
"chart": {
"metrics": [
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "ByteCount",
"aggregationType": 1,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Byte Count"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "PacketCount",
"aggregationType": 1,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Packet Count"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "SynCount",
"aggregationType": 1,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "SYN Count"
}
}
],
"title": "Public IP - Egress Overview",
"titleKind": 2,
"visualization": {
"chartType": 2,
"legendVisualization": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axisVisualization": {
"x": {
"isVisible": true,
"axisType": 2
},
"y": {
"isVisible": true,
"axisType": 1
}
},
"disablePinning": true
}
},
"version": 2
}
}
}
}
},
"3": {
"position": {
"x": 0,
"y": 7,
"colSpan": 8,
"rowSpan": 5
},
"metadata": {
"inputs": [
{
"name": "sharedTimeRange",
"isOptional": true
},
{
"name": "options",
"value": {
"chart": {
"metrics": [
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "BytesInDDoS",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Inbound bytes DDoS"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "BytesDroppedDDoS",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Inbound bytes dropped DDoS"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "TCPBytesInDDoS",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Inbound TCP bytes DDoS"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "DDoSTriggerSYNPackets",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Inbound SYN packets to trigger DDoS mitigation"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "UDPBytesInDDoS",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Inbound UDP bytes DDoS"
}
}
],
"title": "DDoS Statistics",
"titleKind": 1,
"visualization": {
"chartType": 2,
"legendVisualization": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axisVisualization": {
"x": {
"isVisible": true,
"axisType": 2
},
"y": {
"isVisible": true,
"axisType": 1
}
}
}
},
"version": 2
},
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/MonitorChartPart",
"settings": {
"content": {
"options": {
"chart": {
"metrics": [
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "BytesInDDoS",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Inbound bytes DDoS"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "BytesDroppedDDoS",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Inbound bytes dropped DDoS"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "TCPBytesInDDoS",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Inbound TCP bytes DDoS"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "DDoSTriggerSYNPackets",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Inbound SYN packets to trigger DDoS mitigation"
}
},
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "UDPBytesInDDoS",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Inbound UDP bytes DDoS"
}
}
],
"title": "IP address - Egress - DDoS Overview",
"titleKind": 2,
"visualization": {
"chartType": 2,
"legendVisualization": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axisVisualization": {
"x": {
"isVisible": true,
"axisType": 2
},
"y": {
"isVisible": true,
"axisType": 1
}
},
"disablePinning": true
}
},
"version": 2
}
}
}
}
},
"4": {
"position": {
"x": 8,
"y": 7,
"colSpan": 8,
"rowSpan": 5
},
"metadata": {
"inputs": [
{
"name": "sharedTimeRange",
"isOptional": true
},
{
"name": "options",
"value": {
"chart": {
"metrics": [
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "IfUnderDDoSAttack",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Under DDoS attack or not"
}
}
],
"title": "Max Under DDoS attack or not for arnaud-pip-egress",
"titleKind": 1,
"visualization": {
"chartType": 1,
"legendVisualization": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axisVisualization": {
"x": {
"isVisible": true,
"axisType": 2
},
"y": {
"isVisible": true,
"axisType": 1
}
}
}
},
"version": 2
},
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/MonitorChartPart",
"settings": {
"content": {
"options": {
"chart": {
"metrics": [
{
"resourceMetadata": {
"id": "${pip_id}"
},
"name": "IfUnderDDoSAttack",
"aggregationType": 3,
"namespace": "microsoft.network/publicipaddresses",
"metricVisualization": {
"displayName": "Under DDoS attack or not"
}
}
],
"title": "DDoS Attack Detected",
"titleKind": 2,
"visualization": {
"chartType": 1,
"legendVisualization": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axisVisualization": {
"x": {
"isVisible": true,
"axisType": 2
},
"y": {
"isVisible": true,
"axisType": 1
}
},
"disablePinning": true
}
},
"version": 2
}
}
}
}
},
"5": {
"position": {
"x": 0,
"y": 12,
"colSpan": 16,
"rowSpan": 1
},
"metadata": {
"inputs": [],
"type": "Extension/HubsExtension/PartType/MarkdownPart",
"settings": {
"content": {
"settings": {
"content": "",
"title": "Virtual Network Monitoring",
"subtitle": ""
}
}
}
}
}
}
}
},
"metadata": {
"model": {
"timeRange": {
"value": {
"relative": {
"duration": 24,
"timeUnit": 1
}
},
"type": "MsPortalFx.Composition.Configuration.ValueTypes.TimeRange"
},
"filterLocale": {
"value": "en-us"
},
"filters": {
"value": {
"MsPortalFx_TimeRange": {
"model": {
"format": "utc",
"granularity": "auto",
"relative": "24h"
},
"displayCache": {
"name": "UTC Time",
"value": "Past 24 hours"
},
"filteredPartIds": [
"StartboardPart-MonitorChartPart-1bd243d6-36d8-4329-8ed0-02aa14c243e3",
"StartboardPart-MonitorChartPart-1bd243d6-36d8-4329-8ed0-02aa14c245fc",
"StartboardPart-MonitorChartPart-1bd243d6-36d8-4329-8ed0-02aa14c24788",
"StartboardPart-MonitorChartPart-1bd243d6-36d8-4329-8ed0-02aa14c24a01"
]
}
}
}
}
}
}

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

@ -0,0 +1,15 @@
resource "azurerm_dashboard" "egress_dashboard" {
name = var.name
resource_group_name = var.rg
location = var.location
tags = var.tags
dashboard_properties = templatefile("${path.module}/egress-dashboard.tpl",
{
md_content = "CAF landing zones - Egress Dashboard"
pip_id = var.pip_id
fw_id = var.fw_id
})
}

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

@ -0,0 +1,25 @@
variable "fw_id" {
}
variable "pip_id" {
}
variable "name" {
}
variable "rg" {
}
variable "location" {
}
variable "tags" {
}

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

@ -0,0 +1,26 @@
resource "azurerm_firewall_network_rule_collection" "http_https" {
name = "Authorize_http_https"
azure_firewall_name = var.az_firewall_settings.az_fw_name
resource_group_name = var.az_firewall_settings.az_object.resource_group_name
priority = 105
action = "Allow"
rule {
name = "Authorize_http_https"
source_addresses = [
"10.0.0.0/8",
]
destination_ports = [
"80","443",
]
destination_addresses = [
"*"
]
protocols = [
"TCP",
]
}
}

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

@ -0,0 +1,3 @@
variable "az_firewall_settings" {
description = "Azure Firewall Configuration Object"
}

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

@ -0,0 +1,19 @@
terraform {
required_version = ">= 0.12.6"
backend "azurerm" {
}
}
# provider "azurerm" {
# version = "<= 1.44"
# }
data "azurerm_subscription" "current" {
}
locals {
blueprint_tag = {
"blueprint" = basename(abspath(path.module))
}
tags = merge(var.global_settings.tags_hub,local.blueprint_tag)
}

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

@ -0,0 +1,15 @@
output "core_network" {
value = module.core_network
}
# output "shared_services_nsg_table" {
# value = module.networking_shared_services.nsg_vnet
# }
# output "shared_services_subnet_table" {
# value = module.networking_shared_services.vnet_subnets
# }
# output "resource_group_shared_services" {
# value = module.resource_group
# }

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

@ -0,0 +1,29 @@
# blueprint_networking_shared_services
blueprint_networking_shared_services brings the foundation of shared services (hub) network in a hub-spoke topology.
## Overall architecture
The following diagram shows the environment we are deploying in this blueprint:
![Shared](../../_pictures/hub_spoke/hubspoke_nets_shared.png)
## Capabilities
- Virtual network
- Virtual network address space
- DNS Servers
- Subnets
- Subnet address space
- Network Security Groups
- Virtual Network Service Endpoints
- NSG diagnostics
- Attach NSG to subnet
- Virtual network operations logs and auditing
- DDoS Protection standard plan
- Azure Bastion
## Contribute
This is a demo environment but pull requests are welcome to evolve the framework and integrate new features!

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

@ -0,0 +1,22 @@
#Reference https://www.terraform.io/docs/providers/azurerm/r/route_table.html
resource "azurerm_route_table" "user_route" {
name = var.route_name
location = var.location
resource_group_name = var.route_resource_group
disable_bgp_route_propagation = false
tags = var.tags
route {
name = var.route_name
address_prefix = var.route_prefix
next_hop_type = var.route_nexthop_type
//theoritcally should be: next_hop_in_ip_address = var.route_nexthop_type == "VirtualAppliance" ? "${var.route_nexthop_ip}" : null
next_hop_in_ip_address = var.route_nexthop_ip
}
}
resource "azurerm_subnet_route_table_association" "route_subnet_association" {
subnet_id = var.subnet_id
route_table_id = azurerm_route_table.user_route.id
}

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

@ -0,0 +1,15 @@
output "id" {
value = azurerm_route_table.user_route.id
}
output "name" {
value = azurerm_route_table.user_route.name
}
output "object" {
value = azurerm_route_table.user_route
}
output "subnet_route" {
value = azurerm_subnet_route_table_association.route_subnet_association
}

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

@ -0,0 +1,35 @@
variable "route_name" {
description = "(Required) name of the route object to be created"
}
variable "location" {
description = "(Required) location where to deploy the route table object"
}
variable "tags" {
description = "(Required) tags for the route table object"
}
variable "route_resource_group" {
description = "(Required) resource group where to deploy the route table object"
}
variable "subnet_id" {
description = "(Required) subnet where the route table object will be created"
}
variable "route_prefix" {
description = "(Required) route prefix for the route table object"
}
variable "route_nexthop_type" {
description = "(Required) route nexthop type for the route table object, can be VirtualNetworkGateway, VnetLocal, Internet, VirtualAppliance and None."
}
variable "route_nexthop_ip" {
description = "(Optional) route nexthop IP for the route table object - Next hop values are only allowed in routes where the next hop type is VirtualAppliance"
default = ""
}

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

@ -0,0 +1,74 @@
variable "prefix" {
description = "(Optional) Prefix to uniquely identify the deployment"
}
# variable "virtual_network_rg" {
# description = "(Required) Map of the resource groups to create"
# }
# variable "location" {
# description = "(Required) Define the region where the resource groups will be created"
# }
# variable "tags" {
# description = "tags for the deployment"
# }
# variable "shared_services_vnet" {
# description = "Network configuration"
# }
# variable "enable_network_watcher" {
# description = "Enable network watcher for the subnet - this will deploy and configure a Linux VM with network watcher extensions."
# default = false
# }
# variable "subnet_to_deploy_network_monitoring" {
# description = "Name of the subnet (must be a valid subnet name if the shared services virtual network) wher to deploy the network watcher VM"
# default = ""
# }
# variable "log_analytics_workspace" {
# }
# variable "diagnostics_map" {
# }
# variable "enable_ddos_standard" {
# description = "(Optional) boolean to switch on/off ddos standard"
# }
# variable "ddos_name" {
# }
# variable "resource_groups_shared_services" {
# description = "(Required) Resource group to use to host all shared services blueprint resources."
# }
# variable "bastion_config" {
# description = "(Required) Configuration object for the Azure Bastion service."
# }
# variable "enable_bastion" {
# description = "Switch to enable Azure Bastion // reserved for future use"
# }
variable "global_settings" {
description = "global settings"
}
variable "caf_foundations_accounting" {
description = "caf_foundations_accounting"
}
variable "core_networking" {
description = "core_networking"
}
variable "location" {
}
variable "rg_network" {}

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

@ -0,0 +1,18 @@
data "azurerm_client_config" "current" {}
resource "azurerm_key_vault_access_policy" "akv_policy1" {
key_vault_id = var.keyvaultid
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
key_permissions = []
secret_permissions = [
"set",
"get",
"delete",
]
}

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

@ -0,0 +1,33 @@
resource "random_string" "psk_connection" {
length = 128
upper = true
special = true
number = true
}
resource "azurerm_virtual_network_gateway_connection" "connection_object" {
count = var.provision_gateway && var.remote_network_connect == true ? 1 : 0
depends_on = [azurerm_virtual_network_gateway.vpn_gateway, azurerm_local_network_gateway.remote_network]
name = var.connection_name
location = var.location
resource_group_name = var.resource_group_name
type = "IPsec"
virtual_network_gateway_id = azurerm_virtual_network_gateway.vpn_gateway[0].id
local_network_gateway_id = azurerm_local_network_gateway.remote_network.id
shared_key = random_string.psk_connection.result
tags = var.tags
}
resource "azurerm_key_vault_secret" "psk" {
depends_on = [random_string.psk_connection, azurerm_key_vault_access_policy.akv_policy1]
name = "pskconnection"
value = random_string.psk_connection.result
key_vault_id = var.keyvaultid
tags = var.tags
}

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

@ -0,0 +1,13 @@
# module "diagnostics_vpn" {
# source = "aztfmod/caf-diagnostics/azurerm"
# version = "1.0.0"
# #depends_on = [azurerm_virtual_network_gateway.vpn_gateway]
# #count = "${var.gateway_config.gateway_type == "VPN" && var.provision_gateway ? 1 : 0}"
# name = azurerm_virtual_network_gateway.vpn_gateway[0].name
# resource_id = azurerm_virtual_network_gateway.vpn_gateway[0].id
# log_analytics_workspace_id = var.log_analytics_workspace.id
# diagnostics_map = var.diagnostics_map
# diag_object = var.diagnostics_settings
# }

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

@ -0,0 +1,15 @@
resource "azurerm_local_network_gateway" "remote_network" {
name = var.remote_network.gateway_name
resource_group_name = var.resource_group_name
location = var.location
gateway_address = var.remote_network.gateway_ip
address_space = var.remote_network.gateway_adress_space
tags = var.tags
# bgp_settings {
# asn =
# bgp_peering_address =
# peer_weight =
# }
}

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

@ -0,0 +1,7 @@
output "object" {
value = azurerm_virtual_network_gateway.vpn_gateway
}
output "remote_connection_object" {
value = azurerm_local_network_gateway.remote_network
}

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

@ -0,0 +1,50 @@
variable "location" {
}
variable "resource_group_name" {
}
variable "tags" {
}
variable "remote_network" {
}
variable "remote_network_connect" {
}
variable "connection_name" {
}
variable "public_ip_addr" {
}
variable "gateway_subnet" {
}
variable "gateway_config" {
}
variable "diagnostics_map" {
}
variable "provision_gateway" {
}
variable "keyvaultid" {
}
variable "caf_foundations_accounting" {
}

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

@ -0,0 +1,35 @@
# Reference on https://www.terraform.io/docs/providers/azurerm/r/virtual_network_gateway.html
resource "azurerm_virtual_network_gateway" "vpn_gateway" {
count = var.gateway_config.gateway_type == "VPN" && var.provision_gateway ? 1 : 0
name = var.gateway_config.vpn_gateway_name
location = var.location
resource_group_name = var.resource_group_name
type = "Vpn"
vpn_type = var.gateway_config.vpn_gateway_type
active_active = var.gateway_config.active_active
enable_bgp = var.gateway_config.enable_bgp
sku = var.gateway_config.vpn_gateway_sku
tags = var.tags
ip_configuration {
name = "vnetGatewayConfig"
public_ip_address_id = var.public_ip_addr
private_ip_address_allocation = "Dynamic"
subnet_id = var.gateway_subnet
}
# vpn_client_configuration {
# address_space = ["10.2.0.0/24"]
# # root_certificate {
# # name = "Name_Of_CA"
# # public_cert_data = <<EOF
# # EOF
# }
}

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

@ -0,0 +1,274 @@
# definition of variables for the virtual network
rg_network = {
CORE-NET = {
name = "-network-core"
}
TRANSIT-NET = {
name = "-network-transit"
}
EDGE-NET = {
name = "-network-edge"
}
}
# settings for the core network blueprint
core_networking = {
shared_services_vnet = {
vnet = {
name = "Core-Network"
address_space = ["10.0.0.0/8"]
}
specialsubnets = {
AzureFirewallSubnet = {
name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet
cidr = "10.0.4.0/24"
}
GatewaySubnet = {
name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway
cidr = "10.0.255.224/27"
}
}
subnets = {
subnet0 = {
name = "Web_tier"
cidr = "10.0.1.0/24"
nsg_inbound = [
# {"Name", "Priority", "Direction", "Action", "Protocol", "source_port_range", "destination_port_range", "source_address_prefix", "destination_address_prefix" },
["HTTP-In", "100", "Inbound", "Allow", "tcp", "*", "80", "*", "*"],
["HTTPS-In", "101", "Inbound", "Allow", "tcp", "*", "443", "*", "*"],
]
}
subnet1 = {
name = "Business_tier"
cidr = "10.0.2.0/24"
nsg_inbound = [
# {"Name", "Priority", "Direction", "Action", "Protocol", "source_port_range", "destination_port_range", "source_address_prefix", "destination_address_prefix" },
["HTTP-In", "100", "Inbound", "Allow", "tcp", "*", "80", "*", "*"],
["HTTPS-In", "101", "Inbound", "Allow", "tcp", "*", "443", "*", "*"],
]
nsg_outbound = [
["HTTP-Out", "100", "Outbound", "Allow", "tcp", "*", "80", "*", "*"],
["HTTPS-Out", "101", "Outbound", "Allow", "tcp", "*", "443", "*", "*"],
]
}
subnet2 = {
name = "Data_tier"
cidr = "10.0.3.0/24"
nsg_inbound = [
# {"Name", "Priority", "Direction", "Action", "Protocol", "source_port_range", "destination_port_range", "source_address_prefix", "destination_address_prefix" },
["TDS-In", "100", "Inbound", "Allow", "tcp", "*", "1433", "*", "*"],
]
}
subnet3 = {
name = "AzureBastionSubnet" #Must be called AzureBastionSubnet
cidr = "10.0.0.128/25"
nsg_inbound = [
["bastion-in-allow", "100", "Inbound", "Allow", "tcp", "*", "443", "*", "*"],
["bastion-control-in-allow-443", "120", "Inbound", "Allow", "tcp", "*", "443", "GatewayManager", "*"],
["bastion-control-in-allow-4443", "121", "Inbound", "Allow", "tcp", "*", "4443", "GatewayManager", "*"],
]
nsg_outbound = [
["bastion-vnet-out-allow-22", "100", "Outbound", "Allow", "tcp", "*", "22", "*", "VirtualNetwork"],
["bastion-vnet-out-allow-3389", "101", "Outbound", "Allow", "tcp", "*", "3389", "*", "VirtualNetwork"],
["bastion-azure-out-allow", "120", "Outbound", "Allow", "tcp", "*", "443", "*", "AzureCloud"],
]
}
}
diagnostics = {
log = [
# ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["VMProtectionAlerts", true, true, 60],
]
metric = [
#["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["AllMetrics", true, true, 60],
]
}
}
# Settings for the public IP address to be used for Azure Firewall
# Must be standard and static for
ip_addr_config = {
ip_name = "firewall"
allocation_method = "Static"
sku = "Standard" #defaults to Basic
ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both
diagnostics = {
log = [
#["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["DDoSProtectionNotifications", true, true, 30],
["DDoSMitigationFlowLogs", true, true, 30],
["DDoSMitigationReports", true, true, 30],
]
metric = [
["AllMetrics", true, true, 30],
]
}
}
# Settings for the Azure Firewall settings
az_fw_config = {
name = "azfw"
diagnostics = {
log = [
#["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["AzureFirewallApplicationRule", true, true, 30],
["AzureFirewallNetworkRule", true, true, 30],
]
metric = [
["AllMetrics", true, true, 30],
]
}
}
# Settings for the UDR object
udr_web_to_az_firewall = {
nexthop_type = "VirtualAppliance"
prefix = "0.0.0.0/0"
route_name = "web_to_az_firewall"
subnet_to_udr = "Web_tier"
nexthop_ip = ""
}
udr_transit_to_az_firewall = {
nexthop_type = "VirtualAppliance"
prefix = "10.0.1.0/24"
route_name = "transit_to_az_firewall"
subnet_to_udr = "GatewaySubnet"
nexthop_ip = ""
}
## DDoS standard configuration
enable_ddos_standard = false
ddos_name = "ddos_protection_plan"
## settings for Azure bastion configuration
## not enabled, uncomment the code in the networking shared services blueprint.
enable_bastion = true
bastion_config = {
name = "azurebastion"
diagnostics = {
log = [
#["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["BastionAuditLogs", true, true, 30],
]
metric = [
# ["AllMetrics", true, true, 30],
]
}
ip_name = "bastion"
ip_addr = {
allocation_method = "Static"
#Dynamic Public IP Addresses aren't allocated until they're assigned to a resource (such as a Virtual Machine or a Load Balancer) by design within Azure
#properties below are optional
sku = "Standard" #defaults to Basic
ip_version = "IPv4" #defaults to IP4, Only dynamic for IPv6, Supported arguments are IPv4 or IPv6, NOT Both
#dns_prefix = "arnaudmytest"
#timeout = 15 #TCP timeout for idle connections. The value can be set between 4 and 30 minutes.
#zones = [1] #1 zone number, IP address must be standard, ZoneRedundant argument is not supported in provider at time of writing
#reverse_fqdn = ""
#public_ip_prefix_id = "/subscriptions/00000000-00000-0000-0000-000000000000/resourceGroups/uqvh-hub-ingress-net/providers/Microsoft.Network/publicIPPrefixes/myprefix"
#refer to the prefix and check sku types are same in IP and prefix
}
ip_diags = {
log = [
#["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["DDoSProtectionNotifications", true, true, 30],
["DDoSMitigationFlowLogs", true, true, 30],
["DDoSMitigationReports", true, true, 30],
]
metric = [
["AllMetrics", true, true, 30],
]
}
}
# Settings for the Virtual Network gateway to be created
provision_gateway = false
gateway_config = {
gateway_type = "VPN"
# Possible values are "VPN" or "ExpressRoute"
vpn_gateway_name = "vpngateway"
active_active = false
#An active-active gateway requires a HighPerformance or an UltraPerformance sku. If false, an active-standby gateway will be created. Defaults to false.
enable_bgp = false
#If true, BGP (Border Gateway Protocol) will be enabled for this Virtual Network Gateway. Defaults to false.
vpn_gateway_sku = "Basic"
#Valid options are Basic, Standard, HighPerformance, UltraPerformance, ErGw1AZ, ErGw2AZ, ErGw3AZ, VpnGw1, VpnGw2, VpnGw3, VpnGw1AZ, VpnGw2AZ, and VpnGw3AZ
#and depend on the gateway_type (ER or VPN) and vpn_type arguments, ie: PolicyBased gateway only supports the Basic sku.
vpn_gateway_type = "RouteBased"
#The routing type of the Virtual Network Gateway. Valid options are RouteBased or PolicyBased. Defaults to RouteBased.
diagnostics = {
log = [
#["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["GatewayDiagnosticLog", true, true, 30],
["TunnelDiagnosticLog", true, true, 30],
["RouteDiagnosticLog", true, true, 30],
["IKEDiagnosticLog", true, true, 30],
["P2SDiagnosticLog", true, true, 30],
]
metric = [
["AllMetrics", true, true, 30],
]
}
pip = {
name = "vpn"
allocation_method = "Dynamic"
sku = "Basic"
#For basic SKU, you can pick the zone to be deployed - if you want multi zone - pick Standard IP and pick AZ aware VPN gateway SKU
#dns_prefix = "arnaudvpn"
#zones = ["1"]
diagnostics = {
log = [
#["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["DDoSProtectionNotifications", true, true, 30],
["DDoSMitigationFlowLogs", true, true, 30],
["DDoSMitigationReports", true, true, 30],
]
metric = [
["AllMetrics", true, true, 30],
]
}
}
}
#Settings for the connection to be established
#Settings for the local network connection
connection_name = "onpremconnection"
remote_network_connect = true
remote_network = {
gateway_name = "caf_local_network"
gateway_ip = "1.2.3.4"
gateway_adress_space = ["1.0.0.0/8"]
bgp_settings = {
# asn =
# bgp_peering_address =
# peer_weight =
}
}
##Settings for the Azure Key Vault
akv_config = {
name = "vpn-akv"
akv_features = {
enabled_for_disk_encryption = true
enabled_for_deployment = true
enabled_for_template_deployment = true
}
sku_name = "standard"
diagnostics = {
log = [
# ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["AuditEvent", true, true, 60],
]
metric = [
#["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["AllMetrics", true, true, 60],
]
}
}
}

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

@ -0,0 +1,10 @@
module "net_core" {
source = "./net_core"
global_settings = local.global_settings
prefix = local.prefix
location = local.global_settings.location_map["region1"]
caf_foundations_accounting = local.caf_foundations_accounting
core_networking = var.core_networking
rg_network = var.rg_network
}

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

@ -0,0 +1,29 @@
output "net_core" {
sensitive = false # to hide content from logs
value = module.net_core
}
# output "blueprint_networking_shared_services" {
# sensitive = true # to hide content from logs
# value = module.blueprint_networking_shared_services
# }
# output "blueprint_networking_shared_egress" {
# sensitive = true # to hide content from logs
# value = module.blueprint_networking_shared_egress
# }
## re-exporting level1 settings (caf_foundations) for level 3 consumption
output "prefix" {
value = local.prefix
}
output "landingzone_caf_foundations_accounting" {
sensitive = true # to hide content from logs
value = local.caf_foundations_accounting
}
output "landingzone_caf_foundations_global_settings" {
sensitive = false # to hide content from logs
value = local.global_settings
}

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

@ -0,0 +1,39 @@
# Introduction to Network DMZ between Azure and an on-premises datacenter landing zone
Welcome to Azure Cloud Adoption Framework Series.
This landing zone is an implementation of the following reference architecture: <https://docs.microsoft.com/en-gb/azure/architecture/reference-architectures/dmz/secure-vnet-dmz>
## Prerequisites
This landing zone is a "level 2" type of landing zone, which **requires** you have deployed the foundations. The supported lower level landing zone is **landingzone_caf_foundations** which can be found in the same release and must have been applied successfully **before** applying this one.
## Overall architecture
The following diagram shows the environment we are deploying for this POC:
![DMZ](../../_pictures/dmz/dmz-private.png)
## Getting Started
To deploy a landing zone, use the execution environnement as described at the root of the landing zone repository.
## Deploying this landing zone
```
rover /tf/caf/landingzones/landingzone_secure_vnet_dmz plan
```
Review the configuration and if you are ok with it, deploy it by running:
```
rover /tf/caf/landingzones/landingzone_secure_vnet_dmz apply
```
Have fun playing with the landing zone an once you are done, you can simply delete the deployment using:
```
rover /tf/caf/landingzones/landingzone_secure_vnet_dmz destroy
```
More details about this landing zone can also be found in the landing zone folder and its blueprints sub-folders.
## Contribute
Pull requests are welcome to evolve the framework and integrate new features.

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

@ -0,0 +1,7 @@
# Map of the remote data state
variable "lowerlevel_storage_account_name" {}
variable "lowerlevel_container_name" {}
variable "lowerlevel_key" {} # Keeping the key for the lower level0 access
variable "lowerlevel_resource_group_name" {}
variable "workspace" {}

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

@ -0,0 +1,13 @@
variable "web_tier" {
}
variable "app_tier" {
}
variable "db_tier" {
}
variable "core_networking" {}
variable "rg_network" {}
variable "rg_app" {}