How to create a Client Secret using Terraform? - azure

I am trying to create a Client_secret for My service principal using the below code :
data "azuread_service_principal" "existing_SP" {
display_name = "TestAppRegistration"
}
resource "azuread_service_principal_password" "Client_Secret" {
service_principal_id = data.azuread_service_principal.existing_SP.object_id
}
Doing a terraform-apply it get successfully created but I don't see it in the Secrets and certificates section of the app registration:
But when I check the tfstate , it shows the value there created for the service principal but the object Id is same as the enterprise application present for the same app registration:
So, My question:
How can I create a client secret using terraform, is there something I am doing wrong ?
If I am doing correct then where is the secret generated can be found in portal?

How can I create a client secret using terraform, is there something I
am doing wrong ?
Yes , You are doing everything correctly.
But to clear the confusion here , as you may already know there are 2 types of azure ad application i.e. app registrations and enterprise application. In terraform or powershell or cli the App Registration is know as Azure AD application and the Enterprise Application for the same app registration is know as Service Principal. So , if you have created from Portal by going to app registration blade , then bydefault a service principal is created for it , but its not the same if you create a app registration from Powershell or Terraform.
And By default you will be not be able to see the secret or certificate created for service principal from portal but you will be defintely able to use it with the client-id for authentication purpose .
For example :
I tested this on my environment using your code and I took the value of password present in tfstate file and used it to do az login:
Note: Its safe to use terraform for creating a service principal password as it will be stored in the tfstate file so, you won't face difficulty in searching for it .
If I am doing correct then where is the secret generated can be found
in portal?
But if you are trying to look for the secret from portal , then I will suggest you to use azuread_application:
data "azuread_application" "example" {
display_name = "postman"
}
resource "azuread_application_password" "example" {
display_name = "terraformgenerated"
application_object_id = data.azuread_application.example.object_id
}

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

how to add Identity provider to app service by bicep script?

I need to create app registration and then add it as Identity provider to app service programmatically (by bicep).
It's possible to create app registration using Deployment Scripts.
But how I can add it to app service?
For creating app service we use Microsoft.Web sites 2020-12-01.
But I don't see any property for Identity provider.
We have property identity, but it's for ManagedServiceIdentity.
Maybe Microsoft.Web sites/config 'authsettings'?
But:
The sites/config resource type can be deployed to: Resource groups.
So, question is: is it possible to add Identity provider by bicep or I should do it manually?
You can use authsettingsV2. Full documentation can be found here.
param webappname string
resource webapp 'Microsoft.Web/sites#2022-03-01' existing = {
name:webappname
}
resource authsettings 'Microsoft.Web/sites/config#2022-03-01' = {
parent: webapp
name: 'authsettingsV2'
properties:{
...
}
}
You can also refer to a similar post: ARM template for Azure Function with V2 Authentication.

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.

create an azure resource group under a subscription with terraform

I am looking at this example from the terraform docs for creating an azure group:
resource "azurerm_resource_group" "test" {
name = "testResourceGroup1"
location = "West US"
tags = {
environment = "Production"
}
}
It does not specify the subscription anywhere.
How can I specify the subscription?
For your issue, you know the Terraform deploy the Azure resources through the Azure CLI. And there are four ways to authenticate.
Authenticating to Azure using the Azure CLI
Authenticating to Azure using Managed Service Identity
Authenticating to Azure using a Service Principal and a Client Certificate
Authenticating to Azure using a Service Principal and a Client Secret
If you do not set the tenant Id and subscription Id in the Terraform code, then you must use the first method in default. And you authenticate via the Azure CLI with the account that you log in the Azure CLI. So which subscription you set in the CLI then you use it for your Terraform.
But as the Terraform recommend:
We recommend using either a Service Principal or Managed Service
Identity when running Terraform non-interactively (such as when
running Terraform in a CI server) - and authenticating using the Azure
CLI when running Terraform locally.
So that you could grant the more appropriate permission for the service principal as you want.
Subscription is set when you configure Terraform to log in to Azure. The recommended way is to use an Azure AD service principal and environment variables.
To configure Terraform to use your Azure AD service principal, set the following environment variables, which are then used by the Azure Terraform modules. You can also set the environment if working with an Azure cloud other than Azure public.
ARM_SUBSCRIPTION_ID
ARM_CLIENT_ID
ARM_CLIENT_SECRET
ARM_TENANT_ID
ARM_ENVIRONMENT
Reference

How do I register my application locally created with one I created in Azure Active Directory?

