Skip to content

libre-devops/terraform-azapi-api-connection

Repository files navigation

Terraform Azure API Connection

Logic App API connections (Microsoft.Web/connections) with managed identity and oAuth done right, via azapi.

CI Release Terraform Registry License


Overview

API connections are the credential half of every Logic App connector, and the reason playbook deployments fight Terraform: the native azurerm_api_connection resource cannot express managed identity auth or the oAuth consent flow, and naive management makes every portal consent a diff. This module drives the resource through azapi instead:

  • Managed identity auth. use_managed_identity = true sets parameterValueType = "Alternative": no credentials stored, the consuming Logic App presents its identity. This is the shape Sentinel playbooks should use.
  • oAuth without stored secrets. A named parameter_value_set creates the connection unauthenticated; a human consents once in the portal, and because parameter values are ignored after create, the consent sticks instead of being reverted on the next apply.
  • Key-based connectors still work. Secret values ride in a separate sensitive parameter_values variable keyed by connection name (the definitions stay printable), next to inline non-secret and custom parameter values; a check flags secret entries that the chosen auth shape would ignore.
  • Managed APIs by short name. managed_api_name = "office365" resolves against the subscription and region; a full managed_api_id binds custom connectors.

Requires Terraform >= 1.9, azapi >= 2.0, and azurerm >= 4.0 (for its client-side parse_resource_id function only). Pairs with the sentinel-automation-rule module (playbooks) and any Logic App deployment.

Usage

module "api_connection" {
  source  = "libre-devops/api-connection/azapi"
  version = "~> 4.0"

  resource_group_id = module.rg.ids["rg-ldo-uks-prd-001"]
  location          = "uksouth"
  tags              = module.tags.tags

  api_connections = {
    "azuresentinel-mi" = {
      managed_api_name     = "azuresentinel"
      use_managed_identity = true
    }

    "office365-oauth" = {
      managed_api_name    = "office365"
      parameter_value_set = { name = "oauthMI" }
    }

    "azureblob-key" = {
      managed_api_name            = "azureblob"
      non_secret_parameter_values = { accountName = "stldouksprd001" }
    }
  }

  parameter_values = {
    "azureblob-key" = {
      accountName = "stldouksprd001"
      accessKey   = module.storage.primary_access_keys["stldouksprd001"]
    }
  }
}

Examples

  • examples/minimal - one managed identity connection.
  • examples/complete - all three auth shapes plus a full-id binding, with a real storage key wired through the sensitive variable.

Developing

Local work needs PowerShell 7+ and just, because the recipes wrap the LibreDevOpsHelpers PowerShell module (the same engine the libre-devops/terraform-azure action runs in CI). Install just with brew install just, or uv tool add rust-just then uv run just <recipe>.

Run just to list recipes: just update-ldo-pwsh (install or force-update LibreDevOpsHelpers from PSGallery), just validate, just scan (Trivy only), just pwsh-analyze (PSScriptAnalyzer only), just plan, just apply, just destroy, just e2e, just test, and just docs (the plan/apply/destroy recipes mirror the action, including the storage firewall dance; just e2e applies an example then always destroys it, defaulting to minimal, so nothing is left running). Releasing is also just: just increment-release [patch|minor|major] bumps, tags, and publishes a GitHub release, and the Terraform Registry picks up the tag.

Security scan exceptions

This module is scanned with Trivy; HIGH and CRITICAL findings fail the build. Any waiver is a deliberate, reviewed decision, never a way to quiet a finding that should be fixed. Waivers live in a .trivyignore.yaml (the machine-applied source of truth, passed to Trivy with --ignorefile) and are mirrored in a table here so the reason is auditable.

There are currently no exceptions: the module and its examples scan clean.

Reference

The Requirements, Providers, Inputs, Outputs, and Resources below are generated by terraform-docs.

Requirements

Name Version
terraform >= 1.9.0, < 2.0.0
azapi >= 2.0.0, < 3.0.0
azurerm >= 4.0.0, < 5.0.0

Providers

Name Version
azapi >= 2.0.0, < 3.0.0

Modules

No modules.

Resources

Name Type
azapi_resource.this resource

Inputs

Name Description Type Default Required
api_connections API connections (Microsoft.Web/connections, the credential half of a Logic App connector) keyed by
name; the key doubles as the display name unless display_name is set.

The API to bind is managed_api_name (the short connector name: azuresentinel, office365,
keyvault, azureblob, ...), resolved against the subscription and location, or a full
managed_api_id for custom connectors.

Authentication, one of three shapes:
- use_managed_identity = true: the connection authenticates with a managed identity
(parameterValueType Alternative), no credentials stored.
- parameter_value_set: named auth scheme with partial values (an oAuth connection is created
unauthenticated and consented once in the portal; the consent survives Terraform runs because
parameter values are ignored after create).
- secret parameter_values (via the separate sensitive variable) and/or inline
non_secret_parameter_values / custom_parameter_values for key- and token-style connectors.

Parameter values, timestamps, and Azure-managed API metadata are ignored after create, so portal
consent flows and service-side updates never fight Terraform.
map(object({
managed_api_name = optional(string)
managed_api_id = optional(string)

display_name = optional(string)
use_managed_identity = optional(bool, false)

parameter_value_set = optional(object({
name = string
values = optional(map(string), {})
}))

non_secret_parameter_values = optional(map(string))
custom_parameter_values = optional(map(string))

tags = optional(map(string))
}))
{} no
api_version The Microsoft.Web/connections API version azapi drives. string "2016-06-01" no
location The Azure region the connections (and the managed APIs they bind to) live in. string n/a yes
parameter_values Secret parameter values (connection strings, keys, tokens) keyed by the same connection name used in api_connections. Kept out of the main map so the connection definitions stay non-sensitive; ignored after create, so rotation happens by replacing the connection or updating out-of-band. map(map(string)) {} no
resource_group_id The id of the resource group the API connections land in. Parsed for the subscription (to resolve managed API names) and the resource group name. string n/a yes
schema_validation_enabled Whether azapi validates the request body against its embedded ARM schema before sending it. Off by default: the embedded 2016-06-01 connections schema does not model parameterValueType (managed identity) or parameterValueSet (oAuth) even though ARM accepts both. bool false no
tags Tags applied to every connection (merged with any per-connection tags). map(string) {} no

Outputs

Name Description
api_connection_ids Map of connection name to its id.
api_connection_ids_zipmap Map of connection name to { name, id }, for easy composition with other modules (Logic App workflow parameters, for example).
api_connections Map of connection name to { id, name, display_name, managed_api_id, and the exported api metadata, statuses, and parameter value type }.

About

πŸ”Œ Terraform module for Logic App API connections via azapi: managed identity and oAuth done right

Topics

Resources

License

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors