terraform plan not working with azurerm provider - azure

I want to create a resource group in the azure cloud using terraform, for which I have to configure azurerm provider.
I created SPN using cli.
# az ad sp create-for-rbac --name spn_devops_terraform --role="Contributor" --scopes="/subscriptions/XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX"
The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli
{
"appId": "YYYYYY-YYYY-YYYY-YYYY-YYYYYYYYY",
"displayName": "spn_devops_terraform",
"password": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"tenant": "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX"
}
To test my SPN spn_devops_terraform, I logged in via cli
az login --service-principal -u YYYYYY-YYYY-YYYY-YYYY-YYYYYYYYY -p XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX --tenant XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX
then executed
az vm list --output table
And i can see the list of all the VMS.
Now here is my main.tf file
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "3.0.2"
}
}
}
provider "azurerm" {
features {}
subscription_id = "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX" # copy pasted this from portal.
client_id = "YYYYYY-YYYY-YYYY-YYYY-YYYYYYYYY" # this is app_id
client_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" # password
tenant_id = "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX" # tenant
}
I initialized the terraform with "terraform init" command which goes fine.
But when i execute terraform plan it just hung for 10 mins and i have to press CTRL + C to stop it.
Please wait for Terraform to exit or data loss may occur.
Gracefully shutting down...
Stopping operation...
╷
│ Error: Unable to list provider registration status, it is possible that this is due to invalid credentials or the service principal does not have permission to use the Resource Manager API, Azure error: resources.ProvidersClient#List: Failure sending request: StatusCode=0 -- Original Error: context canceled
│
│ with provider["registry.terraform.io/hashicorp/azurerm"],
│ on main.tf line 10, in provider "azurerm":
│ 10: provider "azurerm" {
│
╵
What i am going wrong? what is fix and if there is any command in CLI or GUI in portal where i can see what is happening?

Tested in my enviromemt getting the same kind of error.It looks like the Service Principal doesn't have the Contributor role assigned to it/Doesn't have access to the subscription.
You can define the scope of service principle while creating it.
$ az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/SUBSCRIPTION_ID"
OR
Just go to the Subscription in the portal, select Access Control (IAM) and Add the Role assignment, Contributor to your Service Principal
You can refer this Terraform Document to Authenticating using a Service Principal with a Client Secret
Reference : Terraform unable to list provider registration status

Related

Terraform vm deployment using shared galery issue

I'm implementing a Terraform template, that deploys an Azure VM, based on a custom image that resides on another tenant. I've provided permissions to an AppRegistration, and validated that using Az CLI I can deploy a VMSS referring to that same shared image.
However, if I use Terraform to deploy the VM, I get this error:
Error: compute.VirtualMachinesClient#CreateOrUpdate: Failure sending request: StatusCode=403 -- Original Error: Code="LinkedAuthorizationFailed" Message="The client has permission to perform action 'Microsoft.Compute/galleries/images/versions/read' on scope '/subscriptions//resourceGroups/RG-Images/providers/Microsoft.Compute/virtualMachines/VM1', however the current tenant '' is not authorized to access linked subscription '***'."
Terraform is using the AppRegistration that was created. however, it fails with that error
I've followed this how-to, successfully, that usees Az cli.
https://learn.microsoft.com/en-us/azure/virtual-machine-scale-sets/share-images-across-tenants
I understand by the error message, that the user has the permissions, but the issue is between the 2 tenants, is that it? What else can I do to fix this?
Initially please check with the RBAC permissions on the two tenants like Virtual machine contributor or Network Contributor role .
This issue with cross tenant may be even fixed in terraform azurerm
provider version 1.34.0 or later
provider "azurerm" {
version = "~> 1.34.0"
}
And you can make use of auxiliary_tenant_ids = ["<tenant2 Id>"] to mention both the tenants while using shared image gallery .See shared image gallery /terraform/github.com by #rajaie-algorithmia
provider "azurerm" {
subscription_id = "${var.subscription_id}"
client_id = "${var.client_id}"
client_secret = "${var.client_secret}"
tenant_id = "${var.tenant_id}"
auxiliary_tenant_ids = ["${var.sig_tenant_id}"] #give the other tenant Id here
}
References:
share-images-across-tenants | microsoft docs
azure portal : how-to-share-gallery-vm-images-across-azure-tenants |Ajay varma| axiom

Azure AD Group- Authorization_RequestDenied - Insufficient privileges to complete the operation

I’m trying to create the Azure AD Group using the following terraform code through the Azure DevOps.
# Create Azure AD Group in Active Directory for AKS Admins
resource "azuread_group" "aks_administrators" {
#name = "${azurerm_resource_group.aks_rg.name}-administrators"
display_name = "${azurerm_resource_group.aks_rg.name}-${var.environment}-administrators"
description = "Azure AKS Kubernetes administrators for the ${azurerm_resource_group.aks_rg.name}-${var.environment} cluster."
security_enabled = true
}
I have followed these steps to provide the permission to create Azure AD Groups through the Azure DevOps ARM service connection (Service Principle).
• Provide permission for Service connection created in previous step to create Azure AD Groups
• Go to -> Azure DevOps -> Select Organization -> Select project terraform-azure-aks
• Go to Project Settings -> Pipelines -> Service Connections
• Open terraform-aks-azurerm-svc-con
• Click on Manage Service Principal, new tab will be opened
• Click on View API Permissions
• Click on Add Permission
• Select an API: Microsoft APIs
• Commonly used Microsoft APIs: Supported legacy APIs: Azure Active Directory Graph-DEPRECATING Use Microsoft Graph
• Click on Application Permissions
• Check Directory.ReadWrite.All and click on Add Permission
• Click on Grant Admin consent for Default Directory
But I’m getting the following error:
Error: Creating group "xxxxxxxxxx-administrators"
│
│ with azuread_group.aks_administrators,
│ on 06-aks-administrators-azure-ad.tf line 2, in resource "azuread_group" "aks_administrators":
│ 2: resource "azuread_group" "aks_administrators" {
│
│ graphrbac.GroupsClient#Create: Failure responding to request:
│ StatusCode=403 -- Original Error: autorest/azure: Service returned an
│ error. Status=403 Code="Unknown" Message="Unknown service error"
│ Details=[{"odata.error":{"code":"Authorization_RequestDenied","date":"2022-01-25T04:06:31","message":{"lang":"en","value":"Insufficient
│ privileges to complete the
│ operation."}}}]
Please check the Microsoft Graph permission Directory.ReadWrite.All has been provided to the service connection and it has been granted the admin consent.
I tested the same in my environment where I gave the permission to my service principal but didn't grant admin consent like below :
When deploying the below code, it gave me error :
provider "azuread" {}
# Create Azure AD Group in Active Directory for AKS Admins
resource "azuread_group" "aks_administrators" {
#name = "ans-aks-administrators"
display_name = "ans-aks-test-administrators"
description = "Azure AKS Kubernetes administrators for the ans-aks-test cluster."
security_enabled = true
}
After granting the permission admin consent it gets resolved :
If the issue still occurs then please add a new secret for the service connection service principal and use the below code :
provider "azuread" {
client_id = "ClientID of the service principal"
client_secret = "ClientSecret"
tenant_id = "<TenantID>"
}
# Create Azure AD Group in Active Directory for AKS Admins
resource "azuread_group" "aks_administrators" {
#name = "ans-aks-administrators"
display_name = "ans-aks-test-administrators"
description = "Azure AKS Kubernetes administrators for the ans-aks-test cluster."
security_enabled = true
}

Azure DevOps Release - terraform import fails with 'Authenticate using a Service Principal'

I have a project that is running on Azure DevOps that requires creating a KeyVault and giving a series of managed AppService identities access to secrets in that vault.
Because of Terraform not being able to give its own service connection access to the key vault(this is a bug of some kind), I am forced to create ResourceGroup and Keyvault with SP access before Terraforming.
When running terraform import on resourcegroup and Keyvault through a PowerShell task:
terraform init
$state = terraform state list
if ($state -like '*azurerm_resource_group.instancerg*' -and '*azurerm_key_vault.instancekeyvault*') {
Write-Host "Resources have already been imported!"
}
else {
terraform import azurerm_resource_group.instancerg /subscriptions/$(subscriptionid)/resourceGroups/rgname
terraform import azurerm_key_vault.instancekeyvault /subscriptions/$(subscriptionid)/resourceGroups/rgname/providers/Microsoft.KeyVault/vaults/keyvaultname
}
Failure happens on terraform import commands:
'Authenticate using a Service Principal' To authenticate to Azure
using a Service Principal, you can use the separate auth method -
instructions for which can be found here:'
My main.tf contains:
provider "azurerm" {
version = "=2.7.0"
subscription_id = var.subscriptionid
client_id = var.devopsserviceconnectionaid
client_secret = var.devopsserviceconnectionpw
tenant_id = var.tennantid
features {}
}
The variables are all linked to the proper credentials.
From what I understand Terraform should pick up on what authentication method that is being used based on the credentials that are in the block above or specific env variables (that are also present...) but somehow Terraform still thinks I'm trying to auth through Azure Cli and not Service principal.
You can use manage identities in keyvault in terraform as shown below.
object_id = azurerm_app_service.app.identity.0.principal_id
Web app is as below creating managed identity
KV as below
The order should be create web app with managed identity, then the KV then the KV access policy.
For authenticate with Azure pipelines service connection below works fine but you need to pass the arguments via the pipeline.
for further information check this blog here
Full PowerShell based implementation calling terraform with Azure DevOps pipelines is explained here. This implementation prevents any azure resources as prerequisite before terraforming. Only prerequisite is creating the SPN to enable authentication and authorization.

Terraform - Azure as a provider and limited access account

I want to deploy some resources on Azure with Terraform.
On Azure, I have an account with "Owner rights" on one Resource Group only(RGName). Not at the subscription level.
From my linux server, I installed "az cli" and I did "az login". At this step, everything is OK.
The problem appears when I want to execute terraform to create one resource.
Content of provider.tf (the only one .tf file for now) :
provider "azurerm" {
}
If I do a "terraform plan", it works.
If I add the following line, it fails. Please see the error at the end :
resource "azurerm_virtual_network" "myterraformnetwork" {
name = "myVnet"
address_space = ["10.0.0.0/16"]
location = "eastus"
resource_group_name = "RGName"
tags = {
environment = "Terraform Demo"
}
}
I do not have right on subscription level but I do not need to.
With the Azure WebUI I can create resource on this Resource Group without problem.
The error :
Error: Error ensuring Resource Providers are registered: Cannot register provider Microsoft.DevSpaces with Azure Resource Manager: resources.ProvidersClient#Register: Failure responding to request: StatusCode=403 -- Original Error: autor
est/azure: Service returned an error. Status=403 Code="AuthorizationFailed" Message="The client 'accountName' with object id 'IDaccountName' does not have authorization to perform action 'Microsoft.DevSpaces/r
egister/action' over scope '/subscriptions/subscriptionID' or the scope is invalid. If access was recently granted, please refresh your credentials.".
on provider.tf line 1, in provider "azurerm":
1: provider "azurerm" {
Thank you all !
If anyone else has this issue in a corporate (restricted) Azure environment, and doesn't have the patience to register the provider (which may not be necessary if you don't use the specified terraform resource) - have a look at https://github.com/terraform-providers/terraform-provider-azurerm/issues/4440
Specifically, this may help:
provider "azurerm" {
skip_provider_registration = "true"
It obviously won't help if you actually need the resource that fails to get registered (in our case it was Cannot register provider Microsoft.DevSpaces with Azure Resource Manager, but the resource will be variable depending on your environment and what Terraform decides to support)
For your issue, when you have the Owner role of the resource group, you can create new resources or manage the existing resources as you want. So permission is no problem. With the test on my side, it works well using a user has the Owner role of the resource group.
As the error shows, I think the possible reason is that you have multiple subscriptions in the tenant and the current subscription is not the right one which the user has the right permission. You can try to take a check and set the right subscription via the command:
az account set --subscription subscription_id
Thank you for your answer.
I got this when I execute "az account list" :
"cloudName": "AzureCloud",
"id": "***********0d43",
"isDefault": true,
"name": "BU*******",
"state": "Enabled",
"tenantId": "TENANTID",
"user": {
"name": "LOGINNAME",
"type": "user"
I do not have rights on this subscription but it is the only one that I know.
On Azure WebUI I can see that the RGName is on the same subscription.
This is a capture from Azure WebUI on the RGName :
Azure WebUI
Thank you
You may need to register the Resource provider by clicking on register as shown in below screenshot under subscription id.

Having the Terraform azure state file under different subscription

I have two subscriptions in Azure. Let's call them sub-dev and sub-prod. Under sub-dev I have resources for development (in a resource group rg-dev) and under sub-prod resources for production (in a resource group rg-prod).
Now, I would like to have only one state-file for both dev and prod. I can do this as I am using Terraform workspaces (dev and prod). There is a Storage Account under sub-dev (rg-dev) named tfsate. It has a container etc. The Azure backend is configured like this:
terraform {
backend "azurerm" {
resource_group_name = "rg-dev"
storage_account_name = "tfstate"
container_name = "tfcontainer"
key = "terraform.tfstate"
}
}
If I want to apply to the dev environment I have to switch Az Cli to the sub-dev. Similarly, for production, I would have to use sub-prod. I switch the default subscription with az cli:
az account set -s sub-prod
Problem is that the state's storage account is under sub-dev and not sub-prod. I will get access errors when trying to terraform init (or apply) when the default subscription is set to sub-prod.
Error: Failed to get existing workspaces: Error retrieving keys for Storage Account "tfstate": storage.AccountsClient#ListKeys: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="AuthorizationFailed" Message="The client 'user#example.com' with object id '<redacted>' does not have authorization to perform action 'Microsoft.Storage/storageAccounts/listKeys/action' over scope '/subscriptions/sub-prod/resourceGroups/rg-dev/providers/Microsoft.Storage/storageAccounts/tfstate' or the scope is invalid. If access was recently granted, please refresh your credentials."
I have tried couple of things:
I added subscription_id = "sub-dev"
I generated a SAS token for the tfstate storage account and added the sas_token config value (removed resource_group_name)
but in vain and getting the same error.
I tried to az logout but terraform requires me to login first. Do I have to tune the permissions in the Azure end somehow (this is hard as the Azure environment is configured by a 3rd party) or does Terraform support this kind of having your state file under different subscription setup at all?
For better or worse (I haven't experimented much with other methods of organising terraform) we use terraform in the exact way you are describing. A state file, in a remote backend, in a different subscription to my resources. Workspaces are created to handle environments for the deployment.
Our state files are specified like this:
terraform {
required_version = ">= 0.12.6"
backend "azurerm" {
subscription_id = "<subscription GUID storage account is in>"
resource_group_name = "terraform-rg"
storage_account_name = "myterraform"
container_name = "tfstate"
key = "root.terraform.tfstate"
}
}
We keep our terraform storage account in a completely different subscription to our deployments but this isn't necessary.
When configuring your state file like so, it authenticates to the remote backend via az CLI, using the context of the person interacting with the CLI. This person needs to have the "Reader & Data Access" role to the storage account in order to dynamically retrieve the storage account keys at runtime.
With the above state file configured, executing Terraform would be
az login
az account set -s "<name of subscription where you want to create resources>"
terraform init
terraform plan
terraform apply
There's another way to do that. You can use the Access Key associated with the Storage Account on the other subscription(the one you want to have the state files on) and export it as an environment variable.
Bash:
export ARM_ACCESS_KEY=$(az storage account keys list --resource-group $RESOURCE_GROUP_NAME --account-name $STORAGE_ACCOUNT_NAME --query '[0].value' -o tsv)
Powershell:
$env:ARM_ACCESS_KEY=$(az storage account keys list --resource-group $RESOURCE_GROUP_NAME --account-name $STORAGE_ACCOUNT_NAME --query '[0].value' -o tsv)
Then switch to the subscription you want to deploy to and deploy.

Resources