I am following directions here for learning the AzureKeyVault config settings
Key Vault Configuration Provider sample application (ASP.NET Core 2.x)
This sample illustrates the use of the Azure Key Vault Configuration
Provider for ASP.NET Core 2.x. For the ASP.NET Core 1.x sample, see
Key Vault Configuration Provider sample application (ASP.NET Core
1.x).
For more information on how the sample works, see the Azure Key Vault
configuration provider topic.
Using the sample
Create a key vault and set up Azure Active Directory (Azure AD) for the application following the guidance in Get started with Azure Key
Vault.
Add secrets to the key vault using the AzureRM Key Vault PowerShell Module available from the
PowerShell
Gallery,
the Azure Key Vault REST API, or the Azure
Portal. Secrets are created as either
Manual or Certificate secrets. Certificate secrets are certificates for use by apps and services but are not supported by the
configuration provider. You should use the Manual option to create
name-value pair secrets for use with the configuration provider.
Simple secrets are created as name-value pairs. Azure Key Vault secret names are limited to alphanumeric characters and dashes.
Hierarchical values (configuration sections) use -- (two dashes) as a separator in the sample. Colons, which are normally used
to delimit a section from a subkey in ASP.NET Core
configuration, aren't allowed
in secret names. Therefore, two dashes are used and swapped for a
colon when the secrets are loaded into the app's configuration.
Create two Manual secrets with the following name-value pairs. The first secret is a simple name and value, and the second
secret creates a secret value with a section and subkey in the secret
name:
SecretName: secret_value_1
Section--SecretName: secret_value_2
Register the sample app with Azure Active Directory.
Authorize the app to
access the key vault. When you use the
Set-AzureRmKeyVaultAccessPolicy PowerShell cmdlet to authorize the
app to access the key vault, provide List and Get access to
secrets with -PermissionsToSecrets list,get.
Update the app's appsettings.json file with the values of Vault, ClientId, and ClientSecret.
Run the sample app, which obtains its configuration values from IConfigurationRoot with the same name as the secret name. *
Non-hierarchical values: The value for SecretName is obtained with
config["SecretName"]. * Hierarchical values (sections): Use :
(colon) notation or the GetSection extension method. Use either of
these approaches to obtain the configuration value:
config["Section:SecretName"]
config.GetSection("Section")["SecretName"]
Okay so I have copied the name of my application into Azure Active Directory as an 'Enterprise Application'. And I have added 'Access policies' for 'get' and 'list' in Azure for my ADD object I just created. Yet I get this error in the program when attempting to start the application:
Exception: {"error":"unauthorized_client","error_description":"AADSTS70001:
Application with identifier '(guid)' was not found in the directory ...(continues)
Update 8-4-18
Okay I found out that Azure uses the 'ClientId' and 'ClientSecret' in the local appsettings.json to connect to what Azure registers in this tutorial: https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal#log-in-as-the-application
I get the clientId in appsettings.json from the applicationId on ADD I create with ADD>App Registrations>New
I click settings in ADD on the app I just created and create a key with an expiration to store as ClientSecret in appsettings.json.
I change my 'Vault' in appsettings to my named vault.
I run the powershell above to give access or else do it in ADD.
So now I am getting a simpler error:
'Microsoft.Azure.KeyVault.Models.KeyVaultErrorException: 'Access denied''
I have tried running as Administrator in Visual Studio. I went under Subscriptions in Azure>Access Control>(IAM)>set my new apps to Reader.
So the reason your powershell is failing is because you are trying to assign a User Principal - a user - when actually you want a Service Principal.
I can’t see your C# to support more there than saying when you use the SDK to log in as the Service Principal you use the application id of the Application/Service Principal (its the same id).
The service principal acts like a user in the local directory but you log in as the application.
Edit:
I looked at the example you posted and ran it myself and had very similar problems. However I have got it working. Here's the steps:
Creating the Application
Create the Registered Application. I do this through the Azure Portal so
a Service Principal is created automatically. Make a note of the ApplicationId.
Generate a key credential on the created application and make a note of it.
In the Application click on the link to the Managed app in local directory. This is the Service Principal, make a note of the ObjectId
Creating the Key Vault
Create KeyVault - I used PowerShell to do this. New-AzureRmKeyVault
Apply the Service Principal to the Key Vault.
Set-AzureRmKeyVaultAccessPolicy -VaultName <vault> -ResourceGroupName <ResourceGroupName> -ObjectId <Object Id of the Created Service Principal> -PermissionsToSecrets Get,List
Running the Sample App
In your application settings follow this format:
{
"Vault": <the name of your vault>,
"ClientId": <ApplicationId of the Registered Application>,
"ClientSecret": <Credential generated from the Registered Application>
}
This worked for me and allowed me to run the sample and retrieve the secrets from the vault.
The ultimate problem for me became that running 'Set-AzureRmKeyVaultAccessPolicy' was not needed and for whatever reason it was easier to just ignore it and follow this subsection: https://azure.microsoft.com/documentation/articles/key-vault-get-started/#authorize
I kept trying to set up Object Id and Keys and really I had just overlooked a section mentioning a 'ServerPrincipalName'
They set one commandlet for keys
Set-AzureRmKeyVaultAccessPolicy -VaultName '<vaultName>' -ServicePrincipalName <ApplicationIdGuid> -PermissionsToKeys decrypt,sign
They set one commandlet for secrets
Set-AzureRmKeyVaultAccessPolicy -VaultName '<vaultName>' -ServicePrincipalName <ApplicationIdGuid> -PermissionsToSecrets Get, List
But I decided to follow the immediate proceeding section on doing it all in the Portal. The key take away for me was that the instructions were not wrong. Just vague when it says: "Register a sample app" then "Authorize the App". Really they should be saying
Register a sample app (https://learn.microsoft.com/en-us/azure/key-vault/key-vault-get-started#register)
Authorize the app with Key Vault (https://azure.microsoft.com/documentation/articles/key-vault-get-started/#authorize)
Ultimately all the information is there it was just confusing if you happen to already have a vault and an application and don't understand the prerequisite is that really you need to have a 1. A Vault, 2. An ADD Web Application, 3. Associate permissions for 2 in 1.

Resources