A Model Endpoint Reached by Identity, not a Key
custom_subdomain_name looks cosmetic and decides everything: without it Entra ID auth does not work and no private endpoint can attach, so the account is silently key-only and public - and it is ForceNew. Restricting outbound access is the data-loss-prevention control for an OpenAI account.
Verification
Static-verifiedPassed: validated and lint-clean (provider-schema-validated for AWS/Azure/GCP; Terraform-language lint elsewhere).
Conformance
- Static validation (fmt · validate · tflint)
- Security scan clean (Checkov)
- Plan tests (mocked: validation rules · outputs)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live test pending (no cloud run yet)
Last verified 2026-09-13 · how we verify
Use it from the registry
terraform · opentofumodule "cognitive_services" {
source = "www.iac-bazaar.com/iac-bazaar/azure-cognitive-services/azure"
version = "1.0.0"
}Needs a registry token from /account/tokens. The module itself is free; the account is what identifies you. Full setup: registry docs.
Inputs & outputs
Create a free account to read this module's contract
The declared contract - every input name, type, default and description, plus every output - is shown to signed-in accounts, not to anonymous visitors.
A free account sees the contract of every module in the catalogue. There is no subscription and nothing to buy - the modules are free to download, and they run under Vizier.
Documentation
azure-cognitive-services
An Azure AI Services account that can be reached with an identity rather than a
key, and not from the whole internet. Works with Terraform and OpenTofu
(>= 1.6), azurerm provider >= 4.0, < 5.0.
custom_subdomain_name looks optional and decides everything. Without it
the account answers on the shared regional endpoint, and on that endpoint
Entra ID token authentication does not work and a private endpoint cannot be
attached. So omitting one field that reads like a cosmetic choice silently
produces a key-only, internet-facing service, whatever else you configured.
It is also ForceNew - adding it later recreates the account, taking the
endpoint your clients are configured with. This module requires it.
The customer-managed key is attached as a separate resource, not an inline block. azurerm offers both, and the inline one has an ordering problem you cannot configure your way out of: the account must exist before its managed identity exists, the identity must exist before Key Vault can grant it access, and the key cannot be attached before that grant. The separate resource splits that into two steps with the grant in between - which is also the shape a configuration scanner can follow from account to key.
local_auth_enabled defaults to true. The two API keys are bearer tokens
with no identity attached: every caller looks the same in the logs, there is no
per-caller revocation, and rotating means rotating for everybody at once. With a
custom subdomain in place, Entra ID gives you RBAC and an audit trail with a
name in it.
public_network_access_enabled defaults to true. For a model endpoint that
is a public service holding whatever your users type into it.
outbound_network_access_restricted defaults to false, which matters for
the features that fetch things: "on your data" and similar retrieval settings
let the service call URLs, and unrestricted means it may call any of them.
Restricting outbound access is the data-loss-prevention control. For an
OpenAI account specifically, it is what stops a retrieval feature - or a prompt
that talks one into a fetch - from posting your data to an address you never
listed. A precondition refuses an unrestricted OpenAI account unless
accept_no_dlp says so; other account kinds are left alone, because demanding
an FQDN list from all of them would break more than it protects.
Smaller things: a precondition refuses a Deny network ACL with no rules
and no private endpoint, which would leave the account reachable by nothing at
all; and another refuses restricted outbound access with an empty FQDN list,
which breaks every retrieval feature silently.
Verification
Static validation runs tofu fmt, init, validate, tflint and checkov.
This module has not yet had a live test, so it is published as statically
validated with its live test pending and does not carry the live-tested mark.
Usage code & full reference need an account
The complete copy-paste usage, the full input/output reference, and operational notes are free with an account - shown here and bundled in the download. Sign in and this section fills in.
- Usage
- Wiring the customer-managed key