Skip to content

Commit

Permalink
Merge pull request #38 from amido/feature/module-kv
Browse files Browse the repository at this point in the history
  • Loading branch information
ElvenSpellmaker authored Mar 23, 2023
2 parents c06e963 + 1ba6a50 commit d8948f7
Show file tree
Hide file tree
Showing 10 changed files with 546 additions and 0 deletions.
127 changes: 127 additions & 0 deletions azurerm/modules/azurerm-kv/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<!-- BEGIN_TF_DOCS -->
PROJECT_NAME

DESCRIPTION:
---
Bootstraps the infrastructure for {{SELECT_APP_TYPE }}.

Will be used within the provisioned pipeline for your application depending on the options you chose.

Pipeline implementation for infrastructure relies on workspaces, you can pass in whatever workspace you want from {{ SELECT_DEPLOYMENT_TYPE }} pipeline YAML.

PREREQUISITES:
---
Azure Subscripion
- SPN
- Terraform will use this to perform the authentication for the API calls
- you will need the `client_id, subscription_id, client_secret, tenant_id`

Terraform backend
- resource group (can be manually created for the terraform remote state)
- Blob storage container for the remote state management


USAGE:
---

To activate the terraform backend for running locally we need to initialise the SPN with env vars to ensure you are running the same way as the pipeline that will ultimately be running any incremental changes.

```bash
docker run -it --rm -v $(pwd):/opt/tf-lib amidostacks/ci-tf:latest /bin/bash
```

```bash
export ARM_CLIENT_ID=xxxx \
ARM_CLIENT_SECRET=yyyyy \
ARM_SUBSCRIPTION_ID=yyyyy \
ARM_TENANT_ID=yyyyy
```

alternatively you can run `az login`

To get up and running locally you will want to create a `terraform.tfvars` file
```bash
TFVAR_CONTENTS='''
vnet_id = "amido-stacks-vnet-uks-dev"
rg_name = "amido-stacks-rg-uks-dev"
resource_group_location = "uksouth"
name_company = "amido"
name_project = "stacks"
name_component = "spa"
name_environment = "dev"
'''
$TFVAR_CONTENTS > terraform.tfvars
```

```
terraform workspace select dev || terraform workspace new dev
```

