Terraform for_each azure customer managed keys - automation

I am trying to user a for_each to create multiple azure storage accounts and azure secrets and keys.
so far so good and managed to create everything as supposed to be using this code:
variable "storage-foreach" {
type = list(string)
default = ["storage1", "storage2"]
}
variable "key-name" {
type = list(string)
default = ["key1", "key2"]
}
resource "azurerm_storage_account" "storage-foreach" {
for_each = toset(var.storage-foreach)
access_tier = "Hot"
account_kind = "StorageV2"
account_replication_type = "LRS"
account_tier = "Standard"
location = var.location
name = each.value
resource_group_name = azurerm_resource_group.tenant-testing-test.name
lifecycle {
prevent_destroy = false
}
}
resource "azurerm_key_vault_secret" "storagesctforeach" {
for_each = toset(var.storage-foreach)
key_vault_id = azurerm_key_vault.tenantsnbshared.id
name = each.value
value = azurerm_storage_account.storage-foreach[each.key].primary_connection_string
content_type = "${each.value} Storage Account Connection String"
lifecycle {
prevent_destroy = false
}
}
resource "azurerm_storage_table" "tableautomation" {
for_each = toset(var.storage-foreach)
name = "UserAnswer"
storage_account_name = azurerm_storage_account.storage-foreach[each.key].name
lifecycle {
prevent_destroy = false
}
}
resource "azurerm_key_vault_key" "client-key" {
for_each = toset(var.key-name)
key_vault_id = azurerm_key_vault.tenantsnbshared.id
name = "Key-Client-${each.value}"
key_opts = [
"decrypt",
"encrypt",
"sign",
"unwrapKey",
"verify",
"wrapKey",
]
key_type = "RSA"
key_size = 2048
}
This block of code works perfectly fine until when I try to create a customer managed key resource and automatically assign the keys to the storage accounts.
resource "azurerm_storage_account_customer_managed_key" "storage-managed-key" {
for_each = toset(var.key-name)
key_name = each.value
key_vault_id = azurerm_key_vault.tenantsnbshared.id
storage_account_id = azurerm_storage_account.storage-foreach[each.value].id
key_version = "current"
}
The problem I am facing is, as I created all the previous resources with a for_each in the above resource is expecting a [each.value] in my storage account id. Which I placed but that parameter is targeting the var.key-name, which is throwing an error as it can't find those strings in my storage account.
I was wondering if you can help me to think about a good practice to automate this procedure and make sure that it picks up the correct key to encrypt the correct storage account id in the resource group.
Thank you very much in advance everyone, and I am sorry but I have been struggling on this block of code and how I can automate it.

The problem is you are trying to access var.storage-foreach items by using the var.key-name.
I think the following works for you:
resource "azurerm_storage_account_customer_managed_key" "storage-managed-key" {
count = length(var.key-name)
key_name = var.key-name[count.index]
key_vault_id = azurerm_key_vault.tenantsnbshared.id
storage_account_id = azurerm_storage_account.storage-foreach[var.storage-foreach[count.index]].id
key_version = "current"
}

Related

connection string generated by atlas cluster using terraform not in correct format

So im using terraform to create an atlas cluster but the output im getting is incompleteate to do my request terraform is givim me this:
mongodb+srv://esc-app-dbcluster-devel.b59mwv7.mongodb.net
and what i need shoul be more like this:
mongodb+srv://admin:admin#esc-app-dbcluster-devel.b59mwv7.mongodb.net/development?retryWrites=true&w=majority
or atleast thats the format that works with what im testing.
this is my terraform code:
terraform {
required_providers {
mongodbatlas = {
source = "mongodb/mongodbatlas"
version = "1.4.6"
}
}
}
provider "mongodbatlas" {
public_key = var.atlas_public_key
private_key = var.atlas_private_key
}
resource "mongodbatlas_cluster" "db-cluster" {
project_id = var.atlas_project_id
name = var.db_cluster_name
# Provider Settings "block"
provider_name = "TENANT" //free tier
backing_provider_name = "AWS"
provider_region_name = "US_EAST_1" //free tier
provider_instance_size_name = "M0" //free tier
}
resource "mongodbatlas_database_user" "dbuser" {
username = var.db_user
password = var.db_password
project_id = var.atlas_project_id
auth_database_name = "admin"
roles {
role_name = "readWrite"
database_name = var.environment
}
}
resource "mongodbatlas_project_ip_access_list" "test" {
project_id = var.atlas_project_id
cidr_block = var.cidr
}
output "db_cn_string" {
value = mongodbatlas_cluster.db-cluster.connection_strings.0.standard_srv
}
code i use to connect
const environment = process.env.ENVIRONMENT;
const uridb = "mongodb+srv://admin:admin#esc-app-dbcluster-devel.b59mwv7.mongodb.net/development?retryWrites=true&w=majority" // working format
//dburi = "mongodb+srv://esc-app-dbcluster-devel.b59mwv7.mongodb.net" --- format from terraform
console.log('environment:::::', environment);
let ENVIRONMENT_VARIABLES = {
'process.env.ENVIRONMENT': JSON.stringify(environment),
'process.env.PORT': JSON.stringify('80'),
'process.env.MONGO_CONNECTION_STRING': JSON.stringify(uridb)
};
need a way to genarate the proper connection string

