I am trying to add admin users to SQl Db in terraform where as ending up with syntax error There are some problems with the configuration, described below.
The Terraform configuration must be valid before initialization so that
Terraform can determine which modules and providers need to be installed.
╷
│ Error: Unsupported argument
│
│ on common_locals.tf line 171:
sql_db_login_name_map = {
"123#gmail.com" = "object_id 123"
"234#gmail.com" = "Object_Id 234"
"456#gmail.com" = "object _id 345"
"678#gmail.com" = "Object _id 567"
}
main.tf
resource "azurerm_sql_active_directory_administrator" "Sql_ad_admin" {
server_name = azurerm_sql_server.sql-db-server.name
resource_group_name = azurerm_resource_group.123_rg.name
for_each = local.sql_db_login_name_map
login = "${each.key}"
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = "${each.value}"
}
Could you please specify if i am missing something in mapping my values ?
Related
So my goal is to have write a terraform code to deploy 3 resource groups in AZ dev, uat and prod with each having the following resources.
SQL Database
Key Vault
variable.tf
variable "resource_group_name" {
description = "deafault resource group"
type = list (string)
default = ["Test-dev","Test-uat","Test-prod"]
}
variable "storage_account_name" {
description = "name for storage account"
default = "test-storageact"
}
main.tf
resource "azurerm_resource_group" "resgrp" {
for_each = toset(var.resource_group_name)
name = "${var.resource_group_name}-rg-${each.value}"
location = var.location
tags = {
"Environment" = "${var.env}-${each.value}"
}
}
resource "azurerm_storage_account" "storageact" {
for_each = toset(var.resource_group_name)
name = "${var.storage_account_name}-${each.value}"
resource_group_name = azurerm_resource_group.resgrp["${each.value}"].location
location = azurerm_resource_group.resgrp["${each.value}"].name
account_tier = "Standard"
account_replication_type = "LRS"
tags = {
"Environment" = "${var.env}-${each.value}"
}
}
error message
│ Error: Invalid template interpolation value
│
│ on main.tf line 3, in resource "azurerm_resource_group" "resgrp":
│ 3: name = "${var.resource_group_name}-rg-${each.value}"
│ ├────────────────
│ │ var.resource_group_name is list of string with 3 elements
│
│ on main.tf line 6, in resource "azurerm_resource_group" "resgrp":
│ 6: "Environment" = "${var.env}-${each.value}"
│ ├────────────────
│ │ var.env is map of string with 3 elements
│
│ Cannot include the given value in a string template: string required.
╵
Operation failed: failed running terraform plan (exit 1)
please any help will be greatly appreciated.
i tried using type = map(string) in the variable but still gave me an error.
There are a few problems with the code.
var.resource_group_name is a list containing 3 string elements (by default), and thus the error: var.resource_group_name is list of string with 3 elements explains the problem, and is illustrated below.
The var.env is a map consisting of 3 elements and also being used as a string and fails for the same reason.
resource "azurerm_resource_group" "resgrp" {
for_each = toset(var.resource_group_name)
# var.resource_group_name is actually a list, but it's being
# used as a string here, which will fail.
name = "${var.resource_group_name}-rg-${each.value}"
location = var.location
tags = {
"Environment" = "${var.env}-${each.value}"
}
}
You probably instead want:
resource "azurerm_resource_group" "resgrp" {
for_each = toset(var.resource_group_name)
name = "${each.value}-rg"
location = var.location
tags = {
"Environment" = "${each.value}"
}
}
Additionally, as an alternative to the approach of putting multiple environments in a single resource construct, consider using modules to create reusable infrastructure for your resources and then calling each module for the environment that you're using, this is a best practice when implementing duplicate or near-duplicate infrastructure across multiple environments and allows you some flexibility with naming conventions and other parameters that would differ based upon the environment.
Rough example:
module "test-dev" {
source = "../modules/infrastructure"
environment = "Test-dev"
vm_count = 1
}
module "test-uat" {
source = "../modules/infrastructure"
environment = "Test-dev"
vm_count = 3
}
module "test-prod" {
source = "../modules/infrastructure"
environment = "Test-prod"
account_tier = "Premium"
vm_count = 6
}
I have the following code:
resource "random_string" "password" {
length = 16
special = true
override_special = "_%#"
}
resource "azuread_service_principal_password" "auth" {
service_principal_id = azuread_service_principal.auth.id
value = random_string.password.result
end_date_relative = "240h"
}
I want to use the password in a resource to create an AKS cluster:
resource "azurerm_kubernetes_cluster" "default" {
name = "${random_pet.prefix.id}-aks"
location = azurerm_resource_group.default.location
resource_group_name = azurerm_resource_group.default.name
dns_prefix = "${random_pet.prefix.id}-k8s"
default_node_pool {
name = var.node_pool
node_count = var.node_count
vm_size = var.vm_size
os_disk_size_gb = 30
}
service_principal {
client_id = azuread_service_principal.auth.application_id
client_secret = azuread_service_principal_password.auth.value
}
role_based_access_control {
enabled = true
}
tags = {
environment = "Demo"
}
}
However, when I run terraform apply, I get:
Error: Value for unconfigurable attribute
│
│ with azuread_service_principal_password.auth,
│ on aks-cluster.tf line 26, in resource "azuread_service_principal_password" "auth":
│ 26: value = random_string.password.result
│
│ Can't configure a value for "value": its value will be decided automatically based on the result of applying this
│ configuration.
Is there a way of generating the service principal password in my config and then using it later on in the same configuration ?
Is there a way of generating the service principal password in my
config and then using it later on in the same configuration?
If your question is to set a user defined password/secret for a Service Principal, then it is not possible to do so.
azuread_service_principal_password is essentially a wrapper over servicePrincipal: addPassword Graph API call which does not allow you to specify your own password/secret.
You need to use azuread_application_password instead of azuread_service_principal_password so you can specify the random string value.
Curently I'm trying to build dev and production environment without duplicating resource blocks. I have found that I can crate map of objects and use for loop for this.
For this I have created this piece of code that was
variable "sqlserver" {
type = map(object({
name = string
username = string
password = string
}))
}
sqlserver = {
"dev" = {
name = "devsonovasqlserver"
username = "dev_username"
password = "biaJB8wQJb4n!RwG"
}
"prd" = {
name = "testexamplesqlsonova"
username = "prd_username"
password = "biaJB8wQJb4asdan!RwG"
}
}
resource "azurerm_sql_server" "sql_server" {
for_each = var.sqlserver
name = each.value["name"]
resource_group_name = var.dev_main_rg
location = var.location
version = "12.0"
administrator_login = each.value["username"]
administrator_login_password = each.value["password"]
}
This sadly raise Error like
╷
│ Error: Incorrect attribute value type
│
│ on main.tf line 56, in resource "azurerm_sql_server" "dev_sql_server":
│ 56: name = var.sqlserver.name
│ ├────────────────
│ │ var.sqlserver.name is a object, known only after apply
│
│ Inappropriate value for attribute "name": string required.
╵
Your code is valid. When I copy it to a project of my own it works fine. I guess you have something else in your files that make it work different from what is shown here.
I have recently created a cosmos database in Terraform and I am trying to pass its database connection string as a secret in keyvault, but when doing this I get the following error:
Error: Incorrect attribute value type │ │ on keyvault.tf line 282, in resource "azurerm_key_vault_secret" "Authentication_Server_Cosmos_DB_ConnectionString": │ 282: value = azurerm_cosmosdb_account.nsauthsrvcosmosdb.connection_strings │ ├──────────────── │ │ azurerm_cosmosdb_account.nsauthsrvcosmosdb.connection_strings has a sensitive value │ │ Inappropriate value for attribute "value": string required.
I have also tried to use the sensitive argument but key vault does not like that argument also I cant find any documentation on how to do this. On the Terraform website it just has it listed as an attribute you can call on.
My Terraform Secret code is bellow, I wont put all my code in here as Stack overflow doesn't like the amount of code that I have.
So please presume, I am using the latest Azurerm agent, and all the rest of my code is correct its just the secret part that's not working.
resource "azurerm_key_vault_secret" "Authentication_Server_Cosmos_DB_ConnectionString" { //Auth Server Cosmos Connection String Secret
name = "AuthenticationServerCosmosDBConnectionString"
value = azurerm_cosmosdb_account.nsauthsrvcosmosdb.connection_strings
key_vault_id = azurerm_key_vault.nscsecrets.id
depends_on = [
azurerm_key_vault_access_policy.client,
azurerm_key_vault_access_policy.service_principal,
azurerm_cosmosdb_account.nsauthsrvcosmosdb,
]
}
There are 4 connection Strings inside the value that you have given and also the values are of type secure_string . So you need to convert them to String Value and apply index for which value you want to store in the keyvault.
For Storing all the the 4 Connection Strings you can use below :
resource "azurerm_key_vault_secret" "example" {
count = length(azurerm_cosmosdb_account.nsauthsrvcosmosdb.connection_strings)
name = "AuthenticationServerCosmosDBConnectionString-${count.index}"
value = tostring("${azurerm_cosmosdb_account.nsauthsrvcosmosdb.connection_strings[count.index]}")
key_vault_id = azurerm_key_vault.example.id
}
Outputs:
If you want to store only one connection string then you can use index as per your requirement (for example : if you want to store the first connection_string then use '0' as index and like wise 1/2/3 .) in the below code:
resource "azurerm_key_vault_secret" "example1" {
name = "AuthenticationServerCosmosDBConnectionString"
value = tostring("${azurerm_cosmosdb_account.nsauthsrvcosmosdb.connection_strings[0]}")
key_vault_id = azurerm_key_vault.example.id
}
Outputs:
I am trying to use terraform string function and string concatenation on a terraform tfvars variable. but when run the terraform plan it through the below exception
Error: A reference to a resource type must be followed by at least one attribute
access, specifying the resource name.
Following is the terraform code
locals {
name_suffix = "${var.namespace != "" ? var.namespace : var.env}"
}
resource "azurerm_container_registry" "my_acr" {
name = "myacr${replace(name_suffix, "-", "")}"
location = "${azurerm_resource_group.location}"
resource_group_name = "${azurerm_resource_group.name}"
sku = "Basic"
admin_enabled = true
}
Here namespace value will be resolved at runtime.
Terraform version 0.12.7
it was a silly mistake. instead of name_suffix, I should have written it like local.name_suffix inside the acr resource
Had a similar issue when setting up Terraform configuration files for AWS Fargate.
Got the error below:
│ Error: Invalid reference
│
│ on ../ecs/main.tf line 72, in resource "aws_ecs_service" "aes":
│ 72: type = order_placement_type
│
│ A reference to a resource type must be followed by at least one attribute access, specifying the resource name.
╵
╷
│ Error: Invalid reference
│
│ on ../ecs/main.tf line 73, in resource "aws_ecs_service" "aes":
│ 73: field = order_placement_field
│
│ A reference to a resource type must be followed by at least one attribute access, specifying the resource name.
The issue was that I missed the var prefix for variables, so instead of this:
ordered_placement_strategy {
type = order_placement_type
field = order_placement_field
}
I corrected it to this:
ordered_placement_strategy {
type = var.order_placement_type
field = var.order_placement_field
}
That's all.
Another thing to check. Make sure you have the index specifier in the correct position.
I had the following code and ran into this problem:
data "cloudflare_origin_ca_root_certificate" "current" {
count = var.domain == null ? 0 : 1
algorithm = tls_private_key.privateKey[0].algorithm
}
resource "aws_acm_certificate" "cert" {
count = var.domain == null ? 0 : 1
#...
certificate_chain = data.cloudflare_origin_ca_root_certificate[0].current.cert_pem
}
Turns out I made the mistake of putting the [0] before the current selector instead of after. So I just had to change the certificate_chain line to the following:
certificate_chain = data.cloudflare_origin_ca_root_certificate.current[0].cert_pem