Every Databricks workspace accumulates configuration decisions — access controls, network restrictions, compute policies and secret management. Reviewing those decisions manually does not scale across a shared platform. We need repeatable assessments and a release process for the scanner itself.
The Security Analysis Tool (SAT), published by Databricks Industry Solutions, analyses account and workspace configurations and provides recommendations against Databricks security best practices. Declarative Automation Bundles, formerly known as Databricks Asset Bundles (DABs), let us manage Databricks project resources and source files through version control and CI/CD. Together, they provide a practical foundation for deploying security assessment tooling consistently.
We treat SAT as a platform workload, not a notebook someone runs occasionally in production. That means promoting a reviewed release through DTAP — Development, Test, Acceptance and Production — with environment-specific identities, configuration and evidence. Azure DevOps or GitHub Actions orchestrates the release; neither replaces testing the assessment itself.
The Problem
A scanner deployed manually into production has the same weaknesses as any other manually managed workload. Configuration changes are difficult to review, updates lack a rehearsal environment, and a successful deployment can be mistaken for a successful assessment. We want to know both what was deployed and whether it assessed the intended scope.
This implementation review uses v0.8.0 as its baseline, not as the current latest release. The supplied release notes list 0.9.0, released on 5 August 2026. The template details below belong to v0.8.0 — review and test newer releases rather than assuming their generated configuration is identical.
The v0.8.0 release added live egress testing, per-user identity in Permissions Analysis, expanded secret scanning and 11 new checks. Those changes explain why SAT needs a release process: findings can change without any corresponding change in workspace configuration. We must distinguish scanner changes from changes in the security posture being assessed.
SAT is supplied for exploration purposes, AS-IS, without formal Databricks support SLAs. Bundles and CI/CD improve our deployment discipline — they do not change that support boundary or turn SAT into a compliance certification. Issues belong in the project’s GitHub issue tracker, not a Databricks support ticket.
Why It Matters for Platform Teams
We need two separate forms of evidence: deployment evidence and assessment evidence. A commit, validation result and deployment log explain what we released. A completed assessment, its scope and its accessible outputs explain what we actually checked.
DTAP lets us rehearse authentication, configuration changes and upgrades before they affect production security reporting. It does not require every environment to have identical security settings. Development and production may intentionally differ — we compare each environment against its approved baseline rather than demand blind parity.
Service principals support automation without depending on an employee’s account, but their permissions still need explicit design. The reviewed SAT bundle template sets a target-level run_as identity, which can be a user or service principal. An identity’s ability to deploy a job does not prove that the job can query every API needed by its checks.
Our preferred operating model is straightforward: version the deployment, assess on demand in lower environments, and enable recurring assessments only where there is an operational reason. Findings then become owned remediation work, not an unattended report. We keep assessment access separate from the write access needed to remediate platform configuration.
Use Case: Security Evidence for a Shared Airport Platform
Consider a hypothetical airport operator with autonomous product teams shipping operational pipelines into shared Azure Databricks workspaces. Centrally maintained Terraform modules establish platform controls, while teams own their pipeline releases. Security and audit teams need recurring evidence that workspace configuration still follows policy.
The assessment flow reads account and workspace configuration, writes SAT assessment data and exposes reports for authorised reviewers. Reviewed findings enter the platform remediation backlog, with an owner and an agreed treatment — fix, investigate or record an approved exception. Because the outputs expose identities and security configuration, their access model deserves the same scrutiny as the scanner’s credentials.
The usual approach breaks when an administrator installs SAT directly in production and later updates it by copying files. Teams cannot reliably reproduce the previous release, and reviewers cannot tell whether a changed finding reflects a workspace change or a scanner upgrade. A failed assessment can also leave an older report looking current.
We would promote a pinned SAT revision and reviewed deployment configuration through DTAP. Development proves installation and authentication; test checks coverage and output access; acceptance rehearses production-like permissions and networking. Production receives the same approved source revision, with its own settings and explicitly approved assessment scope.
The scope must respect Azure subscription boundaries: the installation documentation requires at least one SAT setup per Azure subscription. We would also check whether network restrictions require additional deployments within a subscription. DTAP labels alone do not prevent a lower-environment scanner from assessing production — the configured service principal’s workspace access must enforce that boundary.
We would measure assessment freshness, intended versus successfully assessed workspace coverage, assessment failures, remediation age and release recovery time. Approved exceptions remain separate from unresolved findings. A falling finding count is not a success metric unless coverage and check behaviour remain understood.
Implementation
1. Pin SAT and establish the release contract
Start from the upstream repository rather than a hand-built list of assumed directories. Record an approved commit and review the documentation and templates belonging to that revision. For a move from 0.7.x to 0.8.0, include the Upgrade Guide in that review.
set -euo pipefail
# Supply a reviewed, full commit SHA through the release process.
: "${SAT_COMMIT:?Set SAT_COMMIT to the approved upstream commit SHA}"
git clone https://github.com/databricks-industry-solutions/security-analysis-tool.git
cd security-analysis-tool
git checkout --detach "$SAT_COMMIT"
# Record the exact source revision and locate bundle-related files.
git rev-parse HEAD
find . -name 'databricks.yml*' -print
The checkout pins the source instead of following a moving branch. The file search helps reviewers inspect the selected revision rather than assume that a newer release preserves the same layout.
For v0.8.0, install.sh creates a Python environment, installs dabs/requirements.txt and starts dabs/main.py. That installer collects configuration, prepares secrets and calls dabs/setup.sh, which initialises and deploys the bundle. The installation documentation lists Python 3.9 or higher, an authenticated Databricks CLI profile, an account ID, a SQL warehouse for the SQL dashboard and workspace access to PyPI.
set -euo pipefail
# Run from the pinned repository checkout after reviewing prerequisites.
# The installer is interactive and deploys resources; this is not validation only.
bash ./install.sh
This is the reviewed baseline’s installation entry point, not an unattended CI recipe. Use it first in development to establish a working installation and understand its cloud-specific requirements.
The release contract should record the SAT commit, tested CLI version, deployment configuration revision, enabled assessments and intended workspace scope. It should also identify owners for upgrades, findings and recovery. The bundle documentation requires CLI v0.218.0 or above — that is a minimum, not proof that every SAT installation command works with that version.
2. Preserve the generated bundle before designing promotion
The v0.8.0 installer is not a source-control workflow by itself. Its setup script copies configs, notebooks, dashboards, app and lib into the template, generates a temporary project, deploys it and then removes that project. It also attempts to bind an existing Permissions Analysis app and deploys with --force-lock.
For repeatable CI/CD, we would maintain a reviewed adaptation that retains the generated project before cleanup. Preserve the complete source payload and resource definitions, not just databricks.yml. Do not copy the automatic lock override into routine deployment — investigate concurrent or interrupted deployments instead.
The generated baseline has one default target, sat, in production mode. For the command examples below, each DTAP stage uses a separately prepared bundle directory containing that default target and the stage’s approved settings. This avoids depending on an unverified target-selection command form.
bundle:
name: SAT
include:
- resources/*.yml
sync:
include:
- notebooks/**/*.py
- notebooks/**/*.sql
- notebooks/**/
- configs/**/*
- dashboards/**/*
- app/**/*
- lib/**/*
targets:
sat:
default: true
mode: production
workspace:
# Example host — replace with the selected environment's workspace URL.
host: https://adb-1234567890123456.7.azuredatabricks.net
root_path: /Applications/${bundle.name}/
run_as:
# Example application ID for the environment's service principal.
service_principal_name: "11111111-2222-3333-4444-555555555555"
This illustrates the reviewed template rendered for a service principal; it is not a complete SAT deployment without the included resources and files. Keep the baseline root path consistent with its resource templates, which reference notebooks under /Workspace/Applications/SAT/files.
The template schema accepts catalog, cloud, latest_lts, node_type, serverless, schedule settings, enable_brickhound and warehouse_id. These are template-generation inputs, not automatically bundle variables or runtime job parameters. SAT supports choosing a Unity Catalog catalog and schema, but a locally invented variable does not configure either unless the reviewed deployment consumes it.
If we later consolidate environments into named targets, we can express deployment-time values using the standard bundle variable mechanism:
bundle:
name: airport-security-assessment
variables:
assessment_catalog:
description: Environment-specific catalog intended for assessment outputs
targets:
dev:
variables:
assessment_catalog: airport_security_dev
test:
variables:
assessment_catalog: airport_security_test
acc:
variables:
assessment_catalog: airport_security_acc
prd:
variables:
assessment_catalog: airport_security_prd
This remains an illustrative platform overlay, not an upstream SAT configuration. It neither creates a catalog nor connects assessment_catalog to SAT’s generated resources.
Use bundle variables for deployment-time differences and job parameters only where the actual job supports per-run inputs. The job-parameter documentation distinguishes those lifecycles and warns against mixing job-level parameters with task-level base_parameters in the same job. We should not add guessed runtime parameters to SAT’s jobs.
3. Configure identities, scope and OAuth per environment
The Azure Databricks OAuth documentation supports OAuth machine-to-machine (M2M) authentication for unattended workspace operations. It uses a workspace host, client ID and client secret, and covers Databricks-managed service principals. Microsoft Entra-managed service principals have a separate authentication path.
set -euo pipefail
# The pipeline supplies values for the selected environment only.
: "${SAT_WORKSPACE_HOST:?Set the target workspace URL}"
: "${SAT_DEPLOY_CLIENT_ID:?Set the deployment service principal client ID}"
: "${SAT_DEPLOY_CLIENT_SECRET:?Set its Databricks OAuth secret}"
export DATABRICKS_HOST="$SAT_WORKSPACE_HOST"
export DATABRICKS_CLIENT_ID="$SAT_DEPLOY_CLIENT_ID"
export DATABRICKS_CLIENT_SECRET="$SAT_DEPLOY_CLIENT_SECRET"
# Do not enable shell tracing or print credentials.
databricks --version
These variables use the documented workspace-level OAuth configuration. The secret must be the appropriate Databricks OAuth secret — not an interchangeable Microsoft Entra application secret.
Keep credentials distinct per environment and store them in protected pipeline secret storage. Account-level OAuth operations use the account host and additionally require DATABRICKS_ACCOUNT_ID; workspace deployment credentials alone do not establish SAT’s account-analysis configuration. Follow the selected release’s cloud setup guide for the configured assessment service principal rather than assume pipeline authentication replaces it.
SAT uses its configured service principal to call account and workspace APIs. Add that principal only to the workspaces intended for assessment, and rerun initialisation after changing membership to update SAT’s workspace list. Test compute, storage and API access explicitly — the supplied sources do not establish a universal minimum-permission role.
For the initial deployment contract, we would keep the generated job’s run_as identity aligned with the environment’s deployment principal. Separating those identities can be a later design improvement, but it requires its own documented authorisation review. Do not assume that permission to deploy a job includes permission to assign another principal as its execution identity.
4. Validate, deploy and execute the reviewed job
Create a shared script at sat-deployment/ci/deploy.sh. Run it from the prepared directory containing databricks.yml, whose default sat target points to the selected environment. In this contract, SAT_TARGET is a pipeline environment label — it is not passed to the CLI as a bundle target selector.
#!/usr/bin/env bash
set -euo pipefail
: "${SAT_TARGET:?Set SAT_TARGET to dev, test, acc or prd}"
: "${SAT_CLI_VERSION_OUTPUT:?Set the approved CLI version output}"
: "${DATABRICKS_HOST:?Set the selected workspace URL}"
: "${DATABRICKS_CLIENT_ID:?Set the selected deployment client ID}"
: "${DATABRICKS_CLIENT_SECRET:?Set the selected Databricks OAuth secret}"
case "$SAT_TARGET" in
dev|test|acc|prd) ;;
*) printf 'Unsupported SAT environment: %s\n' "$SAT_TARGET" >&2; exit 1 ;;
esac
# Compare with output captured from the approved binary, not a guessed format.
actual_cli_version="$(databricks --version)"
if [[ "$actual_cli_version" != "$SAT_CLI_VERSION_OUTPUT" ]]; then
printf 'Databricks CLI differs from the approved toolchain\n' >&2
exit 1
fi
# The prepared bundle has one default target for this environment.
databricks bundle validate
databricks bundle deploy
These commands use the bundle’s default target and avoid automatic lock overrides. Before invoking the script, the release process must verify that the prepared configuration and injected host both belong to the selected environment.
Capture databricks --version from the approved CLI binary and store that output in the release configuration. Test that the comparison accepts the approved binary and rejects a different version. This is a runner consistency check, not proof of binary integrity.
The reviewed driver resource key is sat_driver; its display name is SAT Driver Notebook. The template runs the security analysis driver notebook, despite naming its task sat_initializer. Do not infer a separate initialisation job from that task name.
set -euo pipefail
# Run from the same prepared bundle directory used for deployment.
# sat_driver is the reviewed v0.8.0 job resource key, not its display name.
databricks bundle run sat_driver
The bundle documentation supports running jobs by resource key, and the supplied template establishes this key. Test the command against the retained, generated configuration before adopting it as a release gate.
A successful run still needs output inspection. Confirm assessment freshness, intended workspace coverage and authorised report access; preserve API and connection failures rather than interpreting them as clean results. When scope changes, follow the documented initialisation procedure and verify that the workspace list updates.
5. Connect the shared script to Azure DevOps or GitHub Actions
Use one CI platform as the release authority. Each stage should prepare the environment-specific bundle from the same approved source revision, inject only that environment’s credentials and run bash ci/deploy.sh from sat-deployment. Retain the rendered configuration and deployment evidence, excluding secrets.
For Azure DevOps, test credential mapping, variable-group access and environment selection in the intended project. For GitHub Actions, test environment selection, secret resolution and simultaneous deployment handling in the intended repository. These are integration requirements — not claims that a particular provider setting guarantees release ordering.
We require tested approval controls for acceptance and production as platform policy. Use a runner containing the pinned toolchain rather than downloading an unpinned installation script during deployment. Require assessment evidence before promotion, and ensure all stages use the same approved SAT source revision.
6. Rehearse schedules, upgrades and recovery
Inspect the generated schedules rather than trust one set of defaults. In v0.8.0, the template schema describes a driver schedule of Monday, Wednesday and Friday at 08:00 UTC and a daily scanner schedule at 10:00 UTC. However, dabs/main.py supplies daily 08:00 fallback expressions for both jobs — those paths are not equivalent.
Keep lower-environment assessments on demand as a deliberate deployment choice. Where recurring runs are needed, review the rendered expressions, timezone and overlap risk. The schema describes offsetting the scanner to avoid Delta write conflicts on shared control tables; that is a reason to inspect actual schedules, not assume the installer guarantees separation.
SAT does not auto-upgrade. For 0.7.x to 0.8.0, the Upgrade Guide documents a Permissions Analysis consent change, additional checks, Azure’s exclusion from IA-9 and Environment v5 for serverless jobs and the app. Review these changes against the previous baseline before production promotion.
Keep the previous source and configuration revisions available, but do not assume redeploying old code reverses stored-data or configuration changes. Test recovery and record whether finding differences come from changed checks, scanner behaviour or platform configuration. Recovery should restore trusted reporting, not merely recreate jobs.
Pitfalls and When Not to Use It
A successful scan is not proof of compliance. SAT provides recommendations and is intended as read-only analysis of workspace and account configuration. It does not replace audit logs, incident detection, penetration testing or formal attestation; some checks also require self-assessment because suitable APIs are unavailable.
Network restrictions can change deployment topology. SAT on classic or serverless compute cannot analyse destinations protected by IP access lists unless access from the SAT workspace is allowed. The installation documentation also states that serverless SAT cannot access other workspaces when egress controls are configured in its workspace — a separate SAT deployment in the target workspace is then required.
Blocked egress can be the expected result. In v0.8.0, NS-14 probes public destinations from the driver compute. “Egress blocked” is the pass state on a properly restricted network, not an installation failure.
Restricted build networks and restricted assessment networks are different problems. The air-gapped bundle documentation describes using a downloaded Databricks CLI Docker image for bundle tooling. Mirror a reviewed version where required; that does not establish that every SAT dependency or assessment works without internet access.
Security outputs need their own access model. Test storage permissions, report visibility and Permissions Analysis access. Its v0.8.0 on-behalf-of-user authentication means Unity Catalog enforces the caller’s grants — deploying the app does not automatically give every reviewer access to its analysis tables.
Automation does not provide upstream support. If the organisation requires a vendor SLA for the assessment tool itself, SAT’s support model may not fit. A short exploratory assessment may also need less automation than four full environments, provided its scope, freshness and limitations are recorded.
Key Takeaways
- Pin a reviewed baseline, not “latest”. The examples review v0.8.0; the supplied release notes also list 0.9.0. Record the exact SAT commit and tested toolchain.
- Preserve the complete deployment. The baseline installer generates and removes a temporary bundle — repeatable CI/CD needs a retained, reviewed project and its assets.
- Separate deployment from assessment evidence. Validation and deployment do not prove coverage, freshness or successful API access.
- Enforce scope through identities and networking. DTAP labels alone do not isolate assessments, and Azure subscription boundaries affect deployment planning.
- Inspect rendered schedules and rehearse upgrades. Installer fallbacks and template defaults differ; changed checks can alter findings without platform changes.
- Respect SAT’s limits. Protect assessment outputs, assign remediation owners and account for the project’s AS-IS, no-SLA support model.
Declarative Automation Bundles: A Practical Guide to CI/CD in Databricks
Use Declarative Automation Bundles to replace ad-hoc Databricks deployment scripts with versioned configuration, explicit targets and tested CI/CD.
Databricks · 11 minDatabricks Data Contracts — Enforce Before You Publish
Build a Databricks data contract gate with explicit schemas, Delta constraints and DTAP tests, and decide what must pass before a dataset is published.
Case study · Cloud Data Platform EngineeringHow we did this at Schiphol Data Platform →
Scaling Databricks and AI adoption with Terraform inner sourcing across Schiphol's Data, AI & Analytics organisation.