Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions known_issues/18_tf_env_azure.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Known Issues: Terraform Azure Environment

> **Audit status (2026-04-20):** `0 still valid · 7 resolved · 1 partially fixed · 0 moved · 0 needs triage`
> **Audit status (2026-04-25):** `0 still valid · 8 resolved · 0 partially fixed · 0 moved · 0 needs triage`

## ~~CRITICAL: `nonsensitive()` strips sensitivity from `additional_secrets` before merge~~ — RESOLVED

Expand Down Expand Up @@ -95,18 +95,17 @@

**Effort:** `small` (contingent on triage)

## ~~HIGH: `SCHEDULED_TASK_SECRET` injected as plain-text environment variable~~ — PARTIALLY RESOLVED
## ~~HIGH: `SCHEDULED_TASK_SECRET` injected as plain-text environment variable~~ — RESOLVED

**File**: `terraform/environments/azure/compute.tf:42`
**Description**: The scheduled-task shared secret was injected into the Container App as a plaintext env var, visible via `az containerapp show`, the Azure Portal, and exported ARM templates.
**Status:** ✔️ Partially resolved — runtime env-var leak closed; Logic App path deferred.
**Status:** ✔️ Fully resolved — runtime env-var leak closed AND Logic App path migrated to Key Vault references (issue #50).

**Resolved by:**

- Container App env var switched from `SCHEDULED_TASK_SECRET = <value>` to `SCHEDULED_TASK_SECRET_NAME = <kv-secret-name>`. `az containerapp show` now reveals only the secret name.
- `ApplicationConfig.ScheduledTaskSecretName` added. `NewApplicationFromDeps` resolves it via the existing `SecretResolver` (Azure Key Vault / AWS Secrets Manager) at startup and populates `ScheduledTaskSecret` in memory. Falls back to the plaintext `SCHEDULED_TASK_SECRET` env var if the lookup fails or the resolver isn't configured, so dev/local runs still work.

**Deferred:** The Logic App workflow (`scheduled-tasks.tf:48,106`) still interpolates `var.scheduled_task_secret` into its outgoing `Authorization: Bearer …` header. This value is stored inside the Logic App resource + Terraform state; removing it requires migrating to Azure Logic Apps Key Vault connections (`@parameters('kv-secret')`), a larger refactor. The container-app side — which is what was actually flagged in the audit — no longer leaks.
- Logic App workflows now have a system-assigned managed identity granted "Key Vault Secrets User" on the vault; each workflow's first action GETs the secret from KV at runtime via that identity, and the call-endpoint action references `@body('get-secret')['value']` in its outgoing Authorization header. The plaintext value no longer lives in the workflow definition or Terraform state. See `terraform/modules/compute/azure/container-apps/scheduled-tasks.tf` and PR resolving #50.

### Original implementation plan

Expand Down
20 changes: 20 additions & 0 deletions terraform/environments/azure/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 8 additions & 11 deletions terraform/environments/azure/compute.tf
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,14 @@ module "compute_container_apps" {

# Scheduled tasks (Logic Apps)
#
# scheduled_task_secret still passes the plaintext value here because the
# Logic App workflow definition embeds it in its outgoing "Authorization:
# Bearer ..." header (see scheduled-tasks.tf). Azure Logic Apps DO support
# Key Vault references via @parameters() + a Key Vault connection, but
# that's a larger refactor. This value is stored in Terraform state and
# in the Logic App resource, but is no longer exposed in the Container
# App's env vars — `az containerapp show` now reveals only the secret
# name, not the value.
enable_scheduled_tasks = var.enable_scheduled_tasks
scheduled_task_secret = module.secrets.scheduled_task_secret_value
recommendation_schedule = var.recommendation_schedule
# Each Logic App workflow has a system-assigned managed identity that holds
# "Key Vault Secrets User" on the same Key Vault as the Container App. The
# workflow's first action GETs scheduled-task-secret from KV via that
# identity at runtime; the value never lands in the workflow definition or
# Terraform state. We only pass the *name* of the secret, not the value.
enable_scheduled_tasks = var.enable_scheduled_tasks
scheduled_task_secret_name = module.secrets.scheduled_task_secret_name
recommendation_schedule = var.recommendation_schedule

# RI exchange automation
enable_ri_exchange_schedule = var.enable_ri_exchange_schedule
Expand Down
Loading