terraform Error: Cycle: data.azurerm_key_vault_secret - terraform

This is my first file main.tf
# Configure the Azure provider
provider "azurerm" {
environment = "public"
features {}
subscription_id = var.azure-subscription-id
client_id = var.azure-client-id
client_secret = "${data.azurerm_key_vault_secret.azure-client-secret1.value}"
tenant_id = var.azure-tenant-id
}
I have another file kv-data.tf
data "azurerm_key_vault_secret" "azure-client-secret1" {
name = "azure-client-secret"
vault_uri = "https://kv23.vault.azure.net/"
}
But I get this error. What is the correct way to access keyvault secret?
│ Error: Cycle: data.azurerm_key_vault_secret.azure-client-secret1,
provider["registry.terraform.io/hashicorp/azurerm"]

It is not possible to do this. To access Keyvault you would need credentials which is not supplied. You will have to hardcode it like other vars.

Related

Where to save Azure app registration secrets

My questions is regarding Azure app registration secrets.
I have an app registration and its secrets (client_id, subscription_id, tenant_id and client_id)
I am able to provision the resources through terraform.
For the security purpose it is recommended to do not upload secrets to your git repo.
So my question is, where we can save these secrets so we can retrieve them at the runtime?
I have already saved them into Azure key vault and when I try to retrieve them in providers.tf I get an error
Cycle: data.azurerm_key_vault_secret.client-secret, provider["registry.terraform.io/hashicorp/azurerm"], data.azurerm_key_vault.my_key_vault
what am I doing wrong?
So finally I have found the solution on terraform's official website
First you have to set env variables in your .zprofile
export ARM_SUBSCRIPTION_ID=*******
export ARM_CLIENT_ID=*******
export ARM_CLIENT_SECRET=*******
export ARM_TENANT_ID=*******
Then you have to create a variables.tf file and then create variable blocks as
variable "subscription_id" {
}
variable "client_id" {
}
variable "client_secret" {
}
variable "tenant_id" {
}
and the last step is to access them in the providers.tf file
# Configuration options
provider "azurerm" {
subscription_id = var.subscription_id
client_id = var.client_id
client_secret = var.client_secret
tenant_id = var.tenant_id
features {
}
}

How to configure multiple azurerm providers authenticated via system-assigned managed identity using environment variables

I want to configure two azurerm providers using environment variables
I tried this:
variable "SUBSCRIPTION_ID" {
description = "Subscription ID where resources will be deployed."
}
variable "TENANT_ID" {
description = "Service Principal Tenant ID."
}
provider "azurerm" {
subscription_id = var.SUBSCRIPTION_ID
tenant_id = var.TENANT_ID
use_msi = true
features {}
}
#################################################################
# Tools provider
#################################################################
variable "TOOLS_SUBSCRIPTION_ID" {
description = "Subscription ID where Tools are located,"
}
variable "TOOLS_TENANT_ID" {
description = "Service Principal Tenant ID."
}
provider "azurerm" {
alias = "tools"
subscription_id = var.TOOLS_SUBSCRIPTION_ID
tenant_id = var.TOOLS_TENANT_ID
use_msi = true
features {}
}
With defined :
TF_VAR_SUBSCRIPTION_ID
TF_VAR_TENANT_ID
TF_VAR_TOOLS_SUBSCRIPTION_ID
TF_VAR_TOOLS_TENANT_ID
I checked and all values are present. However I got this error:
│ Error: building AzureRM Client: 1 error occurred:
│ * A Client ID must be configured when authenticating as a Service Principal using a Client Secret.
│
│
│
│ with provider["registry.terraform.io/hashicorp/azurerm"],
│ on providers.tf line 17, in provider "azurerm":
│ 17: provider "azurerm" {
│
╵
╷
│ Error: building AzureRM Client: 1 error occurred:
│ * A Client ID must be configured when authenticating as a Service Principal using a Client Secret.
│
│
│
│ with provider["registry.terraform.io/hashicorp/azurerm"].tools,
│ on providers.tf line 48, in provider "azurerm":
│ 48: provider "azurerm" {
│
The code was ran on Azure VM Scale set with assigned managed identity.
I made another test and I got the same error for single provider. It looks that something wrong is with passing variable via environment variable TF_VAR_name.
I use these versions:
Terraform v1.0.11
azurerm v2.98.0
The error indicates that the client_id argument for the provider has not been specified. When authenticating the AzureRM provider with service principal, you also need to specify a client_id, and then also either a secret or a certificate (unsure which you are targeting here).
provider "azurerm" {
subscription_id = var.SUBSCRIPTION_ID
tenant_id = var.TENANT_ID
client_id = var.CLIENT_ID
features {}
}
provider "azurerm" {
alias = "tools"
subscription_id = var.TOOLS_SUBSCRIPTION_ID
tenant_id = var.TOOLS_TENANT_ID
client_id = var.TOOLS_CLIENT_ID
features {}
}
This will resolve your issue, but you will also need to specify the client cert or secret as mentioned in the linked documentation above. Also, the use_msi argument is being ignored by the provider configuration, so the provider is understanding the authentication method as service principal instead of managed service identity.
Note also that for the default provider configuration, you can use native authentication environment variables like ARM_SUBSCRIPTION_ID instead of Terraform variables i.e. var.SUBSCRIPTION_ID.
I found that one of script set ARM_ACCESS_KEY and ARM_CLIENT_SECRET and becaue of this terrafrom considered this as Service Prinicpal authentication. Once I removed that part all works fine.

maintain terraform azure state file in one subscription and deploy to multiple cloud subscriptions

I need to store my terraform state file in a single azure storage account and deploy it to multiple cloud subscriptions(china and public cloud)..
I have my backend configured as below:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=2.78.0"
}
}
backend "azurerm" {
resource_group_name = "Terraform-rg"
storage_account_name = "terraformstate"
container_name = "tfstate"
subscription_id = "00000000-0000-0000-0000-000000000000"
key = "prod"
}
}
provider "azurerm" {
features {}
}
provider "azurerm" {
features {}
alias = "sub2"
subscription_id = "xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx"
client_id = "xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx"
client_secret = var.client_secret
tenant_id = "xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx"
}
However, when I am trying to terraform init with this approach, I am getting the below error:
Failed to get configured named states: Error retrieving keys for Storage Account "terraformstate": storage.AccountsClient#ListKeys: Failure responding to request: StatusCode=404 -- Original Error: autorest/azure: Service returned an error. Status=404 Code="SubscriptionNotFound" Message="The subscription 'xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx' could not be found."
I was wondering if it is even possible to do this?
I also have a script to terraform init and terraform plan which would switch the cloud based on env..
"az cloud set --name AzureChinaCloud" for china and for non china "az cloud set --name AzureCloud"
The storage account subscription is in AzureCloud.. How do I authorise to write the state file for AzureChinaCloud in AzureCloud?
Is this approach even possible?
As mentioned in the comment section, The issue in your code is you are missing Environment parameter in the provider block . As you were manually setting the cloud environment so, the code was not able to find the Subscription in the Backend Configuration which is in public cloud .
So, the solution will be setting the parameter in the code like below and not manually using az CLI :
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=2.78.0"
}
}
backend "azurerm" {
resource_group_name = "Terraform-rg"
storage_account_name = "terraformstate"
container_name = "tfstate"
subscription_id = "00000000-0000-0000-0000-000000000000"
key = "prod"
}
}
provider "azurerm" {
features {}
}
provider "azurerm" {
features {}
alias = "USGovernment"
subscription_id = "xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx"
client_id = "xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx"
client_secret = var.client_secret
tenant_id = "xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx"
environment = "usgovernment"
}
provider "azurerm" {
features {}
alias = "China"
subscription_id = "xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx"
client_id = "xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx"
client_secret = var.client_secret
tenant_id = "xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx"
environment = "china"
}
Reference:
Docs overview | hashicorp/azurerm | Terraform Registry
SO thread

