Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add standard vnet config file for buildingblock definition #79

Merged
merged 5 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions kit/azure/buildingblocks/standard-vnet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
name: Buildingblocks-azure-standard-vnet-config
summary: |
Prepares the infrastructure to create a new building block definition for "Azure Standard Virtual Network".
---

# Buildingblocks azure virtual network configuration

Using this module, you can either create a new or use an existing **Service Principal** and **Storage Account** for creating a buildingblock definition inside the meshStack.

## How to use
- a "backend.tf" and a "provider.tf" will be generated as an output of this module which then you can drop them as an encrypted input inside your buildingblock definition.
<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
| <a name="requirement_azuread"></a> [azuread](#requirement\_azuread) | >2.0.0 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | >3.0.0 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_existing_spn"></a> [existing\_spn](#module\_existing\_spn) | ./module-exisiting-service-principal | n/a |
| <a name="module_existing_sta"></a> [existing\_sta](#module\_existing\_sta) | ./module-existing-storage-account | n/a |
| <a name="module_new_spn"></a> [new\_spn](#module\_new\_spn) | ./module-new-service-principal | n/a |
| <a name="module_new_sta"></a> [new\_sta](#module\_new\_sta) | ./module-new-storage-account | n/a |

## Resources

No resources.

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_create_new_spn"></a> [create\_new\_spn](#input\_create\_new\_spn) | If you already have an SPN for deployment of Building block in you environment insert '1', otherwise insert '0' so a new one will be created | `number` | n/a | yes |
| <a name="input_create_new_storageaccount"></a> [create\_new\_storageaccount](#input\_create\_new\_storageaccount) | If you already have an Storage Account to keep your terraform state file in you environment insert '1', otherwise insert '0' so a new one will be created | `number` | n/a | yes |
| <a name="input_existing_storage_account_id"></a> [existing\_storage\_account\_id](#input\_existing\_storage\_account\_id) | 'Only required if you want to re-use an existing storage account. This is the resourceId of an existing storage account. You can retrieve this value from panel. | `string` | `null` | no |
| <a name="input_new_resource_group_name"></a> [new\_resource\_group\_name](#input\_new\_resource\_group\_name) | Name of the resource group to create a new storage account inside this RG | `string` | `null` | no |
| <a name="input_spn_suffix"></a> [spn\_suffix](#input\_spn\_suffix) | suffix for the SPN's name. The format is 'building\_blocks.SUFFIX' | `string` | `null` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_existing_sta_backend"></a> [existing\_sta\_backend](#output\_existing\_sta\_backend) | n/a |
| <a name="output_new_sta_backend"></a> [new\_sta\_backend](#output\_new\_sta\_backend) | n/a |
| <a name="output_provider_existing_spn"></a> [provider\_existing\_spn](#output\_provider\_existing\_spn) | Please run 'terraform output provider\_existing\_spn' to export the provider configuration using the existing service principal |
| <a name="output_provider_new_spn"></a> [provider\_new\_spn](#output\_provider\_new\_spn) | Please run 'terraform output provider\_new\_spn' to export the provider configuration using this new service principal |
<!-- END_TF_DOCS -->
Binary file added kit/azure/buildingblocks/standard-vnet/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions kit/azure/buildingblocks/standard-vnet/main-backend.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
variable "create_new_storageaccount" {
type = number
description = "If you already have an Storage Account to keep your terraform state file in you environment insert '1', otherwise insert '0' so a new one will be created"
validation {
condition = var.create_new_storageaccount == 1 || var.create_new_storageaccount == 0
error_message = "create_new_storageaccount variable must be either 0 or 1."
}
}

variable "existing_storage_account_id" {
type = string
description = "'Only required if you want to re-use an existing storage account. This is the resourceId of an existing storage account. You can retrieve this value from panel."
default = null
}

variable "new_resource_group_name" {
type = string
description = "Name of the resource group to create a new storage account inside this RG"
default = null
}

module "existing_sta" {
count = var.create_new_storageaccount == 1 ? 1 : 0
source = "./module-existing-storage-account"
storage_account_resource_id = var.existing_storage_account_id
}

module "new_sta" {
count = var.create_new_storageaccount == 0 ? 1 : 0
source = "./module-new-storage-account"
resource_group_name = var.new_resource_group_name
}



output "existing_sta_backend" {
value = module.existing_sta
sensitive = true
}

output "new_sta_backend" {
value = module.new_sta
sensitive = true
}
37 changes: 37 additions & 0 deletions kit/azure/buildingblocks/standard-vnet/main-service-principal.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
variable "create_new_spn" {
type = number
description = "If you already have an SPN for deployment of Building block in you environment insert '1', otherwise insert '0' so a new one will be created"
validation {
condition = var.create_new_spn == 1 || var.create_new_spn == 0
error_message = "create_new_spn variable must be either 0 or 1."
}
}
variable "spn_suffix" {
type = string
description = "suffix for the SPN's name. The format is 'building_blocks.SUFFIX'"
default = null
}
module "new_spn" {
count = var.create_new_spn == 0 ? 1 : 0
source = "./module-new-service-principal"
spn_suffix = "module-new-spn"
deployment_scope = "/providers/Microsoft.Management/managementGroups/likvid"
}

module "existing_spn" {
count = var.create_new_spn == 1 ? 1 : 0
source = "./module-exisiting-service-principal"
existing_application_id = "be398b24-374f-415c-905f-b49814435dd1"
}

output "provider_existing_spn" {
description = "Please run 'terraform output provider_existing_spn' to export the provider configuration using the existing service principal"
value = module.existing_spn
sensitive = true
}

output "provider_new_spn" {
description = "Please run 'terraform output provider_new_spn' to export the provider configuration using this new service principal"
value = module.new_spn
sensitive = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//---------------------------------------------------------------------------
// ====== Using existing Service Principal ========
//---------------------------------------------------------------------------

data "azurerm_subscription" "current" {

}

variable "existing_application_id" {
type = string
description = "Application (client) ID of the Enterprise application"
}


data "azuread_service_principal" "existing_spn" {
client_id = var.existing_application_id
}
data "azuread_application" "existing_app" {
client_id = data.azuread_service_principal.existing_spn.client_id
}

resource "time_rotating" "building_blocks_secret_rotation" {
rotation_days = 365
}

resource "azuread_application_password" "existing_application_pw" {
application_id = "/applications/${data.azuread_application.existing_app.id}"
rotate_when_changed = {
rotation = time_rotating.building_blocks_secret_rotation.id
}
}

output "provider_block" {

description = "Generates a config.tf that can be dropped into meshStack's BuildingBlockDefinition as an encrypted file input to configure this building block."
value = <<EOF
provider "azurerm" {
features {}
client_id = "${data.azuread_service_principal.existing_spn.client_id}"
client_secret = "${azuread_application_password.existing_application_pw.value}
tenant_id = "${data.azurerm_subscription.current.tenant_id}"
subscription_id = "${data.azurerm_subscription.current.subscription_id}"
}
EOF
}

resource "local_file" "provider" {
filename = "./outputs/generated-provider.tf"
content = <<-EOT
provider "azurerm" {
features {}
client_id = "${data.azuread_service_principal.existing_spn.client_id}"
client_secret = "${azuread_application_password.existing_application_pw.value}"
tenant_id = "${data.azurerm_subscription.current.tenant_id}"
subscription_id = "${data.azurerm_subscription.current.subscription_id}"
}
EOT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
variable "storage_account_resource_id" {
type = string
description = "This is the ID of the storage account resource and it retrievable via panel. It is in the format of '/subscription/<sub_id>/resourcegroups/<rg_name>/..."
}

locals {
sta_resource_id = split("/", "${var.storage_account_resource_id}")
sta_subscription_id = local.sta_resource_id[2]
sta_rg_name = local.sta_resource_id[4]
sta_name = local.sta_resource_id[8]
}

data "azurerm_subscription" "sta_subscription" {
subscription_id = local.sta_subscription_id
}

output "backend_tf" {
sensitive = true
description = "Generates a config.tf that can be dropped into meshStack's BuildingBlockDefinition as an encrypted file input to configure this building block."
value = <<EOF
terraform {
backend "azurerm" {
tenant_id = "${data.azurerm_subscription.sta_subscription.tenant_id}"
subscription_id = "${local.sta_subscription_id}"
resource_group_name = "${local.sta_rg_name}"
storage_account_name = "${local.sta_name}"
container_name = "tfstates"
key = "building-block-standard-vnet"
}
}
EOF
}

resource "local_file" "backend" {
filename = "./outputs/generated-backend.tf"
content = <<-EOT
terraform {
backend "azurerm" {
tenant_id = "${data.azurerm_subscription.sta_subscription.tenant_id}"
subscription_id = "${local.sta_subscription_id}"
resource_group_name = "${local.sta_rg_name}"
storage_account_name = "${local.sta_name}"
container_name = "tfstates"
key = "building-block-standard-vnet"
}
}
EOT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
locals {
scope = var.deployment_scope
service_principal_name_suffix = var.spn_suffix
deployment_scope = var.deployment_scope
}

variable "deployment_scope" {
type = string
description = "The scope where this service principal have access on. Usually in the format of '/providers/Microsoft.Management/managementGroups/0000-0000-0000'"
}

variable "spn_suffix" {
type = string
description = "suffix for the SPN's name. The format is 'building_blocks.<SUFFIX>'"
}


data "azurerm_subscription" "current" {

}
//---------------------------------------------------------------------------
// Queries Entra ID for information about well-known application IDs.
// Retrieve details about the service principal
//---------------------------------------------------------------------------

data "azuread_application_published_app_ids" "well_known" {}

data "azuread_service_principal" "msgraph" {
client_id = data.azuread_application_published_app_ids.well_known.result.MicrosoftGraph
}

//---------------------------------------------------------------------------
// Create New application in Microsoft Entra ID
//---------------------------------------------------------------------------
resource "azuread_application" "building_blocks" {
display_name = "building_blocks.${local.service_principal_name_suffix}"

feature_tags {
enterprise = true
}
web {
implicit_grant {
access_token_issuance_enabled = false
}
}

lifecycle {
ignore_changes = [
app_role
]
}

logo_image = filebase64("./icon.png")

}

//---------------------------------------------------------------------------
// Create new client secret and associate it with building_blocks_application application
//---------------------------------------------------------------------------
resource "time_rotating" "building_blocks_secret_rotation" {
rotation_days = 365
}
resource "azuread_application_password" "building_blocks_application_pw" {
application_id = azuread_application.building_blocks.id
rotate_when_changed = {
rotation = time_rotating.building_blocks_secret_rotation.id
}
}

//---------------------------------------------------------------------------
// Create new Enterprise Application and associate it with building_blocks_application application
//---------------------------------------------------------------------------
resource "azuread_service_principal" "building_blocks_spn" {
client_id = azuread_application.building_blocks.client_id

feature_tags {
enterprise = true
custom_single_sign_on = true
}
}


//---------------------------------------------------------------------------
// Assign the created ARM role to the Enterprise application
//---------------------------------------------------------------------------
data "azurerm_role_definition" "builtin" {
name = "Contributor"
}

resource "azurerm_role_assignment" "building_blocks" {
scope = local.scope
role_definition_id = data.azurerm_role_definition.builtin.id
principal_id = azuread_service_principal.building_blocks_spn.id
}

output "provider_block" {
description = "Generates a config.tf that can be dropped into meshStack's BuildingBlock Definition as an encrypted file input to configure this building block."
value = <<EOF
provider "azurerm" {
features {}
client_id = "${azuread_service_principal.building_blocks_spn.client_id}"
client_secret = "${azuread_application_password.building_blocks_application_pw.value}"
tenant_id = "${data.azurerm_subscription.current.tenant_id}"
subscription_id = "${data.azurerm_subscription.current.subscription_id}"
}
EOF
}

resource "local_file" "provider" {
filename = "./outputs/generated-provider.tf"
content = <<-EOT
provider "azurerm" {
features {}
client_id = "${azuread_service_principal.building_blocks_spn.client_id}"
client_secret = "${azuread_application_password.building_blocks_application_pw.value}"
tenant_id = "${data.azurerm_subscription.current.tenant_id}"
subscription_id = "${data.azurerm_subscription.current.subscription_id}"
}
EOT
}
Loading
Loading