SP renewal and update keyvault through terraform - azure

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

Related

error deploying resources on azure using terraform cloud

I have deployed resources on Microsoft Azure using terraform. I'm using azure storage account container to save my terraform states. I tried to configure terraform cloud to automate the deployment but I get this error.
Error: A resource with the ID "/subscriptions/{SUBSCRIPTION_ID}/resourceGroups/msk-stage-keyvault" already exists - to be managed via Terraform this resource needs to be imported into the State. Please see the resource documentation for "azurerm_resource_group" for more information.
with module.keyvault.azurerm_resource_group.msk-keyvault
on ../../modules/az-keyvault/main.tf line 2, in resource "azurerm_resource_group" "msk-keyvault":
resource "azurerm_resource_group" "msk-keyvault" {
It seems that terraform cloud is not using my backend state in my provider.tf. How do I make terraform cloud use my backend state in provider.tf.
My Backend Provider
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=2.91.0"
}
}
backend "azurerm" {
resource_group_name = "msk-configurations"
storage_account_name = "mskconfigurations"
container_name = "key-vault"
key = "stage.tfstate"
}
}
provider "azurerm" {
features {}
subscription_id = var.subscription
tenant_id = var.ternant_id
}
It looks like your main.tf has already existing keyvault state.
So Initially please check if you have already configured keyvault resource in main.tf file or if you have already imported the state.
If its already present in main.tf file , and if you are again giving it in the backend , please try to remove the one from main.tf file and then execute again.
Also please note that terraform backend needs azure storage account credentials before hand in order to store into the tfstate.
So please avoid creating storage simultaneously all account, container and then the keyvault resource to tfstate.
So if storage account is already created first , then terraform can refer it later in backend.
To preconfigure the storage account and container :
Example:
1. Create storage account and container one after the other instead in the same file:
provider "azurerm" {
features {}
}
data "azurerm_resource_group" "example" {
name = "resourcegroupname"
}
resource "azurerm_storage_account" "example" {
name = "<yourstorageaccountname>"
resource_group_name = data.azurerm_resource_group.example.name
location = data.azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_storage_container" "example" {
name = "newterraformcont"
storage_account_name = azurerm_storage_account.example.name
container_access_type = "private"
}
Then create the msk-keyvault resource group and store the tfstate in container.
This is my already created state file in terraform (terraform.tf)
provider "azurerm" {
features {}
}
terraform {
# Configure Terraform State Storage
backend "azurerm" {
resource_group_name = "<resourcegroup>"
storage_account_name = "<storage-earliercreated>"
container_name = " newterraformcont "
key = "terraform.tfstate"
}
}
resource "azurerm_resource_group" " msk-keyvault" {
name = "<msk-keyvault>"
location = "west us"
}
Reference:
azurerm_resource_group | Resources | hashicorp/azurerm | Terraform
Registry
https://www.jorgebernhardt.com/terraform-backend

Add an AD Group as a member of already existing Enterprise Application with Terraform

Right now I am provisioning an AD Security Group just fine via Terraform with:
resource "azuread_group" "my_group" {
display_name = "Test_Group_Terraform"
owners = ["<hardcoded user>"]
security_enabled = true
}
I am trying to figure out how to assign this group to be a member of an already existing Enterprise Application.
According to https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/app_role_assignment#example-usage I should be using something like
resource "azuread_app_role_assignment" "example" {
app_role_id = azuread_service_principal.internal.app_role_ids["Admin.All"]
principal_object_id = azuread_group.example.object_id
resource_object_id = azuread_service_principal.internal.object_id
}
But how can I do so to an already existing Enterprise Application?
Already existing enterprise application /service principal which is previously created using UI in portal, can be used in terraform by first importing it to its terraform state .
Service principals can be imported using their object ID,
e.g.
First the resource must be specified in the root module
main.tf
resource "azuread_service_principal" "mynewappsv" {
#arguments
}
(also application in appregistration can be imported if needed before terraform import azuread_application.mynewapp <objId>)
And then run the terraform import with the apps service principal object id something like below
>terraform import azuread_service_principal.test <objectId here>
Executed:
Then to see or print out the TF state run > terraform show where you can see all the state files present. You can copy the content of azuread serviceprincipal if required to the actual block in .tf file.
Then you can use the resource in the terraform to assign a group to
the service principal.
main.tf (Reference: azuread_app_role_assignment | Resources | hashicorp/azuread | Terraform Registry )
provider "azurerm" {
features {}
}
data "azurerm_resource_group" "example" {
name = "xxxxxxxxx"
}
data "azuread_client_config" "current" {}
resource "azuread_application" "mynewapp" {
display_name = "mynewapp"
owners = [data.azuread_client_config.current.object_id]
}
resource "azuread_service_principal" "mynewapp" {
application_id = azuread_application.mynewapp.application_id
app_role_assignment_required = true
owners = [data.azuread_client_config.current.object_id]
}
resource "azuread_group" "example" {
display_name = "example"
security_enabled = true
}
#Assign a user and group to an internal application
resource "azuread_app_role_assignment" "example" {
app_role_id = azuread_service_principal.internal.app_role_ids["Admin.All"]
principal_object_id = azuread_group.example.object_id
resource_object_id = azuread_service_principal.mynewapp.object_id
}
Reference: https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/service_principal

Terraform does not wait for update of azurerm_key_vault_secret.xyz.id

