Adding LZ secure_vnet_dmz and crafting doc
This commit is contained in:
Родитель
a1430b5d91
Коммит
889a533526
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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" {}
|
Загрузка…
Ссылка в новой задаче