November 1, 2025

Using Resource Selectors in Humanitec Terraform Container Runner Driver

The code in this post is based on Humanitec’s Azure resource packs.

Resource selectors in Humanitec return a set of resources that have a particular type and have a certain dependency. For instance, in order to obtain all Azure role definitions to create appropriate role assignments, the following resource selectors can be used:

  role_definition_ids = "$${resources.workload>azure-role-definition.outputs.id}"
  scopes              = "$${resources.workload>azure-role-definition.outputs.scope}"

These are input variables of the corresponding Humanitec resource definition, where the are used to set variable values of the Terraform module creating the role assigments:

resource "humanitec_resource_definition" "main" {
  driver_type = "humanitec/terraform" (1)
  id          = local.def_id
  name        = local.def_id
  type        = "azure-role-assignments"

  driver_account = var.driver_account
  driver_inputs = {
    values_string = jsonencode({
      source = {
        path = "modules/azure-role-assignments/basic"
        rev  = var.resource_packs_azure_rev
        url  = var.resource_packs_azure_url
      }

      append_logs_to_error = var.append_logs_to_error

      credentials_config = {
        environment = {
          ARM_CLIENT_ID     = "appId"
          ARM_CLIENT_SECRET = "password"
          ARM_TENANT_ID     = "tenant"
        }
      }

      files = local.files

      variables = { (2)
        res_id = "$${context.res.id}"
        app_id = "$${context.app.id}"
        env_id = "$${context.env.id}"

        name                = var.name
        subscription_id     = var.subscription_id
        prefix              = var.prefix
        role_definition_ids = var.role_definition_ids
        scopes              = var.scopes
        principal_id        = var.principal_id
      }
    })
  }
}
1The Azure resource packs use Terraform and Humanitec’s Terraform driver.
2The input variables to the Terraform root module creating the role assignments.

This driver runs in Humanitec’s infrastructure, but you might want to run Terraform in a Kubernetes cluster in Azure for security reasons. To achieve that, Humanitec’s Terraform Container Runner Driver provides an easy way to do that. It is a virtual driver that wraps the Container Driver.

If the Terraform Container Runner Driver is used instead - with the necessary changes in configuration but the same variable block - error messages similar to the one listed below will appear in the runner and deployment log. Note that the error message has been redacted and formatted for easier readability.

Humanitec Operator error
error provisioning resource azure-role-assignments#modules.quotes-api GuResID: 0000000000000000000000000000000000000000.
Status: False. Reason: DriverFailed. Message: unexpected response code (400) and error provisioning the resource:
RES-004: Provisioning failed: Error: Root value must be object on gjqsfboc.auto.tfvars.json line 1: 1:
{
  "app_id": "app-01",
  "env_id": "env",
  "principal_id": "00000000-0000-0000-0000-000000000000",
  "res_id": "modules.api-1",
  (1)
  "role_definition_ids": "["/providers/Microsoft.Authorization/roleDefinitions/00000000-0000-0000-0000-000000000000"]",
  "scopes": "["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/.../blobServices/default/containers/app-01-testblob-gftrsd"]",
  "subscription_id": "00000000-0000-0000-0000-000000000000"
}

The root value in a JSON-based configuration must be either a JSON object or a JSON array of objects. Error: Missing attribute seperator comma on gjqsfboc.auto.tfvars.json line 1: 1:
{
  "app_id": "app-01",
  "env_id": "env",
  "principal_id": "00000000-0000-0000-0000-000000000000",
  "res_id": "modules.api-1",
  (1)
  "role_definition_ids": "["/providers/Microsoft.Authorization/roleDefinitions/00000000-0000-0000-0000-000000000000"]",
  "scopes": "["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/.../blobServices/default/containers/app-01-testblob-gftrsd"]",
  "subscription_id": "00000000-0000-0000-0000-000000000000"
}

A comma must appear between each property definition in an object.
1The quotes around the list of role definition ids and scopes cause the JSON to be invalid.

The error results from the way encoding is handled when a virtual driver is used. The list of e.g. scopes is considered a string and encoded as such, resulting in invalid JSON.

The solution is described here:

To supply OpenTofu or Terraform variables, the field variables described in values can be used,
unless you want to inject a Resource Selector.

Due to some encoding limitations, OpenTofu or Terraform variables that take their value from a
Resource Selector can not be placed in the variables inputs field. Instead, you can use the files
section to create a variable definitions file (Terraform , OpenTofu ) and place those variables here
like this:

When using Terraform, this can be implemented using heredoc:

      files = merge(local.files, { "input_vars.auto.tfvars.json" = <<-EOT (1)
                            {
                              "role_definition_ids": ${var.role_definition_ids}, (2)
                              "scopes": ${var.scopes}
                            }
EOT
        }
      )

      variables = {
        res_id = "$${context.res.id}"
        app_id = "$${context.app.id}"
        env_id = "$${context.env.id}"

        subscription_id = var.subscription_id
        principal_id = var.principal_id
      }
1The file content of input_vars.auto.tfvars.json is created literally using heredoc. Using jsonencode results in the same encoding error.
2No extra quotes around the set of ids and scopes.

Happy plattforming!

Tags: Humanitec IaC Platform Engineering