Module with multiple providers

I have a question regarding the following.
I am using terraform with fortios provider
tree:
these are my providers in the root-prod:
provider "fortios" {
hostname = "xxxxx"
token = "xxxxx"
insecure = "true"
vdom = "PROD"
}
provider "fortios" {
hostname = "xxxx"
token = "xxxx"
insecure = "true"
vdom = "OPS"
alias = "isops"
}
I h got my root-module-prod:
module "AWS_xxx"{
source = "../modules"
name = "AWS_PROD"
prefix_lists = local.aws_prod
providers = {
fortios.dc1 = fortios
fortios.dc2 = fortios.isops
}
}
provider & resource within-child-modules:
terraform {
required_providers {
fortios = {
source = "fortinetdev/fortios"
version = "1.13.1"
configuration_aliases = [ fortios.dc1, fortios.dc2 ]
}
}
}
resource "fortios_router_prefixlist" "prefix_lists" {
name = var.name
dynamic "rule" {
for_each = var.prefix_lists
content {
id = rule.value["id"]
action = rule.value["action"]
prefix = rule.value["prefix"]
ge = rule.value["ge"]
le = rule.value["le"]
}
}
}
my goal is for the above module to create two instances of the resource, one in each of the declared providers.
My issue is that while the resource is created in the first provider PROD it doesn't crated in OPS.
Do you have any clue on this..?
Not really did not work through Terraform-multi-providers.
In our case, I found a way through Jenkins Parallelism.
We launch in parallel multiple envs with the credentials saved encrypted in Jenkins server.

How to pass/concat variable into the `data.aws_ami` section in the `aws_instance` resource

I am having difficulties with defining a variable inside the ami=data.aws_ami.$var.ami_name.id line.
I have tried ami= "${data.aws_ami.(var.ami_name).id}"but in both cases I am getting the:
79: ami = data.aws_ami.(var.ami_name)).id
│
│ An attribute name is required after a dot.
It only works with the string value data.aws_ami.ubuntu-1804.id.
My question is how to concat the variable to the data.aws_ami?
The end goal is to provision based on different OS ec2 instances (Suse,Ubuntu,RHEL) All depending on the variable provided when deploying it.
variable "ami_name" {
default = "ubuntu"
}
data "aws_ami" "amazon" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm*"]
}
}
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
resource "aws_instance" "linux" {
key_name = var.ami_key_pair_name
//ami = var.ami_id
//I want this to be dynamic so I can deploy either Amazon or Ubuntu in all regions.
ami = data.aws_ami.$var.ami_name.id
//ami = data.aws_ami.ubuntu.id # this works
instance_type = "t2.micro"
tags = {
Name = var.instance_name
}
vpc_security_group_ids = [
aws_security_group.allow-ssh-http.id
]
}
I did the search but could not find anything related. I am using Terraform v0.15.4
The code you show: data.aws_ami.$var.ami_name.id that is not valid terraform syntax.
Here is a possibility for what you are asking:
provider "aws" { region = "us-east-2" }
locals {
allowed_os = {
"amazon": {owner: "amazon", filter: "amzn2-ami-hvm*"},
"suse": {owner: "amazon", filter: "*suse*"},
"RHEL": {owner: "amazon", filter: "*RHEL*"},
"ubuntu": {owner: "099720109477", filter: "*ubuntu-bionic-18.04-amd64-*"},
}
}
variable "ami_name" {
default = "ubuntu"
validation {
condition = can(regex("amazon|suse|RHEL|ubuntu", var.ami_name))
error_message = "Invalid ami name, allowed_values = [amazon suse RHEL ubuntu]."
}
}
data "aws_ami" "os" {
for_each = local.allowed_os
most_recent = true
owners = [each.value.owner]
filter {
name = "name"
values = [each.value.filter]
}
}
resource "aws_instance" "linux" {
ami = data.aws_ami.os[var.ami_name].id
instance_type = "t2.micro"
# ... todo add arguments here
}
My approach here is to use a for_each in the aws_ami, that will give us an array, we can consume that later in the aws_instance resource:
data.aws_ami.os["ubuntu"].id
Here we use a hardcoded value to access a specific AMI in your code.
data.aws_ami.os[var.ami_name].id
Or this way with the variable that will be provided by user or a config file.
You can add more items to the array to add other operating systems, and same with the filters, you can just change the allowed_os local variable to suit your needs.
As an extra, I added validation to your ami_name variable to match the allowed different OS we use in the for_each, that way we prevent any issues right before they can cause errors.