terraform init -backend-config=./backend.local.tfvars
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.13 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | ~> 3.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | ~> 3.0 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [azurerm_key_vault.example](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault) | resource |
| [azurerm_key_vault_access_policy.contributors_access_policy](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
| [azurerm_key_vault_access_policy.reader_access_policy](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
| [azurerm_client_config.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/client_config) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_contributor_object_ids"></a> [contributor\_object\_ids](#input\_contributor\_object\_ids) | A list of Azure active directory user,group or application object ID's that will have contributor role to the key vault | `list(string)` | `[]` | no |
| <a name="input_create_kv"></a> [create\_kv](#input\_create\_kv) | set value wether to create a KV or not | `bool` | `true` | no |
| <a name="input_create_kv_networkacl"></a> [create\_kv\_networkacl](#input\_create\_kv\_networkacl) | whether to create a acl for kv or not | `bool` | `false` | no |
| <a name="input_enable_rbac_authorization"></a> [enable\_rbac\_authorization](#input\_enable\_rbac\_authorization) | whether Azure Resource Manager is permitted to retrieve secrets from the key vault | `bool` | `false` | no |
| <a name="input_enabled_for_disk_encryption"></a> [enabled\_for\_disk\_encryption](#input\_enabled\_for\_disk\_encryption) | Boolean flag to specify whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys | `bool` | `true` | no |
| <a name="input_enabled_for_template_deployment"></a> [enabled\_for\_template\_deployment](#input\_enabled\_for\_template\_deployment) | whether Azure Resource Manager is permitted to retrieve secrets from the key vault | `bool` | `false` | no |
| <a name="input_key_permissions"></a> [key\_permissions](#input\_key\_permissions) | List of key permissions | `list(string)` | <pre>[<br> "Get"<br>]</pre> | no |
| <a name="input_name_component"></a> [name\_component](#input\_name\_component) | Component Name - should/will be used in conventional resource naming. Typically this will be a logical name for this part of the system i.e. `API` \|\| `middleware` or more generic like `Billing` | `string` | `"kv"` | no |
| <a name="input_network_acl_default_action"></a> [network\_acl\_default\_action](#input\_network\_acl\_default\_action) | he Name of the SKU used for this Key Vault. Possible values are standard and premium | `string` | `"Deny"` | no |
| <a name="input_network_acls_bypass"></a> [network\_acls\_bypass](#input\_network\_acls\_bypass) | Specifies which traffic can bypass the network rules. Possible values are AzureServices and None | `string` | `"AzureServices"` | no |
| <a name="input_network_acls_ip_rules"></a> [network\_acls\_ip\_rules](#input\_network\_acls\_ip\_rules) | The Default Action to use when no rules match from ip\_rules / virtual\_network\_subnet\_ids. Possible values are Allow and Deny | `list(string)` | `[]` | no |
| <a name="input_purge_protection_enabled"></a> [purge\_protection\_enabled](#input\_purge\_protection\_enabled) | Is Purge Protection enabled for this Key Vault | `bool` | `false` | no |
| <a name="input_reader_object_ids"></a> [reader\_object\_ids](#input\_reader\_object\_ids) | A list of Azure active directory user,group or application object ID's that will have reader role to the key vault | `list(string)` | `[]` | no |
| <a name="input_resource_group_location"></a> [resource\_group\_location](#input\_resource\_group\_location) | Location of Resource group | `string` | `"uksouth"` | no |
| <a name="input_resource_group_name"></a> [resource\_group\_name](#input\_resource\_group\_name) | name of resource group | `string` | n/a | yes |
| <a name="input_resource_namer"></a> [resource\_namer](#input\_resource\_namer) | User defined naming convention applied to all resources created as part of this module | `string` | n/a | yes |
| <a name="input_resource_tags"></a> [resource\_tags](#input\_resource\_tags) | Map of tags to be applied to all resources created as part of this module | `map(string)` | `{}` | no |
| <a name="input_secret_permissions"></a> [secret\_permissions](#input\_secret\_permissions) | List of secret permissions, must be one or more | `list(string)` | <pre>[<br> "Get"<br>]</pre> | no |
| <a name="input_sku_name"></a> [sku\_name](#input\_sku\_name) | he Name of the SKU used for this Key Vault. Possible values are standard and premium | `string` | `"standard"` | no |
| <a name="input_soft_delete_retention_days"></a> [soft\_delete\_retention\_days](#input\_soft\_delete\_retention\_days) | number of days that items should be retained for once soft-deleted. This value can be between 7 and 90 | `number` | `7` | no |
| <a name="input_storage_permissions"></a> [storage\_permissions](#input\_storage\_permissions) | List of storage permissions, must be one or more from the following | `list(string)` | <pre>[<br> "Get"<br>]</pre> | no |
| <a name="input_virtual_network_subnet_ids"></a> [virtual\_network\_subnet\_ids](#input\_virtual\_network\_subnet\_ids) | One or more IP Addresses, or CIDR Blocks which should be able to access the Key Vault | `list(string)` | `[]` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_id"></a> [id](#output\_id) | The ID of the Key Vault. |
| <a name="output_key_vault_name"></a> [key\_vault\_name](#output\_key\_vault\_name) | n/a |
| <a name="output_vault_uri"></a> [vault\_uri](#output\_vault\_uri) | vault\_uri |

## EXAMPLES:
---
There is an examples folder with possible usage patterns.

`example`
<!-- END_TF_DOCS -->
9 changes: 9 additions & 0 deletions azurerm/modules/azurerm-kv/constraints.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 0.13"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
9 changes: 9 additions & 0 deletions azurerm/modules/azurerm-kv/example/constraints.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 0.13"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
33 changes: 33 additions & 0 deletions azurerm/modules/azurerm-kv/example/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
data "azurerm_client_config" "current" {}

module "default_label" {
source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=0.25.0"
namespace = "${var.name_company}-${var.name_project}"
stage = var.stage
name = "${lookup(var.location_name_map, var.resource_group_location, "uksouth")}-${var.name_component}"
attributes = var.attributes
delimiter = "-"
tags = var.tags
}

##################################################
# ResourceGroups
##################################################

resource "azurerm_resource_group" "default" {
name = module.default_label.id
location = var.resource_group_location
tags = var.tags
}

module "kv_default" {
source = "../../azurerm-kv"
resource_namer = module.default_label.id
resource_group_name = azurerm_resource_group.default.name
resource_group_location = azurerm_resource_group.default.location
create_kv_networkacl = false
enable_rbac_authorization = false
contributor_object_ids = var.contributor_object_ids
reader_object_ids = var.reader_object_ids

}
8 changes: 8 additions & 0 deletions azurerm/modules/azurerm-kv/example/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

output "resource_group_name" {
value = azurerm_resource_group.default.name
}

output "key_vault_name" {
value = module.kv_default.key_vault_name
}
13 changes: 13 additions & 0 deletions azurerm/modules/azurerm-kv/example/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
terraform {
backend "azurerm" {
resource_group_name = "tfstateresourcegroup"
storage_account_name = "tfstate"
container_name = "tfstate"
key = "devkv.terraform.tfstate"
}

}

provider "azurerm" {
features {}
}
75 changes: 75 additions & 0 deletions azurerm/modules/azurerm-kv/example/vars.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
############################################
# NAMING
############################################

variable "name_company" {
description = "Company Name - should/will be used in conventional resource naming"
type = string
}

variable "name_project" {
description = "Project Name - should/will be used in conventional resource naming"
type = string
}

variable "name_component" {
description = "Component Name - should/will be used in conventional resource naming. Typically this will be a logical name for this part of the system i.e. `API` || `middleware` or more generic like `Billing`"
type = string
}

variable "name_environment" {
type = string
}

variable "stage" {
type = string
default = "dev"
}

variable "attributes" {
description = "Additional attributes for tagging"
default = []
}

variable "tags" {
description = "Tags to be assigned to all resources, NB if global tagging is enabled these will get overwritten periodically"
type = map(string)
default = {}
}


variable "resource_group_location" {
type = string
default = "uksouth"
}


# Each region must have corresponding a shortend name for resource naming purposes
variable "location_name_map" {
type = map(string)

default = {
northeurope = "eun"
westeurope = "euw"
uksouth = "uks"
ukwest = "ukw"
eastus = "use"
eastus2 = "use2"
westus = "usw"
eastasia = "ase"
southeastasia = "asse"
}
}


variable "contributor_object_ids" {
description = "A list of Azure active directory user,group or application object ID's that will have contributor role to the key vault"
type = list(string)
default = []
}

variable "reader_object_ids" {
description = "A list of Azure active directory user,group or application object ID's that will have reader role to the key vault"
type = list(string)
default = []
}
110 changes: 110 additions & 0 deletions azurerm/modules/azurerm-kv/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@

# Configure data to access the SPN that has been used to deploy the environment
data "azurerm_client_config" "current" {
}


resource "azurerm_key_vault" "example" {
count = var.create_kv ? 1 : 0
name = var.resource_namer
location = var.resource_group_location
resource_group_name = var.resource_group_name
enabled_for_disk_encryption = var.enabled_for_disk_encryption
tenant_id = data.azurerm_client_config.current.tenant_id
soft_delete_retention_days = var.soft_delete_retention_days
purge_protection_enabled = var.purge_protection_enabled
enabled_for_template_deployment = var.enabled_for_template_deployment
enable_rbac_authorization = var.enable_rbac_authorization
sku_name = var.sku_name


dynamic "network_acls" {
for_each = var.create_kv_networkacl == false ? toset([]) : toset([1])
content {
bypass = var.network_acls_bypass
default_action = var.network_acl_default_action
ip_rules = var.network_acls_ip_rules
virtual_network_subnet_ids = var.virtual_network_subnet_ids
}


}


tags = var.resource_tags
lifecycle {
ignore_changes = [
tags,
]
}
}


resource "azurerm_key_vault_access_policy" "contributors_access_policy" {
count = length(var.contributor_object_ids)

key_vault_id = azurerm_key_vault.example.0.id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = var.contributor_object_ids[count.index]

key_permissions = [
"Get",
"List",
"Delete",
"Create",
"Update",
"Import",
"Backup",
"Recover",
"Restore"
]

secret_permissions = [
"Get",
"List",
"Delete",
"Set",
"Backup",
"Recover",
"Restore"
]

certificate_permissions = [
"Get",
"List",
"Update",
"Create",
"Import",
"Delete",
"Backup",
"Recover",
"Restore"
]

storage_permissions = []
}

resource "azurerm_key_vault_access_policy" "reader_access_policy" {
count = length(var.reader_object_ids)

key_vault_id = azurerm_key_vault.example.0.id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = var.reader_object_ids[count.index]

key_permissions = [
"Get",
"List"
]

secret_permissions = [
"Get",
"List"
]

certificate_permissions = [
"Get",
"GetIssuers",
"List",
"ListIssuers"
]
}
Loading

0 comments on commit d8948f7

Please sign in to comment.