Skip to content

saif-api-service

This is a module for deploying an API to an App Service Plan and add that API to an API Management Service.

⚠️ Authentication Provider Changes

This module now supports dual authentication:

  • Corporate Tenant: Uses Entra ID (Microsoft) for internal/corporate authentication
  • External Tenant: Uses Okta for external user authentication

The API Management policies are configured to validate JWT tokens from both providers, allowing the API to serve both corporate and external users.

Feature flags

Optional capabilities such as Cosmos DB NoSQL, Blob Storage, and Service Bus queues are members of the single feature_flags object input, not top-level module arguments. In a Forge v3 project, the templates generate this module call as module "saif-appservices" in infra/api/app.generated.tf.

A module block accepts only one feature_flags argument, and Terraform rejects a second one as a duplicate. When you enable another feature and the module call already defines feature_flags (for example, a project scaffolded with database_type=cosmosdb already has the Cosmos DB members generated into it), add the new feature's members to that existing object instead of adding a new feature_flags = { ... } block:

module "saif-appservices" {
  # ... existing generated module arguments ...

  feature_flags = {
    # Existing members, e.g. from Cosmos DB
    cosmosdb_nosql_serverless = true

    # Members added for another feature, e.g. Blob Storage
    enable_blob_storage = true
    blob_storage_settings = {
      containers           = ["documents"]
      contributor_group_id = "12345678-1234-1234-1234-123456789abc"
    }
  }
}

The feature_flags row in the Inputs table below lists every member and its default. Each feature's development guide documents the members it needs.

Providers

Name Version
azurerm.shared-services >= 4.0, < 5.0

Inputs

Name Description Type Default Required
api n/a
object({
name = string
type = string
open_api_file = string
})
n/a yes
api_policy_type APIM policy type. 'standard' uses Okta/Entra tenant-based routing. 'filevine' validates Filevine Identity Server JWTs for webhook endpoints. 'subscription_key' allows legacy apps to authenticate via APIM subscription keys (Experience APIs only). string "standard" no
application_secrets Secrets for your application from Azure Devops Library map(string) {} no
application_settings Settings for your application map(string) {} no
azure_logging_level The logging level for the Azure Infrastructure string "Error" no
create_staging_slot Whether to create a staging slot for the web app bool false no
deployed_by Identifier for the deployment mechanism (e.g. Terraform, GitHub Actions) string "Terraform" no
enable_health_check Whether to enable the App Service health check. Defaults to true. Set to false to opt out. bool true no
environment The environment in which the resources are deployed string n/a yes
environment_short_name The short name of the environment string "" no
feature_flags Feature Flags for this module
object({
cosmosdb_nosql_serverless = optional(bool, false)
cosmosdb_nosql_serverless_settings = optional(object({
containers = map(object({
partition_key_path = string
ttl_in_days = optional(number) # TTL in days; null = TTL disabled, -1 = TTL enabled with no expiration, positive whole number = TTL in days
unique_keys = optional(list(list(string)), []) # each inner list = one unique key constraint (single-path or composite)
}))
}), {
containers = {}
})
cosmosdb_nosql_serverless_data_readers = optional(map(object({
object_id = optional(string)
group_name = optional(string)
})), {})
enable_blob_storage = optional(bool, false)
blob_storage_settings = optional(object({
containers = list(string)
contributor_group_id = string
}), {
containers = []
contributor_group_id = ""
})
enable_document_intelligence = optional(bool, false)
enable_servicebus_queue = optional(bool, false)
# Keyed by a stable queue identity name (e.g. "intake", "retries") so an app can provision
# multiple, independent Service Bus queues. Defaults to a single "default" queue. Mirrors the
# full servicebus-queue module's per-queue settings so every module option is configurable here.
servicebus_queues = optional(map(object({
max_delivery_count = optional(number, 10)
lock_duration = optional(string, "PT30S")
default_message_ttl = optional(string, "P14D")
dead_lettering_on_message_expiration = optional(bool, true)
requires_duplicate_detection = optional(bool, false)
duplicate_detection_history_time_window = optional(string, "PT10M")
max_size_in_megabytes = optional(number, 1024)
dlq_reader_identities = optional(map(string), {})
dlq_manager_identities = optional(map(string), {})
})), {
default = {
max_delivery_count = 10
dead_lettering_on_message_expiration = true
requires_duplicate_detection = false
dlq_reader_identities = {}
dlq_manager_identities = {}
}
})
})
{
"blob_storage_settings": {
"containers": [],
"contributor_group_id": ""
},
"cosmosdb_nosql_serverless": false,
"cosmosdb_nosql_serverless_data_readers": {},
"cosmosdb_nosql_serverless_settings": {
"containers": {}
},
"enable_blob_storage": false,
"enable_document_intelligence": false,
"enable_servicebus_queue": false,
"servicebus_queues": {
"default": {
"dead_lettering_on_message_expiration": true,
"dlq_manager_identities": {},
"dlq_reader_identities": {},
"max_delivery_count": 10,
"requires_duplicate_detection": false
}
}
}
no
is_experience_api Is this an Experience API bool false no
is_external_app Is this an external app bool false no
is_production Is this a production environment bool n/a yes
owner The name of the team that owns the resources string n/a yes
project_id The id of the project. This will be used to name the resources. string n/a yes
resource_location The location the resources will be deployed to. string "westus2" no
tags A map of tags to be applied to resources in the module map(string) n/a yes
tenant Deprecated — the Azure infra tenant is fixed to Corporate (see local.azure_tenant). Retained for backward compatibility with existing workspace variable sets (e.g. the Okta credentials variable set that injects tenant = "ext"), but no longer read by this module. string "Corporate" no

Outputs

Name Description
application_client_id n/a
application_id n/a
application_object_id n/a
application_principal_client_id n/a
application_principal_id n/a
application_principal_object_id n/a
cosmosdb_account_endpoint n/a
cosmosdb_account_id n/a
cosmosdb_account_name n/a
organization_name n/a
resource_group_name n/a
subscription_primary_key Primary key of the APIM subscription scoped to this API. Only populated when api_policy_type = "subscription_key".
subscription_secondary_key Secondary key of the APIM subscription scoped to this API. Only populated when api_policy_type = "subscription_key".
user_assigned_identity_clientid n/a
user_assigned_identity_id n/a
user_assigned_identity_principalid n/a

Resources

  • resource.azurerm_app_configuration_key.application_secrets (/terraform-docs/main.tf#310)
  • resource.azurerm_app_configuration_key.application_settings (/terraform-docs/main.tf#298)
  • resource.azurerm_key_vault_secret.Application_Secrets (/terraform-docs/main.tf#219)
  • resource.azurerm_role_assignment.Application_Secret_Permissions (/terraform-docs/main.tf#283)

View source on GitHub