Configuration Reference
All configuration is provided through environment variables with the VENDING_ prefix.
Variables can also be placed in a .env file in the project root (loaded automatically by Pydantic Settings).
Copy .env.example to .env and fill in the values before starting the service.
For guidance on which variables are secrets and how to handle them securely in each deployment context, see secrets.md.
Azure credentials
| Variable | Default | Description |
|---|---|---|
VENDING_AZURE_TENANT_ID |
(required) | Azure Active Directory tenant ID. Must always be set. |
VENDING_AZURE_CLIENT_ID |
"" |
Service principal application (client) ID. Leave empty to use Managed Identity. |
VENDING_AZURE_CLIENT_SECRET |
"" |
Service principal secret. Required when VENDING_AZURE_CLIENT_ID is set. |
When both VENDING_AZURE_CLIENT_ID and VENDING_AZURE_CLIENT_SECRET are populated the service uses ClientSecretCredential. If either is empty, ManagedIdentityCredential is used instead. Managed Identity is recommended for all Azure-hosted deployments.
Management group placement
| Variable | Default | Description |
|---|---|---|
VENDING_ROOT_MANAGEMENT_GROUP |
ITL |
Name of the root/default management group. Used as a fallback when no itl-environment tag is present. |
VENDING_ENVIRONMENT_MG_MAPPING |
(JSON — see below) | JSON string mapping environment names to management group names. Supports unlimited custom environments. |
Environment → Management Group mapping
VENDING_ENVIRONMENT_MG_MAPPING accepts a JSON object where each key is an itl-environment tag value and each value is the target management group name.
Default mapping:
VENDING_ENVIRONMENT_MG_MAPPING='{
"production": "ITL-Production",
"staging": "ITL-Staging",
"development": "ITL-Development",
"sandbox": "ITL-Sandbox"
}'
Any number of additional environments can be added:
VENDING_ENVIRONMENT_MG_MAPPING='{
"production": "ITL-Production",
"staging": "ITL-Staging",
"development": "ITL-Development",
"sandbox": "ITL-Sandbox",
"acceptance": "ITL-Acceptance",
"test": "ITL-Test",
"customer-a": "CustomerA-Prod",
"customer-b": "CustomerB-Prod"
}'
If the itl-environment tag value is not found in the mapping, the subscription falls back to the sandbox management group (or ITL-Sandbox if that key is also absent from the mapping). If the JSON value is malformed, the entire mapping falls back to {"sandbox": "ITL-Sandbox"}.
RBAC role assignments
The following variables control which Azure AD principals receive default role assignments on each new subscription. Leave a variable empty to skip the corresponding role assignment.
| Variable | Default | Role granted | Description |
|---|---|---|---|
VENDING_PLATFORM_SPN_OBJECT_ID |
"" |
Owner | Object ID of the ITL platform service principal. |
VENDING_OPS_GROUP_OBJECT_ID |
"" |
Contributor | Object ID of the ITL Operations Azure AD group. |
VENDING_SECURITY_GROUP_OBJECT_ID |
"" |
Security Reader | Object ID of the ITL Security Azure AD group. |
VENDING_FINOPS_GROUP_OBJECT_ID |
"" |
Cost Management Reader | Object ID of the ITL FinOps Azure AD group. |
Note: These values are Azure AD object IDs, not display names or client IDs. You can look up object IDs in the Azure Portal under Azure Active Directory → Groups / Enterprise applications.
Budget alerts
| Variable | Default | Description |
|---|---|---|
VENDING_DEFAULT_ALERT_EMAIL |
"" |
Fallback e-mail address for budget alert notifications when the itl-owner subscription tag is not set. If empty and the tag is absent, no notification contact is configured. |
Authorization service
| Variable | Default | Description |
|---|---|---|
VENDING_AUTHORIZATION_SERVICE_URL |
http://itl-authorization:8004 |
Base URL of the internal ITL Authorization service. Used to attach the ITL Foundation Policy Initiative to new subscriptions. |
Keycloak
| Variable | Default | Description |
|---|---|---|
VENDING_KEYCLOAK_URL |
http://keycloak:8080 |
Base URL of the Keycloak identity provider. |
VENDING_KEYCLOAK_REALM |
ITL |
Keycloak realm name. |
Event Grid
| Variable | Default | Description |
|---|---|---|
VENDING_EVENT_GRID_SAS_KEY |
"" |
Shared-access-signature key injected by Event Grid as the aeg-sas-key header. When set, the webhook rejects any request whose header does not match. Leave empty to disable SAS key validation. |
VENDING_EVENT_GRID_TOPIC_ENDPOINT |
"" |
Endpoint URL of an Azure Event Grid Custom Topic. When set, the service publishes an outbound ITL.SubscriptionVending.SubscriptionProvisioned event after each provisioning run (Step 6). Leave empty to disable outbound notifications. |
Feature flags
| Variable | Default | Description |
|---|---|---|
VENDING_MOCK_MODE |
false |
Set to true to mount the POST /webhook/test mock endpoint. Intended for local development and integration testing only. Never enable in production. |
Extensions
These variables are read by the built-in extension modules in extensions/. They are optional — leave them unset to disable the corresponding extension.
Webhook notify (extensions/webhook_notify.py)
Posts the provisioning result as JSON to a plain HTTPS endpoint after each workflow run.
| Variable | Default | Description |
|---|---|---|
VENDING_WEBHOOK_URL |
"" |
HTTPS endpoint to POST to. Leave empty to disable. |
VENDING_WEBHOOK_SECRET |
"" |
Sent as the X-Webhook-Secret header. Leave empty to omit the header. |
VENDING_WEBHOOK_TIMEOUT |
10 |
Request timeout in seconds. |
API notify (extensions/api_notify.py)
Posts the provisioning result as JSON to a REST API endpoint using Bearer token authentication.
| Variable | Default | Description |
|---|---|---|
VENDING_API_NOTIFY_URL |
"" |
API endpoint to POST to. Leave empty to disable. |
VENDING_API_NOTIFY_TOKEN |
"" |
Bearer token value sent as Authorization: Bearer <token>. Leave empty to omit the header. |
VENDING_API_NOTIFY_TIMEOUT |
10 |
Request timeout in seconds. |
Both extensions are auto-discovered at startup. They activate when their controlling env var is set (
VENDING_WEBHOOK_URLorVENDING_API_NOTIFY_URLrespectively). No code changes are required — set the env var and the extension registers itself.
ServiceNow check (extensions/servicenow_check.py)
Gate check that validates a ServiceNow ticket before any provisioning step runs. The check is read-only and runs even during dry-run.
| Variable | Default | Description |
|---|---|---|
VENDING_SNOW_INSTANCE |
"" |
ServiceNow instance hostname (e.g. myco.service-now.com). Leave empty to disable. |
VENDING_SNOW_USER |
"" |
ServiceNow username for basic authentication. |
VENDING_SNOW_PASSWORD |
"" |
ServiceNow password for basic authentication. |
VENDING_SNOW_TABLE |
sc_req_item |
Table to query. Use change_request for CHG tickets. |
VENDING_SNOW_REQUIRE_STATE |
approved |
Required value of the approval or state field. Set to "" to check existence only. |
VENDING_SNOW_TIMEOUT |
10 |
HTTP timeout in seconds. |
ServiceNow feedback (extensions/servicenow_feedback.py)
Provisioning step that PATCHes the ServiceNow ticket with the outcome after STEP_NOTIFY. Feedback failures are non-fatal.
| Variable | Default | Description |
|---|---|---|
VENDING_SNOW_INSTANCE |
"" |
ServiceNow instance hostname. Shared with check extension. Leave empty to disable. |
VENDING_SNOW_USER |
"" |
ServiceNow username. Shared with check extension. |
VENDING_SNOW_PASSWORD |
"" |
ServiceNow password. Shared with check extension. |
VENDING_SNOW_TABLE |
sc_req_item |
Table to update. |
VENDING_SNOW_SUCCESS_STATE |
"" |
state value to set when provisioning succeeds (e.g. 3 = Closed Complete). Leave empty to not change state. |
VENDING_SNOW_FAILURE_STATE |
"" |
state value to set when provisioning fails (e.g. 4 = Closed Incomplete). Leave empty to not change state. |
VENDING_SNOW_TIMEOUT |
10 |
HTTP timeout in seconds. |
Retry strategy (retry/)
Controls how the service handles provisioning failures. Select a strategy via VENDING_RETRY_STRATEGY.
| Strategy | Behaviour |
|---|---|
none (default) |
Runs the provisioning workflow inline and always returns 200 OK to Event Grid. Failures are logged but not retried. |
dead_letter |
Runs inline but returns 500 on failure, causing Event Grid to retry according to its own retry policy and eventually dead-letter the event. |
queue |
Immediately enqueues a ProvisioningJob to Azure Storage Queue and returns 200. A separate worker (POST /worker/process-job) processes jobs asynchronously with configurable max delivery and dead-letter support. |
| Variable | Default | Description |
|---|---|---|
VENDING_RETRY_STRATEGY |
none |
Retry strategy: none, dead_letter, or queue. |
VENDING_STORAGE_ACCOUNT_NAME |
"" |
Azure Storage Account name. Required when VENDING_RETRY_STRATEGY=queue. The Managed Identity must have Storage Queue Data Contributor on this account. |
VENDING_PROVISIONING_QUEUE_NAME |
provisioning-jobs |
Name of the work queue. Created automatically on first dispatch if it does not exist. |
VENDING_PROVISIONING_DLQ_NAME |
provisioning-jobs-deadletter |
Name of the dead-letter queue. Created automatically alongside the work queue. |
VENDING_QUEUE_MAX_DELIVERY_COUNT |
5 |
Number of failed deliveries before the worker moves a message to the dead-letter queue. |
VENDING_QUEUE_VISIBILITY_TIMEOUT |
30 |
Seconds a message remains invisible in the queue after a failed attempt before it reappears for retry. |
VENDING_WORKER_SECRET |
"" |
Shared secret validated via the x-worker-secret / x-replay-secret header on POST /worker/process-job and POST /webhook/replay. Leave empty to disable header authentication (use only on private networks). |
Soft dependency: The
azure-storage-queuepackage is required whenVENDING_RETRY_STRATEGY=queue. It is wrapped in atry/exceptimport — the service starts normally without it, but thequeuestrategy will raise aRuntimeErrorat first dispatch if the package is missing. Install it withpip install azure-storage-queue.
Tag-based provisioning
Azure subscription tags are read at the start of the provisioning workflow. They override defaults derived from environment variables.
| Tag | Expected values | Effect | Fallback |
|—–|—————-|——–|———|
| itl-environment | Any string (e.g. production, staging, acceptance, customer-a) | Selects the target management group via VENDING_ENVIRONMENT_MG_MAPPING. Also determines policy enforcement mode (Default for production, DoNotEnforce for all others). | sandbox MG |
| itl-aks | true, false | Marks the subscription for AKS/Flux base chart installation. | false |
| itl-budget | Integer (e.g. 500) | Creates a monthly Azure Cost Management budget at the specified EUR amount with e-mail alerts at 80 % and 100 %. | No budget alert |
| itl-owner | E-mail address | Contact address for budget alert notifications. Overrides VENDING_DEFAULT_ALERT_EMAIL. | VENDING_DEFAULT_ALERT_EMAIL || itl-snow-ticket | Ticket number (e.g. RITM0041872) | Validated by the ServiceNow gate check before provisioning starts. Required when servicenow_check extension is active. Updated with the provisioning outcome by the servicenow_feedback extension. | (gate skipped if absent and SNOW not configured) |
Invalid tag values are silently ignored and the corresponding default is used, so provisioning always continues even when tags are malformed.
Configurable tag key names
The tag key names shown above are defaults. You can override them to match your own tagging conventions using the following environment variables:
| Environment variable | Default value | Description |
|---|---|---|
VENDING_TAG_ENVIRONMENT |
itl-environment |
Tag key used to determine the target environment / management group |
VENDING_TAG_AKS |
itl-aks |
Tag key used to enable AKS/Flux setup |
VENDING_TAG_BUDGET |
itl-budget |
Tag key for the monthly budget amount in EUR |
VENDING_TAG_OWNER |
itl-owner |
Tag key for the budget alert e-mail address |
VENDING_TAG_SNOW_TICKET |
itl-snow-ticket |
Tag key for the ServiceNow ticket number |
For example, to use myorg-environment instead of itl-environment:
VENDING_TAG_ENVIRONMENT=myorg-environment
VENDING_TAG_AKS=myorg-aks
VENDING_TAG_BUDGET=cost-budget
VENDING_TAG_OWNER=cost-owner