Terraform Azure Service Principal Client Secret expiration - azure

Is it really not possible to set the expiration date for a client secret?
I tried looking at the docs (see below), and I can't find anything other than the output of the expiration Terraform which is two years.
I can't even view the secret on Azure AD since it doesn't show up in the Client Secrets area (though this might be due to some sort of replication/eventual consistency lag).
https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/service_principal_password

Service Principal Password cannot be seen in the Portal, you can only find the value of it from the Terraform state. As Service Principal is referred to Enterprise Application , we can use the secret with the client id but it won't be visible in portal as Enterprise application doesn't have a certificates and secrets blade.
So, in order to make it visible in portal you have to use Application Password so that it can be seen in the certificates and secrets blade of the App Registration.
Also in the Application Password you can use relative end date in hours corresponding to the time you want the secret to expire.
You can use something like below:
provider "azuread" {}
data "azuread_application" "example" {
display_name = "aksspansuman"
}
resource "azuread_application_password" "example" {
display_name = "Test"
application_object_id = data.azuread_application.example.object_id
end_date_relative = "24h"
}
Output:
Update:
resource "azuread_service_principal_password" "example" {
service_principal_id = data.azuread_service_principal.example.object_id
end_date = "2021-11-18T01:02:03Z"
}
If We try using end_date in SP password it gives the below error.

Related

Terraform authenticating to azure by service principal and client secret

Whenever I run terraform plan command I have to put client id, secret id, tenant id and subscription id manually.
Here is my setup
I have set env variables in my .zprofile
export ARM_SUBSCRIPTION_ID=*********
export ARM_CLIENT_ID=*********
export ARM_CLIENT_SECRET=*********
export ARM_TENANT_ID=*********
if I want to see them echo $ARM_SUBSCRIPTION_ID it does print out its value
In my providers.tf file this is the code
# 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 {
}
}
And in my variables.tf file the code looks like this
variable "SUBSCRIPTION_ID" {
}
variable "CLIENT_ID" {
}
variable "CLIENT_SECRET" {
}
variable "TENANT_ID" {
}
so when I run terraform plan commands the terminal prompts me to put all ids manually.
Authenticating to azure by service principal and client secret using terraform:
I tried to authenticate with AzureAD service principal in my environment after finding a workaround and was able to perform it successfully.
I've setup env variables in azCLI as shown here:
export ARM_SUBSCRIPTION_ID="<subscription_id>"
export ARM_CLIENT_ID="<client_id>"
export ARM_TENANT_ID="<tenant_id>"
export ARM_CLIENT_SECRET="<client_secret>"
To authenticate service principal, we need to give some role permissions and API Permissions as well.
Required Permissions to enable:
Goto Roles and Administrators under Azure Active Directory through portal. There are certain administrator positions that come with default configuration. Actively enable the roles of "Application Administrator, Global Administrator, and User Administrator".
and
Goto API permissions under registered App registration and add application permissions for microsoft graph as its the main source to authenticate to Portal and enable below given permissions by clicking on Add permission.
App registration:
To check, I created a resource group and applying a dev tag for it after successful authentication.
Provider.tf
variable "client_secret" {}
terraform {
required_providers {
azuread = {
source = "hashicorp/azuread"
version = "2.30.0" //Give the latest version
}
}
}
provider "azurerm"{
features{}
}
provider "azuread" {
subscription_id = "<subscription_id>"
client_id = "<client_id>"
client_secret = var.client_secret
tenant_id = "<tenant_id>"
features{}
}
resource "azurerm_resource_group" "t_rg" {
name = "<resourcegroupName>"
location = "<location>"
tags = {
Environment = "Dev"
}
}
Executed terraform init:
After setting up everything, I executed terraform plan, it is asking for client_secret only not client_id:
Executed Terraform apply:
Authenticated & deployed successfully in Portal:
Applied tags successfully for resourcegroup as given:
So finally I have found the solution.
If you have multiple subscriptions of Azure (you are working for multiple clients) then the first thing is that you need to check which is your current subscription.
Run this command to check all subscriptions
az account tenant list
and run this command to change switch your subscription
az login --tenant <myTenantID>
and now you can run any Azure cli command and changes will be reflected on your current subscription

Terraform - Trying to create resources in Azure with service principal and pulling that SPs key from keyvault