SP renewal and update keyvault through terraform

I want to update the details of an expired SP through terraform. I can regenerate the SP by changing the expiration date for the SP. but the SP details are been stored in the keyvault. So while updating the keyvault with the same id/secret it errors out. Is there a way to update/delete the key_vault secret through terraform ?
resource "azurerm_key_vault_secret" "sp_arm_client_id"
{
name = "ARM-CLIENT-ID"
value = az_sp.app_id key_vault_id = data.azurerm_key_vault.storable_kvs[each.key].id
}
I tested your scenario in my environment and I was successfully able to do the changes and it got stored in current version and the previous one was in older version using the below code:
provider "azuread" {}
provider "azurerm" {
features{}
}
data "azuread_client_config" "current" {}
data "azuread_application" "appreg" {
display_name="ansumanterraformtest"
}
resource "azuread_application_password" "apppass" {
application_object_id = data.azuread_application.appreg.object_id
end_date_relative = "3h"
}
data "azurerm_key_vault" "kv" {
name = "kvname"
resource_group_name = "ansumantest"
}
resource "azurerm_key_vault_secret" "demo_sp_client_id" {
name = "demo-sp-client-id"
value = data.azuread_application.appreg.application_id
key_vault_id = data.azurerm_key_vault.kv.id
}
resource "azurerm_key_vault_secret" "demo_sp_client_secret" {
name = "demo-sp-client-secret"
value =azuread_application_password.apppass.value
key_vault_id = data.azurerm_key_vault.kv.id
}
Output:
Note: You might be getting the error if that secret in keyvault was not created from terraform . If it was created from portal or any other source then you have to first import that secret to terraform state and then change it so that the terraform can manage it .
Import command:
terraform import azurerm_key_vault_secret.example "https://example-keyvault.vault.azure.net/secrets/example/fdf067c93bbb4b22bff4d8b7a9a56217"
Reference:
azurerm_key_vault_secret | Resources | hashicorp/azurerm | Terraform Registry

How to make "terraform plan" use my config file

I created an Azure service principal
I created a file called azureProviderAndCreds.tf that looks similar to the following:
variable subscription_id {}
variable tenant_id {}
variable client_id {}
variable client_secret {}
provider "azurerm" {
subscription_id = "<my-azure-subscription-id>"
tenant_id = "<tenantid-returned-from-creating-a-service-principal>"
client_id = "<appid-returned-from-creating-a-service-principal>"
client_secret = "<password-returned-from-creating-a-service-principal>"
}
I ran terraform init
I ran terraform plan
When executing terraform plan, the command asks me for the client_id.
I have this value defined in the azureProviderAndCreds.tf file. How do I get Terraform to look at my config file for that info?
I'd read through the docs to get a handle of the input variables basics.
But heres a couple quick things:
You are declaring variables and not actually using them in your provider:
provider "azurerm" {
subscription_id = "${var.subscription_id}"
tenant_id = "${var.tenant_id}"
client_id = "${var.client_id}"
client_secret = "${client_secret}"
}
You could set defaults for your variables when declaring them:
variable subscription_id {
default = "your-subscription-id"
}
Of you could create a .tfvars file like variables.tfvars and pass that when running plan:
subscription_id = "your-subscription-id"
tenant_id = "your-tenant-id"
client_id = "your-client-id"
client_secret = "your-client-secret"
terraform plan -var-file=variables.tfvars

Resources