Skip to main content

STORING SECRETS

In this tutorial, we will create a vault, store a secret in it, annotate it with metadata, reference the secret from a model using a vault.get() expression, and see Swamp automatically redact it from output.

What we will build

We are going to set up a local encrypted vault, store an API token in it, then create a model that uses the token. When the model runs, we will see the secret resolved into the command but redacted from all output — logs, data, and the terminal.

Prerequisites

  • Swamp installed (Hello World covers installation)
  • A terminal open in an empty directory

Initialize the repository

First, we create a fresh Swamp repo:

$ mkdir vault-tutorial
$ cd vault-tutorial
$ swamp repo init --tool none

You will see the Swamp banner followed by:

info    repo·init Initialized swamp repository at "..." (tools: "none")

Create a vault

Vaults store secrets. We create one using the local_encryption type, which encrypts secrets on disk using your SSH key:

$ swamp vault create local_encryption secrets
info    vault·create Created vault: "secrets" ("Local Encryption")

Store a secret

Now we store a secret in the vault. The value is encrypted at rest — it never appears in plain text in any file:

$ swamp vault put secrets api-token my-secret-value
info    vault·put Stored secret "api-token" in vault "secrets"

We can verify it is stored without seeing the value:

$ swamp vault list-keys secrets
info    vault·list-keys Vault "secrets" ("local_encryption"): 1 key(s)
info    vault·list-keys   - "api-token"

Annotate the secret

Secrets accumulate over time and it becomes hard to remember what each one is for. We add metadata — a URL to the settings page where the token was created and a note about its purpose:

$ swamp vault annotate secrets api-token \
    --url "https://example.com/settings/api" \
    --notes "Production API token"
info    vault·annotate Annotated "api-token" in vault "secrets" (fields: "url, notes")

Now inspect shows the metadata without exposing the value:

$ swamp vault inspect secrets api-token
info    vault·inspect Metadata for "api-token" in vault "secrets":
info    vault·inspect   size: 15 chars (15 bytes)
info    vault·inspect   url: "https://example.com/settings/api"
info    vault·inspect   notes: "Production API token"
info    vault·inspect   updated: "..."
info    vault·inspect   refresh-hook: (none)

Notice we can see the size, URL, notes, and when it was last updated — but never the value itself.

Use the secret in a model

Now we create a model that references the secret. This is where vault.get() comes in:

$ swamp model create command/shell api-caller

Open the definition file (swamp model edit api-caller) and set the run global argument to a command that uses the secret:

globalArguments:
  run: "echo \"Calling API with token: ${{ vault.get('secrets', 'api-token') }}\""

The ${{ vault.get('secrets', 'api-token') }} expression reads the secret from the vault at evaluation time. The secret is resolved into the command before execution.

Now run it:

$ swamp model method run api-caller execute
info    model·method·run·api-caller·execute Evaluating expressions
info    model·method·run·api-caller·execute Executing method "execute"
info    model·method·run·api-caller·execute Calling API with token: ***
info    model·method·run·api-caller·execute Method "execute" completed on "api-caller"

Notice *** where the token value should be. Swamp detected that the output contains a vault secret and redacted it automatically.

Check the data

Let us look at the stored data to confirm the secret is redacted there too:

$ swamp data get api-caller result
Data: result (v1)
Model: api-caller (command/shell)
Content: application/json, 169B
Lifetime: infinite | GC: 10
Tags: type=resource, specName=result, modelName=api-caller
Owner: model-method (...)
Created: ...
Path: .swamp/data/command/shell/.../result/1/raw

{
  "exitCode": 0,
  "executedAt": "...",
  "command": "echo \"Calling API with token: ***\"",
  "durationMs": 5,
  "stdout": "Calling API with token: ***",
  "stderr": ""
}

The secret is *** in the command, in stdout, and everywhere else it appears. The actual value was used when the shell command ran, but it is never stored in plain text in the data output.

Verify vault health

Swamp can scan model definitions for secrets that were accidentally stored as plain text instead of vault references:

$ swamp doctor secrets
Scanning definitions for cleartext sensitive global arguments…

✓ No cleartext sensitive global arguments found (1 definition(s) scanned)

What we built

We created a vault, stored a secret, annotated it with metadata for future reference, used vault.get() to reference it from a model definition, and confirmed that Swamp automatically redacts vault secrets from all output. We also ran swamp doctor secrets to verify no cleartext secrets leaked into model definitions.