Been brushing up using Terraform to manage resources in Azure the past week or so.
Great tool.
I've found there is a distinction between using an AZ user account vs service principal.
The goal is to create resources in Azure using a designated service principal and referencing it's secret that is stored within AZ key vault. Moving away from locally stored secret (file, env var, etc).
I can successfully create resources using an authenticated service principal as long as I have my azurerm provider containing the subid, clientid, clientsecret & tenantid, it works great.
Example of what works when I store service principal secret as a var sp_secret in variables.tf (or even works as env var):
provider "azurerm" {
version = "=2.48.0"
features { }
subscription_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
client_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
client_secret = "${var.sp_secret}"
tenant_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
I have been able to successfully pull the service principals secret from the keyvault and 'output' it, but what I want to do is to pull that secret from kv and use, say as a var inside the provider client_secret value. ex. 'client_secret = "${link to secret sitting in kv}"'
Here is what I am doing to retrieve the SP secret from keyvault and output it:
data "azurerm_client_config" "current" {}
variable "keyvault_name" {
default = "blah-kv"
}
variable "kvrg_name" {
default = "blah-kv-rg"
}
data "azurerm_key_vault" "keyvault" {
name = "${var.keyvault_name}"
resource_group_name = "${var.kvrg_name}"
}
data "azurerm_key_vault_secret" "kv-sp" {
name = "blah-tf-sp-secret"
key_vault_id = "${data.azurerm_key_vault.keyvault.id}"
}
output "secret_value" {
value = "${data.azurerm_key_vault_secret.kv-sp.value}"
}
As mentioned, the above snippet successfully retrieves and outputs the secret. I just want to, instead of output the secret, just set that secret as client_secret value in the azurerm provider reference.
I've tried many variations of client_secret = "${data.azurerm_key_vault_secret.kv-sp.value}", and I get the following error:
Error: Cycle: data.azurerm_key_vault.keyvault, provider["registry.terraform.io/hashicorp/azurerm"], data.azurerm_key_vault_secret.kv-sp
I interpret the above error to indicate a circular reference. I've tried a few things i've picked up in my searching for an answer, but no dice.
Any guidance is appreciated.
Thanks!
As I know. it's impossible to achieve what you expect. When you use the Terraform to manage Azure resources, then you need to have an Azure account or service principle with enough permissions. If you use the service principle, it means you need to configure the provider azurerm with client id and client secret before running the Terraform code. But when you store the secret in the Azure Key Vault, then you need to run the code, and then you can get the secret. It causes cycle dependency.

Service Principal from Terraform not recognized by Azure API

What specific changes need to be made to the syntax below in order for the terraform azurerm provider to be able to authenticate the service principal that will be created using the following code?
The Problem
A Second Terraform module needs to authenticate to Azure through the azurerm provider with a client_id and client_secret that is created programatically during an earlier, separate process.
The provider block in the Second Terraform module looks like:
provider "azurerm" {
subscription_id = var.subscriptionId
client_id = var.clientId
client_secret = var.clientSecret
tenant_id = var.tenantId
}
The problem arises when the correct values whcih we validated from the earlier preceding process are not accepted as the var.clientId and the var.clientSecret in the provider code block above.
How the Service Principal is Created:
The client_id and client_secret to be used to authenticate to the Second Terraform module are currently created by a First Terraform module which includes the following:
resource "azuread_application" "appReg" {
name = var.appName
}
resource "azuread_service_principal" "example-sp" {
application_id = azuread_application.appReg.application_id
}
resource "azuread_service_principal_password" "example-sp_pwd" {
service_principal_id = azuread_service_principal.example-sp.id
value = "long-random-string"
end_date = "2021-06-02T01:02:03Z"
}
data "azurerm_subscription" "thisSubscription" {
subscription_id = var.subscriptionId
}
resource "azurerm_role_assignment" "example-sp_role_assignment" {
scope = data.azurerm_subscription.thisSubscription.id
role_definition_name = "Contributor"
principal_id = azuread_service_principal.example-sp.id
}
resource "azuread_application_app_role" "example-role" {
application_object_id = azuread_application.appReg.id
allowed_member_types = ["User", "Application"]
description = "Admins can manage roles and perform all task actions"
display_name = "Admin"
is_enabled = true
value = "administer"
}
Terraform reports Apply complete after the above First module is run, and we are also able to confirm in the Azure Portal that the correct Active Directory has a new app registration with name var.appName and with ID equal to what we find in the First modules tfstate file.
The Error Message:
When Terraform tries to apply the Second module using the Service Principal ID and Secret created by the First module, the following error is thrown:
Error:
Error building account:
Error getting authenticated object ID:
Error listing Service Principals:
autorest.DetailedError{
Original:adal.tokenRefreshError{
message:"adal: Refresh request failed.
Status Code = '400'.
Response body: {
\"error\":\"unauthorized_client\",
\"error_description\":\"AADSTS700016:
Application with identifier 'correct-app-id' was not found in the directory 'the-right-ad-id'.
This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant.
You may have sent your authentication request to the wrong tenant.\\r\\n
Trace ID: some-trace-id\\r\\n
Correlation ID: correlation-id-redacted\\r\\n
Timestamp: 2020-12-31 19:02:19Z\",
\"error_codes\":[700016],
\"timestamp\":\"2020-12-31 19:02:19Z\",
\"trace_id\":\"some-trace-id\",
\"correlation_id\":\"correlation-id-redacted\",
\"error_uri\":\"https://login.microsoftonline.com/error?code=700016\"
}",
resp:(*http.Response)(0xc000ac2000)},
PackageType:"azure.BearerAuthorizer",
Method:"WithAuthorization",
StatusCode:400,
Message:"Failed to refresh the Token for request to https://graph.windows.net/the-right-ad-id/servicePrincipals?%24filter=appId+eq+%27correct-app-id%27&api-version=1.6",
ServiceError:[]uint8(nil),
Response:(*http.Response)(0xc000ac2000)
}
The error message does not seem helpful because we validated that the app is registered with the AAD instance.
How can we resolve this problem and programmatically create a client_id and client_secret that will be accepted and usable by the Second module?
As I see there is no problem with your Terraform code. It should work fine. But you got the error that the application was not found in the tenant. So what you need to do is to check if the tenant Id is really right in the second module.
I had the same issue on Deployment Agents for Terraform on Kubernetes. Several types of error can appear when the memory or the CPU is not large enough.
Below are the Terraform recommendations: https://www.terraform.io/docs/enterprise/before-installing/index.html
You have to be careful with the deployment infrastructures that mutualises the resources (K8s, Hypervisor Pool etc.)when several Terraform deployments are in parallel it causes somewhat random errors.
Terraform which does not stop, API AZure / AWS error, tfstate lock etc.

Attach certificate thumbprint to app registration in Azure using Terraform

I'm wondering if anyone knows of a way to attach a certificate thumbprint to an app registration using either the azuread or azurerm providers? Currently I can make a valid cert with thumbprint and drop it into my keyvault, as well as make an app registration in Azure AD via terraform, however for the purpose of our apps I would need my app registration to have access to and consume certificates in my keyvault. Any input would be greatly appreciated.
you can do it like this. You will need to have the cert correctly encoded.
resource "azuread_application" "application" {
display_name = "nameofapp"
}
resource "azuread_application_certificate" "application_certificate" {
application_object_id = azuread_application.application.id
type = "AsymmetricX509Cert"
value = file("cert-der-base64.cer")
end_date = "2022-02-24T00:00:00Z"
}

Terraform - How to get App Service object id for azurerm key vault access policy?

Using Terraform, I am trying to add a keyvault access policy to an application (that is also created in Terraform), which requires an object_it (which is GUID) of that application. In ARM template it looks like this:
"objectId": "[reference(variables('myAppResourceId'), '2015-08-31-PREVIEW').principalId]"
so Terraform needs the principal id there to be assigned to the object_id. If I use the value "object_id = ${azurerm_app_service.myApp.id}" like this:
resource "azurerm_key_vault_access_policy" "pol1" {
vault_name = "${azurerm_key_vault.kv1.name}"
resource_group_name = "${azurerm_key_vault.kv1.resource_group_name}"
tenant_id = "${data.azurerm_subscription.current.subscription_id}"
object_id = "${azurerm_app_service.myApp.id}"
key_permissions = "${var.app_keys_permissions}"
secret_permissions = "${var.app_secrets_permissions}"
}
then when I run apply command, I get the following error:
azurerm_key_vault_access_policy.pol1: "object_id" is an invalid UUUID: encoding/hex: invalid byte: U+002F '/'
this is probably the id that looks like an url with a slash,so this does not work, since I need the GUID only.
I tried also a suggestion from Terraform grant azure function app with msi access to azure keyvault, by using object_id = "${lookup(azurerm_app_service.app1.identity[0],"principal_id")}" for an app service instead of the function and I get an error:
azurerm_key_vault_access_policy.appPolicy1: At column 43, line 1: list "azurerm_app_service.app1.identity" does not have any elements so cannot determine type. in:
${lookup(azurerm_app_service.app1.identity[0],"principal_id")}
could someone help me with this object_id please?
thanks
When you read the description for azurerm_key_vault_access_policy property object_id, then you should know it could mean the web app principal Id.
And the azurerm_app_service.myApp.id that you put is not the principal Id, it's the app service resource Id. You should put the azurerm_app_service.myApp.identity.principal_id that associated with your web app. Take a look at the Attributes of the App Service Resource. Hope this will help you.
However, something not mentionned in the documentation is the need to specify an identity block in your app_service declaration.
identity { type = "SystemAssigned" }
If you don't specify it, you might get an empty list as identity attribute.

Resources