2
votes

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?

2
I used your terraform code and I did not have a problem. You are leaving something out of your question that indicates the problem. Create a two part example that is complete with everything. Update your question with those parts.John Hanley
CodeMed can you share the "article about service principals that will be used for remote api calls like terraform need to be created by a script"? Or any other that may be useful to understand your setup (I don't know terraform but do tons of Azure AD)Alfredo R
I create two Gists. The output from Part 1 is put into Part 2 manually. Part 1 gist.github.com/jhanley-com/3de93b2243cd1ba5fcad6e2c6dc49da3 and Part 2 gist.github.com/jhanley-com/335a9b949e67d9027590219216279811John Hanley
i think this may be the think referring to issues related to eventual consistency: github.com/hashicorp/terraform-provider-azuread/issues/156Kam
@JohnHanley Your suggestions worked. Thank you for being a second set of eyes on this.CodeMed

2 Answers

0
votes

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.

0
votes

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.