How to configure App Service to use Azure AD login from Terraform

It is easy to Configure a web App Service to use Azure AD login manually via the official document However, How can I achieve this from Terraform? I've searched a while didn't found any examples, if you happen to address one, would be nice to share with me.
The following code is how I created Resource group and provisioned the web application
terraform {
backend "azurerm" {}
}
terraform {
required_version = ">= 0.13"
}
resource "azurerm_resource_group" "tf_resource_group" {
name = "RG_${var.application_name}_${var.environment}"
location = var.location
tags = {
environment = var.environment
DeployedBy = "terraform"
}
}
resource "azurerm_app_service_plan" "tf_service_plan" {
name = "${var.application_name}-${var.environment}-asp"
location = azurerm_resource_group.tf_resource_group.location
resource_group_name = azurerm_resource_group.tf_resource_group.name
kind = "Linux"
reserved = true
sku {
tier = "Standard"
size = "S1"
}
tags = {
environment = var.environment
DeployedBy = "terraform"
}
}
resource "azurerm_app_service" "tf_app_service" {
name = var.application_name
location = azurerm_resource_group.tf_resource_group.location
resource_group_name = azurerm_resource_group.tf_resource_group.name
app_service_plan_id = azurerm_app_service_plan.tf_service_plan.id
site_config {
always_on = true
linux_fx_version = "DOCKER|${var.acr_name}.azurecr.io/${var.img_repo_name}:${var.tag}"
}
app_settings = {
DOCKER_REGISTRY_SERVER_URL = "$DRSRUL"
WEBSITES_ENABLE_APP_SERVICE_STORAGE = "false"
DOCKER_REGISTRY_SERVER_USERNAME = "$ACRNAME"
DOCKER_REGISTRY_SERVER_PASSWORD = "$PW"
}
identity {
type = "SystemAssigned"
}
}
I believe your "azurerm_app_service" resource block needs a auth_settings block with a active_directory block. Example:
auth_settings {
enabled = true
active_directory {
client_id = "${azuread_application.example.application_id}"
}
default_provider = "AzureActiveDirectory"
issuer = "https://sts.windows.net/xxxxxxx-xxxx-xxx-xxxx-xxxtenantID/"

How to create new database in the serverless compute tier in Azure Sql through terraform

I want to create new database in the serverless compute tier in Azure Sql through Terraform. Is it possible to create ? if yes could you please tell me how to create it ?
The serverless compute tier is currently available on Gen5 hardware only.
Just set one of the Gen5 pricing tiers to SKU in azurerm_mssql_database block.
A working example is as below:
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "rg" {
location = var.location
name = var.rg_name
}
resource "azurerm_sql_server" "sqlserver" {
name = var.sqlserver_name
resource_group_name = azurerm_resource_group.rg.name
location = var.location
version = "12.0"
administrator_login = var.admin
administrator_login_password = var.admin_password
}
resource "azurerm_mssql_database" "serverless_db" {
name = "serverles-db"
server_id = azurerm_sql_server.sqlserver.id
collation = "SQL_Latin1_General_CP1_CI_AS"
auto_pause_delay_in_minutes = 60
max_size_gb = 32
min_capacity = 0.5
read_replica_count = 0
read_scale = false
sku_name = "GP_S_Gen5_1"
zone_redundant = false
threat_detection_policy {
disabled_alerts = []
email_account_admins = "Disabled"
email_addresses = []
retention_days = 0
state = "Disabled"
use_server_default = "Disabled"
}
}