<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Managing &amp;quot;Secret&amp;quot; Injection in DABs across Dev/Stage/Prod in Data Engineering</title>
    <link>https://community.databricks.com/t5/data-engineering/managing-quot-secret-quot-injection-in-dabs-across-dev-stage/m-p/169233#M56060</link>
    <description>&lt;P&gt;Hi Khasim,&lt;/P&gt;&lt;P&gt;No secret value ever goes into databricks.yml. Bundle variables get resolved at deploy time and rendered into the job definition in the workspace, so anyone who can open the job can read them. Only names and references live in the bundle.&lt;/P&gt;&lt;P&gt;Second, let the bundle own the secret containers, one per target. Two ways to do that today.&lt;/P&gt;&lt;P&gt;The classic route is secret scopes as a bundle resource (CLI 0.252 or newer):&lt;/P&gt;&lt;P&gt;resources:&lt;BR /&gt;secret_scopes:&lt;BR /&gt;ingestion:&lt;BR /&gt;name: ingestion-secrets&lt;BR /&gt;permissions:&lt;BR /&gt;- level: READ&lt;BR /&gt;group_name: data-engineers&lt;/P&gt;&lt;P&gt;On Azure we set backend_type: AZURE_KEYVAULT and keyvault_metadata (dns_name and resource_id) pointing to a different Key Vault per target, so values never touch the bundle or the CI runner. On AWS we keep Databricks-backed scopes and run databricks secrets put-secret right after bundle deploy, pulling the values from the pipeline's own secret store. Bundle owns the scope and ACLs, pipeline owns the values.&lt;/P&gt;&lt;P&gt;The newer route is Unity Catalog secrets as a bundle resource, added in CLI 1.12 last month:&lt;/P&gt;&lt;P&gt;resources:&lt;BR /&gt;secrets:&lt;BR /&gt;ingestion_api_key:&lt;BR /&gt;catalog_name: ${var.catalog}&lt;BR /&gt;schema_name: secrets&lt;BR /&gt;name: ingestion_api_key&lt;BR /&gt;value: ${var.ingestion_api_key}&lt;BR /&gt;grants:&lt;BR /&gt;- principal: data-engineers&lt;BR /&gt;privileges: [READ_SECRET]&lt;/P&gt;&lt;P&gt;The value has to be a variable reference. If you type a literal the CLI stops you with "Secret value must be a variable reference... Plain text secret values are not allowed". In CI you set BUNDLE_VAR_ingestion_api_key from your pipeline secrets and the value exists only there and in UC. Jobs read it with dbutils.secrets.get(catalog=..., schema=..., key=...). Two things to know before picking this: it needs DBR 17.3 LTS or serverless environment 4, and it doesn't work on SQL warehouses, init scripts or spark_env_vars. If you still need the double-brace secrets syntax in cluster env vars, keep those on scopes.&lt;/P&gt;&lt;P&gt;Third, jobs reference the scope or the catalog.schema, never the value. We pass the scope name as a job parameter with ${resources.secret_scopes.ingestion.name} and call dbutils.secrets.get at runtime.&lt;/P&gt;&lt;P&gt;Parity then takes care of itself. Same names in every target, and the only thing that changes is the backing vault or the value CI injects. Each target deploys with its own service principal, so dev can't read prod even by accident.&lt;/P&gt;&lt;P&gt;One more thing worth keeping an eye on: UC external secrets, where a schema is backed directly by AWS Secrets Manager or Azure Key Vault, is in Beta right now. We haven't moved production to it yet but that is where I expect this to land.&lt;/P&gt;&lt;P&gt;Hope it helps, happy to share more detail on the CI side if useful.&lt;/P&gt;</description>
    <pubDate>Sun, 20 Sep 2026 11:26:49 GMT</pubDate>
    <dc:creator>ThomazNeto</dc:creator>
    <dc:date>2026-09-20T11:26:49Z</dc:date>
    <item>
      <title>Managing "Secret" Injection in DABs across Dev/Stage/Prod</title>
      <link>https://community.databricks.com/t5/data-engineering/managing-quot-secret-quot-injection-in-dabs-across-dev-stage/m-p/169191#M56053</link>
      <description>&lt;P&gt;Hi everyone, I am fully moving our team to Databricks Asset Bundles (DABs) for CI/CD, but I’m struggling with the "Secret" management pattern.&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;How are you handling the injection of secrets (like API keys for ingestion) into DABs without hardcoding anything in the databricks.yml?&lt;/LI&gt;&lt;LI&gt;Do you use Databricks Secret Scopes referenced via environment variables in the bundle, or are you pulling them dynamically from an external vault (e.g., KeyVault/Secrets Manager) during the deploy phase?&lt;/LI&gt;&lt;LI&gt;What is the cleanest way to maintain "Environment Parity" for these secrets without having to manually configure scopes in each workspace?&lt;/LI&gt;&lt;/OL&gt;</description>
      <pubDate>Sat, 19 Sep 2026 16:02:36 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/managing-quot-secret-quot-injection-in-dabs-across-dev-stage/m-p/169191#M56053</guid>
      <dc:creator>Khasim_1</dc:creator>
      <dc:date>2026-09-19T16:02:36Z</dc:date>
    </item>
    <item>
      <title>Re: Managing "Secret" Injection in DABs across Dev/Stage/Prod</title>
      <link>https://community.databricks.com/t5/data-engineering/managing-quot-secret-quot-injection-in-dabs-across-dev-stage/m-p/169233#M56060</link>
      <description>&lt;P&gt;Hi Khasim,&lt;/P&gt;&lt;P&gt;No secret value ever goes into databricks.yml. Bundle variables get resolved at deploy time and rendered into the job definition in the workspace, so anyone who can open the job can read them. Only names and references live in the bundle.&lt;/P&gt;&lt;P&gt;Second, let the bundle own the secret containers, one per target. Two ways to do that today.&lt;/P&gt;&lt;P&gt;The classic route is secret scopes as a bundle resource (CLI 0.252 or newer):&lt;/P&gt;&lt;P&gt;resources:&lt;BR /&gt;secret_scopes:&lt;BR /&gt;ingestion:&lt;BR /&gt;name: ingestion-secrets&lt;BR /&gt;permissions:&lt;BR /&gt;- level: READ&lt;BR /&gt;group_name: data-engineers&lt;/P&gt;&lt;P&gt;On Azure we set backend_type: AZURE_KEYVAULT and keyvault_metadata (dns_name and resource_id) pointing to a different Key Vault per target, so values never touch the bundle or the CI runner. On AWS we keep Databricks-backed scopes and run databricks secrets put-secret right after bundle deploy, pulling the values from the pipeline's own secret store. Bundle owns the scope and ACLs, pipeline owns the values.&lt;/P&gt;&lt;P&gt;The newer route is Unity Catalog secrets as a bundle resource, added in CLI 1.12 last month:&lt;/P&gt;&lt;P&gt;resources:&lt;BR /&gt;secrets:&lt;BR /&gt;ingestion_api_key:&lt;BR /&gt;catalog_name: ${var.catalog}&lt;BR /&gt;schema_name: secrets&lt;BR /&gt;name: ingestion_api_key&lt;BR /&gt;value: ${var.ingestion_api_key}&lt;BR /&gt;grants:&lt;BR /&gt;- principal: data-engineers&lt;BR /&gt;privileges: [READ_SECRET]&lt;/P&gt;&lt;P&gt;The value has to be a variable reference. If you type a literal the CLI stops you with "Secret value must be a variable reference... Plain text secret values are not allowed". In CI you set BUNDLE_VAR_ingestion_api_key from your pipeline secrets and the value exists only there and in UC. Jobs read it with dbutils.secrets.get(catalog=..., schema=..., key=...). Two things to know before picking this: it needs DBR 17.3 LTS or serverless environment 4, and it doesn't work on SQL warehouses, init scripts or spark_env_vars. If you still need the double-brace secrets syntax in cluster env vars, keep those on scopes.&lt;/P&gt;&lt;P&gt;Third, jobs reference the scope or the catalog.schema, never the value. We pass the scope name as a job parameter with ${resources.secret_scopes.ingestion.name} and call dbutils.secrets.get at runtime.&lt;/P&gt;&lt;P&gt;Parity then takes care of itself. Same names in every target, and the only thing that changes is the backing vault or the value CI injects. Each target deploys with its own service principal, so dev can't read prod even by accident.&lt;/P&gt;&lt;P&gt;One more thing worth keeping an eye on: UC external secrets, where a schema is backed directly by AWS Secrets Manager or Azure Key Vault, is in Beta right now. We haven't moved production to it yet but that is where I expect this to land.&lt;/P&gt;&lt;P&gt;Hope it helps, happy to share more detail on the CI side if useful.&lt;/P&gt;</description>
      <pubDate>Sun, 20 Sep 2026 11:26:49 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/managing-quot-secret-quot-injection-in-dabs-across-dev-stage/m-p/169233#M56060</guid>
      <dc:creator>ThomazNeto</dc:creator>
      <dc:date>2026-09-20T11:26:49Z</dc:date>
    </item>
    <item>
      <title>Re: Managing "Secret" Injection in DABs across Dev/Stage/Prod</title>
      <link>https://community.databricks.com/t5/data-engineering/managing-quot-secret-quot-injection-in-dabs-across-dev-stage/m-p/170026#M56214</link>
      <description>&lt;P&gt;Hi,&lt;/P&gt;&lt;P&gt;The basic rule: the bundle manages secret scopes and references to secrets, never the secret values.&lt;/P&gt;&lt;P&gt;1. Keeping secrets out of databricks.yml: Only reference scope and key names. Jobs resolve the secret at runtime:&lt;/P&gt;&lt;P&gt;In code: dbutils.secrets.get(scope, key)&lt;BR /&gt;In cluster Spark config or environment variables: {{secrets/&amp;lt;scope&amp;gt;/&amp;lt;key&amp;gt;}}&lt;/P&gt;&lt;P&gt;Make the scope name a bundle variable so each target uses its own scope:&lt;/P&gt;&lt;P&gt;yaml&lt;BR /&gt;variables:&lt;BR /&gt;secret_scope:&lt;BR /&gt;default: ingest-dev&lt;/P&gt;&lt;P&gt;targets:&lt;BR /&gt;prod:&lt;BR /&gt;variables:&lt;BR /&gt;secret_scope: ingest-prod&lt;/P&gt;&lt;P&gt;resources:&lt;BR /&gt;jobs:&lt;BR /&gt;ingest:&lt;BR /&gt;tasks:&lt;BR /&gt;- task_key: load&lt;BR /&gt;new_cluster:&lt;BR /&gt;spark_env_vars:&lt;BR /&gt;API_KEY: "{{secrets/${var.secret_scope}/api-key}}"&lt;/P&gt;&lt;P&gt;The value is resolved on the cluster and redacted in logs. Nothing sensitive goes into Git or the deployment state.&lt;/P&gt;&lt;P&gt;You can also inject values through BUNDLE_VAR_* environment variables from your CI secrets. That works, but the resolved value ends up in the bundle's deployment state, so keep it for non-sensitive config.&lt;/P&gt;&lt;P&gt;2. Secret scopes vs. an external vault:&lt;/P&gt;&lt;P&gt;Azure: use Key Vault-backed secret scopes. Secrets live in Key Vault and are read live, so rotating a secret needs no redeploy. These scopes are read-only from Databricks, so manage the values in Key Vault.&lt;BR /&gt;AWS/GCP: use Databricks-backed scopes, filled by your CI pipeline from Secrets Manager or Secret Manager (for example databricks secrets put-secret) as a separate step from bundle deploy.&lt;/P&gt;&lt;P&gt;3. Environment parity: Since CLI v0.252, bundles support a secret_scopes resource, so the scope is defined once and deployed to every target:&lt;/P&gt;&lt;P&gt;yaml&lt;BR /&gt;resources:&lt;BR /&gt;secret_scopes:&lt;BR /&gt;ingest:&lt;BR /&gt;name: ingest-${bundle.target}&lt;BR /&gt;backend_type: AZURE_KEYVAULT&lt;BR /&gt;keyvault_metadata:&lt;BR /&gt;resource_id: ${var.kv_resource_id}&lt;BR /&gt;dns_name: ${var.kv_dns_name}&lt;BR /&gt;permissions:&lt;BR /&gt;- group_name: data-engineers&lt;BR /&gt;level: READ&lt;/P&gt;&lt;P&gt;Give each environment its own Key Vault with the same secret names. Only kv_resource_id and kv_dns_name change per target, so the code is identical in dev, qa and prod.&lt;/P&gt;&lt;P&gt;Two notes:&lt;/P&gt;&lt;P&gt;Creating a Key Vault-backed scope requires the deploying identity to authenticate with Microsoft Entra ID. A PAT fails with a userAADToken error.&lt;BR /&gt;Scopes that already exist aren't managed by the bundle automatically. Import them or recreate them through the bundle.&lt;/P&gt;&lt;P&gt;Docs: Bundle resources · Secret Scope API · Secret management (Azure) · KB: userAADToken error&lt;/P&gt;</description>
      <pubDate>Mon, 28 Sep 2026 09:36:50 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/managing-quot-secret-quot-injection-in-dabs-across-dev-stage/m-p/170026#M56214</guid>
      <dc:creator>Islam_hoti</dc:creator>
      <dc:date>2026-09-28T09:36:50Z</dc:date>
    </item>
  </channel>
</rss>

