The scanner runs in your subscription as Container Apps Jobs with a user-assigned managed identity. A scheduled coordinator job starts every 15 minutes, and an event-driven worker job scales with the queue from zero up to max_workers. The scanner reads Blob and Azure Files storage, databases and storage activity where they are. Only findings, classifications, counts, identifiers and run status leave.

Before you start

  • Terraform 1.11 or later, hashicorp/azurerm 5.5 or later within 5.x, hashicorp/random and hashicorp/time.
  • Rights to create role assignments. The identity applying the module needs Owner, or Contributor plus User Access Administrator, on the resource group and on every scanned subscription or management group.
  • Resource providers registered in the subscription the scanner runs in: Microsoft.App, Microsoft.OperationalInsights, Microsoft.KeyVault, Microsoft.Storage and Microsoft.ManagedIdentity.
  • An organization API key (tg_). See Before you deploy.

Deploy with Terraform

1

Start the wizard

In TigerGate, go to DSPM → Deployments → Add deployment and choose Azure subscription. Review the roles the module grants.
2

Enter the subscription and network

Enter the name, the Subscription id, the Location the scanner runs in, the TigerGate region and the Resource group for the scanner. To reach private storage and databases, enter an Infrastructure subnet id. Choose the profile, schedule, max workers and whether to share masked samples, then select Create deployment and enrollment token.
3

Copy the token and the Terraform

Copy the enrollment token (shown once), choose the organization API key, and copy main.tf and terraform.tfvars.
4

Apply

az account show                # the subscription you are about to deploy into
terraform init
terraform plan
terraform apply
5

Register

The coordinator registers within 15 minutes. To start it now, run the command that terraform output -raw run_now_command prints (az containerapp job start ...).
provider "azurerm" {
  features {}
  subscription_id = "00000000-0000-0000-0000-000000000000"
}

module "tigergate_dspm" {
  source = "https://releases.tigergate.dev/dspm/<version>/tigergate-dspm-azure.zip"

  tigergate_api_url   = "https://api.eu.tigergate.dev"
  tigergate_api_key   = var.tigergate_api_key # tg_..., your organization's API key
  enrollment_token    = var.enrollment_token  # tgdspm_..., from the console
  location            = "westeurope"
  resource_group_name = "tigergate-dspm"
}
The module writes the token and the key to its own Key Vault as write-only values. To keep the key out of Terraform, pass an existing secret as tigergate_api_key_key_vault_secret_id (and the token as enrollment_token_key_vault_secret_id). The vault must use Azure RBAC, and you must grant Key Vault Secrets User on each secret to the scanner_principal_id output. Without that grant on the API key, every call fails.

What the module creates

ResourcePurpose
Managed identity <prefix>-scannerThe identity of both jobs. It has no secret or certificate.
Role assignmentsRead roles on the scanned scopes, and runtime roles on the module’s own queue, table and secrets.
Storage accountThe queues shards and shards-poison and the state table dspmstate. Shared keys are disabled.
Key Vaultenrollment-token, tigergate-api-key and scanner-credential. Soft delete for 7 days, no purge protection.
Log Analytics workspace <prefix>-logsScanner logs, kept for log_retention_days.
Container Apps environment and jobs<prefix>-coordinator (cron */15 * * * *) and <prefix>-worker (event-driven).

Permissions

RoleScopeWhy
ReaderEach scanned subscription and management groupInventory and posture. Reader has no data-plane access and no listKeys.
Storage Blob Data ReaderThe scanned scopes, or only content_storage_account_idsRead blob content.
Storage File Data Privileged ReaderThe same scopes (enable_file_content)Read Azure Files shares with the identity’s token. Read-only.
Storage Queue Data Contributor, Storage Table Data ContributorThe module’s queues and table onlyThe runtime’s work queue and state.
Key Vault Secrets User, Key Vault Secrets OfficerThe module’s secrets onlyRead the token and key; write the scanner credential.
Nothing grants write access to your data, and the module grants no database role. For database content:
  • Azure SQL, SQL Managed Instance, Synapse, PostgreSQL and MySQL flexible servers: create a database user for the scanner’s managed identity with read-only grants (Microsoft Entra authentication). The user is tigergate_dspm unless the deployment’s Database access settings name another. Or keep a login in a Key Vault secret and name it there.
  • Cosmos DB (NoSQL API): assign Cosmos DB Built-in Data Reader to the identity. This is a Cosmos DB SQL role assignment, made with the Azure CLI or ARM, not in the portal’s access control pane.
  • NFS shares and NetApp Files volumes are read over NFS from the scanner’s subnet. An SMB share can be read over SMB with a Key Vault login named under File shares (Azure Files).
Without these grants, those stores get inventory and posture only, and preflight and the run’s store errors name the missing grant.

Networking

  • Default: Azure-managed networking with outbound internet. The jobs accept no inbound traffic.
  • infrastructure_subnet_id: puts the environment in your VNet, on a /27 or larger subnet delegated to Microsoft.App/environments. Use it to reach private endpoints and to route egress through your NAT gateway or firewall. Allow outbound HTTPS to the TigerGate API host, *.blob.core.windows.net, *.file.core.windows.net, *.queue.core.windows.net, *.table.core.windows.net, *.vault.azure.net, management.azure.com, api.loganalytics.io and login.microsoftonline.com, and to the databases and shares in scope (TCP 1433, 5432, 3306, 2049 and 445, and *.documents.azure.com for Cosmos DB).
  • Storage account firewalls: an account that allows only selected networks must allow the scanner’s subnet or its NAT IP. Otherwise its blobs fail with access_denied.
  • Private runtime storage: set storage_public_network_access = "Disabled" when you add private endpoints for the runtime storage account’s queue and table services yourself.
  • No internet egress: copy the image to your registry, set scanner_image and registry_server, and grant AcrPull to the scanner_principal_id output.

Several subscriptions

List subscriptions in scan_subscription_ids, or management groups in scan_management_group_ids to cover every subscription below them, including ones created later. One deployment scans all of them from its location. You can also add subscriptions the identity can read on the deployment’s Configuration tab (More subscriptions in scope).

Edge cases

  • MissingSubscriptionRegistration on apply: run az provider register --namespace Microsoft.App (and the other providers listed above).
  • Role assignment delay: Azure role assignments can take minutes to apply. A first run that fails with access_denied right after apply recovers on the next tick.
  • Customer managed keys: Azure Storage decrypts server-side, so blobs under a customer managed key need no extra grant.
  • Archive tier blobs cannot be read without rehydration and are reported as unreadable, not clean.
  • Immutable containers and legal holds do not affect reading. The scanner never writes.
  • Soft-deleted vaults: names carry a random suffix, so a redeploy never collides with a vault in its 7-day soft-delete window.

Cost

The Consumption profile bills only while a job runs: a few seconds per tick for the coordinator, and the workers while there are shards. Fixed costs are Log Analytics, the runtime storage account and Key Vault operations. Blob reads are billed as read transactions on the scanned accounts.

Operate the deployment

  • Rotate the API key: add a new version to the secret in the api_key_secret_id output, or apply a new tigergate_api_key with tigergate_api_key_version raised by one. No redeploy is needed.
  • Logs: the Log Analytics workspace in the log_analytics_workspace_id output, table ContainerAppConsoleLogs_CL.
  • Remove: select Revoke on the deployment, then terraform destroy.