Azure / Azure/terraform-provider-azapi

`azapi_update_resource` with `Microsoft.App/managedEnvironments@2025-02-02-preview` doesn't set `headers` if using `sensitive_body`

Open
#943 2 comments 0 reactions 0 assignees View on GitHub
example triaged
Dominant language
Go
Stars
244
Forks
97
Avg merge
5d 9h
Merged PRs (30d)
9

Description

Terraform Version: `v1.12.2`
AzApi Version: `2.5.0`

When trying to update the Azure Container App Environment OTel Endpoints via an `azapi_update_resource` using `sensitive_body` for the `headers` property which would contain sensitive API keys. The merge-patch seems to be setting the property value as `null` but its type is an array or maps of Key/Value properties as per the Azure API spec for `Microsoft.App/managedEnvironments@2025-02-02-preview`: https://github.com/Azure/azure-rest-api-specs/blob/9e82d503ceec8ab4248587d066e1702608bb33ab/specification/app/resource-manager/Microsoft.App/preview/2025-02-02-preview/examples/ManagedEnvironments_CreateOrUpdate.json#L38

I validated that the data structure expected by the API spec matches what i'm supplying in the `headers` property that im setting in the `sensitive_body` but when I apply, there are no errors but the value is `null`.

I validated this by just setting it in the `body` propery (so no merge-patching) and it works so suspect there is something odd happening when supplying a property thats not just a simple string etc

What am I doing wrong here or is this a bug.

This is an example of what I am doing:

- Setting up local maps to pass into the AzApi Update Resource:

```terraform
locals {
otlp_configurations = {
logzio_logs = {
endpoint = format("https://otlp-%s/v1/logs", var.logzio_otlp_listener_host)
insecure = false
auth_secret_name = "logzio-otlp-logs-headers"
logs_destinations = ["logzio_logs"]
traces_destinations = null
metrics_destinations = null
}
logzio_metrics = {
endpoint = format("https://%s:8053", var.logzio_otlp_listener_host)
insecure = false
auth_secret_name = "logzio-otlp-metrics-headers"
logs_destinations = null
traces_destinations = null
metrics_destinations = ["logzio_metrics"]
}
logzio_traces = {
endpoint = format("https://otlp-%s/v1/traces", var.logzio_otlp_listener_host)
insecure = false
auth_secret_name = "logzio-otlp-traces-headers"
logs_destinations = null
traces_destinations = ["logzio_traces"]
metrics_destinations = null
}
}

otlp_secret_headers = {
for key, secret in ephemeral.azurerm_key_vault_secret.otlp : key => flatten([
for headers in split(";", secret.value) : {
key = split("=", headers)[0]
value = split("=", headers)[1]
}
])
}

otlp_config_map = {
for key, config in local.otlp_configurations : key => {
endpoint = config.endpoint
insecure = config.insecure
auth_secret_name = config.auth_secret_name
logs_destinations = config.logs_destinations
traces_destinations = config.traces_destinations
metrics_destinations = config.metrics_destinations
headers = config.auth_secret_name != null ? flatten([for header in local.otlp_secret_headers[key] : {
key = header.key
value = header.value
}]) : null
}
}
}
```

The AzApi Update resource which is setting `headers` to `null` instead of for example
```json
"headers": [
{
"key": "api-key",
"value": "xxxxxxxxxxx"
}
]
```

```terraform
resource "azapi_update_resource" "otlp_collector" {
type = "Microsoft.App/managedEnvironments@2025-02-02-preview"
resource_id = azurerm_container_app_environment.env.id
ignore_casing = true

body = {
properties = {
openTelemetryConfiguration = {
destinationsConfiguration = {
otlpConfigurations = [for key, config in local.otlp_config_map :
{
name = key
endpoint = config.endpoint
insecure = config.insecure
}
]
}
logsConfiguration = {
destinations = flatten([for key, value in local.otlp_config_map : value.logs_destinations if value.logs_destinations != null])
}
tracesConfiguration = {
destinations = flatten([for key, value in local.otlp_config_map : value.traces_destinations if value.traces_destinations != null])
}
metricsConfiguration = {
destinations = flatten([for key, value in local.otlp_config_map : value.metrics_destinations if value.metrics_destinations != null])
}
}
}
}

sensitive_body = {
properties = {
openTelemetryConfiguration = {
destinationsConfiguration = {
otlpConfigurations = [for key, config in local.otlp_config_map :
{
headers = config.headers
}
]
}
}
}
}

sensitive_body_version = {
for key, value in local.otlp_config_map : key => [
for secret in data.azapi_resource_list.otlp_secret_versions[key].output.value :
secret.properties.secretUriWithVersion
if secret.name == value.auth_secret_name
][0] if value.auth_secret_name != null
}

depends_on = [azurerm_container_app_environment.env]
}
```

This incorrectly sets `headers` to `null`:

```json
"openTelemetryConfiguration": {
"destinationsConfiguration": {
"dataDogConfiguration": null,
"otlpConfigurations": [
{
"name": "logzio_logs",
"endpoint": "https://otlp-listener.logz.io/v1/logs",
"insecure": false,
"headers": null
},
{
"name": "logzio_metrics",
"endpoint": "https://listener.logz.io:8053",
"insecure": false,
"headers": null
},
{
"name": "logzio_traces",
"endpoint": "https://otlp-listener.logz.io/v1/traces",
"insecure": false,
"headers": null
}
]
},
"tracesConfiguration": {
"includeDapr": false,
"destinations": [
"logzio_traces"
]
},
"logsConfiguration": {
"destinations": [
"logzio_logs"
]
},
"metricsConfiguration": {
"includeKeda": false,
"destinations": [
"logzio_metrics"
]
}
},
```

As mentioned setting the headers just in the body works fine.

Contributor guide

Open the contributing guide

Research direction

Start at the azapi_update_resource handling for sensitive_body and its merge-patch path, comparing it with the working body path described in the issue. Reproduce the Microsoft.App/managedEnvironments example and trace why the nested headers array becomes null; done means sensitive headers remain an array in the generated request and a regression test covers the case.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, go, terraform
Domain
api, cloud
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.