Skip to content

Manage secrets with a DSC configuration document

In this tutorial, you author a DSC configuration document that manages a secret scope, a secret, and a secret ACL as one unit. You preview the changes with what-if, apply the configuration, verify the result, and make a change to see the configuration converge.

Prerequisites

  • A working installation and the Basic usage of dsc-databricks round trip behind you: DSC engine v3.2 or later, discoverable manifests, and working authentication.
  • A second user or group in your workspace to grant access to. This tutorial uses the built-in users group.

Step 1: Create the configuration document

Create a file named secrets.dsc.config.yaml with the following content:

$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
resources:
  - name: deployment scope
    type: LibreDsc.Databricks/SecretScope
    properties:
      scope: dsc-deployment
  - name: api token
    type: LibreDsc.Databricks/Secret
    dependsOn:
      - "[resourceId('LibreDsc.Databricks/SecretScope', 'deployment scope')]"
    properties:
      scope: dsc-deployment
      key: api-token
      string_value: tutorial-secret-value
  - name: reader access
    type: LibreDsc.Databricks/SecretAcl
    dependsOn:
      - "[resourceId('LibreDsc.Databricks/SecretScope', 'deployment scope')]"
    properties:
      scope: dsc-deployment
      principal: users
      permission: READ

The dependsOn entries make the engine create the scope before the secret and the ACL that live in it.

Do not commit a secret in plain text

string_value: tutorial-secret-value is acceptable for a throwaway tutorial value and wrong for anything else. A configuration document is a file you commit, review in pull requests and hand to CI, so a literal written there is readable by everyone who can read the repository, and it stays in the history after you delete the line.

Keep the value out of the document instead. DSC gives you two ways to do that: the secret() function, which resolves a name through a registered secret extension when the configuration runs, and a securestring parameter referenced with parameters(), whose value you supply at apply time. Both suit this resource, because string_value is write-only. The module never reads it back, so the value appears in neither get output, nor export output, nor a what-if afterState.

  - name: api token
    type: LibreDsc.Databricks/Secret
    dependsOn:
      - "[resourceId('LibreDsc.Databricks/SecretScope', 'deployment scope')]"
    properties:
      scope: dsc-deployment
      key: api-token
      string_value: "[secret('DatabricksApiToken')]"

The value never enters the document. Pass a second argument, as in [secret('DatabricksApiToken', 'MyVault')], when more than one registered vault holds a secret under that name.

parameters:
  apiToken:
    type: securestring
    metadata:
      description: Value stored in dsc-deployment/api-token.
resources:
  - name: api token
    type: LibreDsc.Databricks/Secret
    properties:
      scope: dsc-deployment
      key: api-token
      string_value: "[parameters('apiToken')]"

Supply the value at apply time, from a file your repository ignores or from your CI system's secret store:

dsc config --parameters-file .\secrets.parameters.yaml set --file .\secrets.dsc.config.yaml

Note where the option sits: the parameter options belong to dsc config, before the subcommand, not to set after it.

Step 2: Preview the changes

Run a what-if operation to see what would happen without changing anything:

dsc config set -w -f .\secrets.dsc.config.yaml

The metadata reports the execution type as whatIf, and each resource shows its predicted after-state:

metadata:
  Microsoft.DSC:
    executionType: whatIf
results:
- name: deployment scope
  result:
    afterState:
      scope: dsc-deployment
      backend_type: DATABRICKS
      _exist: true

Nothing has been created yet. Run dsc resource get -r LibreDsc.Databricks/SecretScope --input '{"scope":"dsc-deployment"}' to confirm the scope still reports _exist: false.

Step 3: Apply the configuration

Apply the document for real:

dsc config set -f .\secrets.dsc.config.yaml

The result lists all three resources with their after-states. The summary reports no errors.

Step 4: Verify the deployed state

Read the ACL to confirm the grant landed:

dsc resource get -r LibreDsc.Databricks/SecretAcl --input '{"scope":"dsc-deployment","principal":"users"}'

You should see the READ permission:

actualState:
  scope: dsc-deployment
  principal: users
  permission: READ
  _exist: true

Step 5: Change and re-apply

Edit secrets.dsc.config.yaml and change the ACL permission from READ to WRITE. Apply the document again:

dsc config set -f .\secrets.dsc.config.yaml

Only the ACL reports a change; the scope and the secret are already in the desired state. Repeat the get from step 4. The permission is now WRITE.

Step 6: Clean up

Delete the scope. Deleting the scope removes the secret and the ACL stored within it:

dsc resource delete -r LibreDsc.Databricks/SecretScope --input '{"scope":"dsc-deployment"}'

What you learned

  • A configuration document describes multiple resource instances and their ordering with dependsOn.
  • dsc config set -w predicts an apply without changing anything.
  • Re-applying a configuration only changes what drifted — the operation converges.
  • Secret values belong outside the document, resolved by secret() or passed in as a securestring parameter.

Next steps