Skip to content

Azure Module Dependencies

The Merkalis Azure modules are designed for provisioning the components of a complete Kastoria environment. This page records which module outputs are consumed as inputs by which other modules, so that wiring and build order are explicit rather than implicit.

Module inventory

Module Role
networking Provisions the VNet and its subnets (compute / storage / gateway)
secrets Provisions a Key Vault and a reader user-assigned identity
filestore Provisions SMB file shares, one storage account per shard
objectstore Provisions Blob + table storage, one storage account per shard
queue Provisions a Storage Queue on a dedicated key-disabled account (optional)
compute Provisions the Container App Environment with container apps and jobs
gateway Provisions the reverse proxy entrypoint, with optional Cloudflare Tunnel and mTLS proxy
telemetry Provisions the OTel collector container app and Grafana datasource

An environment also defines a user-assigned storage-accessor identity that no module produces; it feeds the storage and compute modules (see Storage identity).

Dependency graph

graph TD
    RG[Resource Group]
    ID[User Managed Identity<br/>storage accessor]

    NET[networking]
    SEC[secrets]
    FILE[filestore]
    OBJ[objectstore]
    COMP[compute]
    GW[gateway]
    TEL[telemetry]
    QUEUE[queue]

    RG --> NET & SEC & FILE & OBJ & COMP & GW & TEL & QUEUE
    ID --> FILE & OBJ & COMP

    NET -->|subnet ids| SEC & FILE & OBJ & COMP & QUEUE
    QUEUE -->|storage_account_name, queue_name, publisher_id, publisher_client_id| COMP
    SEC -->|vault_uri, identity_id| COMP
    SEC -->|vault_id, vault_name, identity_id| GW
    FILE -->|file_shares_config, access keys| COMP
    COMP -->|environment id, default domain, identity_id| GW
    COMP -->|environment id, identity_id| TEL

Output → input edges

networking

Output Consumer Input Notes
created_subnets["compute"].id secrets allowed_subnet_ids Key Vault service-endpoint ACL
filestore allowed_subnet_ids shared with storage
objectstore allowed_subnet_ids shared with storage
queue allowed_subnet_ids the only subnet the queue admits
compute subnet_id ACA VNet integration
created_subnets["storage"].id filestore allowed_subnet_ids
objectstore allowed_subnet_ids
created_subnets["gateway"].id compute gateway_subnet_id

Subnet names are not invented by the module — the caller declares the set of subnets, and networking mirrors them back in created_subnets, keyed by subnet name (compute / storage / gateway in the standard layout).

secrets

Output Consumer Input Notes
vault_uri compute key_vault_uri for key_vault_secrets per app/job
identity_id compute key_vault_reader_identity_id reader identity attached to apps/jobs reading Key Vault
gateway user_assigned_identity_id proxy reads the vault for the CA cert + tunnel token
vault_id gateway key_vault_id
vault_name gateway key_vault_name

filestore

Output Consumer Input Notes
file_shares_config compute apps[].share_mounts, jobs[].share_mounts non-sensitive share metadata
file_shares[].access_key compute storage_access_keys delivered through a separate sensitive map

The two paths are deliberately separate: the non-sensitive file_shares_config drives for_each on apps/jobs, while the sensitive access_key values travel through the dedicated storage_access_keys map so they do not taint for_each keys downstream.

Note: These outputs are only indirectly consumed by compute

queue

Output Consumer Input Notes
storage_account_name compute app_config.queue_writer accountName in the JSON-encoded queueWriter section
queue_name compute app_config.queue_writer queueName in the same section
publisher_id compute apps[].user_managed_queue_app.id, jobs[].user_managed_queue_app.id attached to the workloads that publish
publisher_client_id compute same, and app_config.queue_writer managedIdentityClientId in the queueWriter section
publisher_principal_id — — the Sender grant target, for post-apply inspection
queue_url — — handed to your queue reader
storage_account_id — — currently unconsumed

The queue module owns its publisher identity end to end — it creates it, grants it Storage Queue Data Message Sender, and exports it — the same shape secrets uses for its reader identity. You decide which workloads receive it, just as you decide which receive the storage-accessor identity. The queue is optional: omit the module and leave queue_writer unset.

Note: These outputs are only indirectly consumed by compute

compute

Output Consumer Input Notes
container_app_environment_id gateway container_app_environment_id proxy provisions into the same ACA environment
telemetry container_app_environment_id OTel collector provisions into the same environment
container_app_environment_default_domain gateway domain overridable per environment
identity_id gateway registry_identity_id ACR pull auth for proxy images
telemetry registry_identity_id ACR pull auth for the collector image
identity_principal_id — — consumed at the environment level for ACR RBAC
app_fqdns — — currently unconsumed

compute depends almost entirely on its own configuration rather than on module outputs: the caller supplies apps, jobs, storage_access_keys, app_config, key_vault_uri, key_vault_reader_identity_id, and the subnet IDs.

Storage identity

The environment defines one user-assigned managed identity that is not owned by any module. It is the identity Kastoria uses to reach storage without account keys, and it feeds three places:

  • filestore.user_managed_identity_principal_id → share-access role assignment
  • objectstore.user_managed_identity_principal_id → blob + table data contributor role assignments
  • compute apps/jobs as user_managed_storage_app, so workloads authenticate to storage with the identity rather than connection strings

It does not feed queue: holding the storage identity grants no access to the queue. A workload that publishes carries the queue module's publisher identity as well (see queue).

Leaf modules

objectstore, gateway, and telemetry produce no inputs to other modules in the composition:

Module Outputs Consumed by
objectstore storage_accounts, tables environment-side wiring only — workload access is via RBAC + app_config.storage_tiers
gateway container_app_*, cloudflared_*, cloudflare_tunnel_*, mtls_proxy_* nothing — terminal
telemetry grafana_datasource_uid nothing — terminal

Ordering

Terraform/OpenTofu derives apply order from references, but the effective levels are:

  1. Resource group + storage-accessor identity
  2. networking
  3. secrets, filestore, objectstore, queue (in parallel)
  4. compute (needs the subnets, vault URI/reader identity, share metadata + keys, and the queue account, name and publisher identity when queue_writer is set)
  5. gateway, telemetry (need the Container App Environment id)

On a fresh subscription, also declare an explicit depends_on from compute to the Microsoft.App resource-provider registration and the storage-accessor identity — neither is a data reference, so without them the ordering would be implicit and racy.