We are using terraform to build my azure resources with azurerm provider.
We are injecting a secret during the terraform run and this secret may change from time to time.
We use a azurerm_key_vault_secret to store the secret and a function app with managed identity (that has got reading access to the key vault) that receives the secret like this:
resource "azurerm_key_vault_secret" "my_secret" {
name = "my-secret"
value = var.my_secret
key_vault_id = azurerm_key_vault.default.id
}
resource "azurerm_function_app" "app" {
name = "..."
app_settings = {
MySecret = "#Microsoft.KeyVault(SecretUri=${azurerm_key_vault_secret.my_secret.id})"
}
identity {
type = "SystemAssigned"
}
...
}
When i run terraform apply and the secret is changed, the function app points to the old version of the secret. It seems the azurerm_key_vault_secret.my_secret.id is being read before the secret was updated.
Does anybody have any idea, how I can make sure the function_app will wait for the update of the secret?
(And yes, the id changes and I also don't like it, but that is how the provider works.)
When you are updating a key vault secret then the change is handled by Key vault UI . So Terraform won't detect the changes on azurerm_key_vault_secret.example.id and thus the reference's also won't be modified .
As a Workaround , You can use a data source for the same key vault secret and provide it in the function-app as shown in the below code , so that all the changes done in key vault secret can be read from data source and the changes can be applied accordingly :
resource "azurerm_key_vault_secret" "example" {
name = "functionappsecret"
value = "changedpassword"
key_vault_id = azurerm_key_vault.example.id
}
data "azurerm_key_vault_secret" "secret" {
name="functionappsecret"
key_vault_id = azurerm_key_vault.example.id
depends_on = [
azurerm_key_vault_secret.example
]
}
resource "azurerm_function_app" "example" {
name = "ansuman-azure-functions"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
app_settings = {
MySecret = "#Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.secret.id})"
}
identity {
type="SystemAssigned"
}
}
Ouptut:

How to add keyvault access policies after importing keyvault into terraform

My terraform design depends on a pre-provisioned keyvault containing secrets to be used by app services. I imported this key vault into my remote state. I can see it has been imported. Now when I run terraform plan, it acts as if it does not know about the imported resource.
This is how my terraform looks like
provider "azurerm" {
version="=2.20.0"
skip_provider_registration="true"
features{}
}
terraform {
backend "azurerm" {}
}
resource "azurerm_key_vault" "kv" {
name = "${var.env}ActicoDQM-kv"
}
module "app_service_plan"{
source = "./modules/app-service-plan"
...redacted for brevity
tags = var.tags
}
module "app-service"{
source = "./modules/app-service"
...redacted for brevity
tags = var.tags
key_vault_id = azurerm_key_vault.kv.key_vault_id
}
Adding an access policy for the app service inside the module
resource "azurerm_app_service" "app" {
... redacted for brevity
}
identity {
type = "SystemAssigned"
}
}
resource "azurerm_key_vault_access_policy" "app" {
key_vault_id = var.key_vault_id
tenant_id = azurerm_app_service.app.identity[0].tenant_id
object_id = azurerm_app_service.app.identity[0].principal_id
secret_permissions = ["get", "list"]
}
There seems to be some missing link in my understanding, because now when I do
terraform plan
It acts as if it doesn't know about imported keyvault
Error: Missing required argument
on main.tf line 19, in resource "azurerm_key_vault" "kv":
19: resource "azurerm_key_vault" "kv" {
The argument "tenant_id" is required, but no definition was found.
Even though you're importing an existing keyvault into your terraform state you need to fully define all required arguments according to keyvault resource docs.
At minimum your keyvault resource should specify these arguments:
resource "azurerm_key_vault" "kv" {
name = "${var.env}ActicoDQM-kv"
location = ..
resource_group_name = ..
sku_name = "standard" or "premium"
tenant_id = data.azurerm_client_config.current.tenant_id
}
You can expose the tenant_id using a data resource:
data "azurerm_client_config" "current" {
}

Moving Certificate from Keyvault to another Keyvault in a diffrent subscription

I am trying to find some way of moving my certificates from a Key Vault in one Azure Subscription to another Azure subscription. Is there anyway of doing this>
Find below an approach to move a self-signed certification created in Azure Key Vault assuming it is already created.
--- Download PFX ---
First, go to the Azure Portal and navigate to the Key Vault that holds the certificate that needs to be moved. Then, select the certificate, the desired version and click Download in PFX/PEM format.
--- Import PFX ---
Now, go to the Key Vault in the destination subscription, Certificates, click +Generate/Import and import the PFX file downloaded in the previous step.
If you need to automate this process, the following article provides good examples related to your question:
https://blogs.technet.microsoft.com/kv/2016/09/26/get-started-with-azure-key-vault-certificates/
I eventually used terraform to achieve this. I referenced the certificates from the azure keyvault secret resource and created new certificates.
the sample code here.
terraform {
required_version = ">= 0.13"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=3.17.0"
}
}
}
provider "azurerm" {
features {}
}
locals {
certificates = [
"certificate_name_1",
"certificate_name_2",
"certificate_name_3",
"certificate_name_4",
"certificate_name_5",
"certificate_name_6"
]
}
data "azurerm_key_vault" "old" {
name = "old_keyvault_name"
resource_group_name = "old_keyvault_resource_group"
}
data "azurerm_key_vault" "new" {
name = "new_keyvault_name"
resource_group_name = "new_keyvault_resource_group"
}
data "azurerm_key_vault_secret" "secrets" {
for_each = toset(local.certificates)
name = each.value
key_vault_id = data.azurerm_key_vault.old.id
}
resource "azurerm_key_vault_certificate" "secrets" {
for_each = data.azurerm_key_vault_secret.secrets
name = each.value.name
key_vault_id = data.azurerm_key_vault.new.id
certificate {
contents = each.value.value
}
}
wrote a post here as well

Resources