Skip to main content
Version: Preview

Secret stores

A pipeline against a database needs a password. Marmot never stores it. It stores where the password lives in your secret manager and reads the value just before each run. Marmot authenticates to your secret manager with a short-lived token it mints itself, so there is no credential for reading credentials either.

Stores and secrets

A store is a connection to one secret manager. Keep one per account or environment, so production and staging are two stores.

A secret is the address of one value inside a store. It holds no value, so it is safe in Terraform, in git and in plan output.

BackendStoreSecret
Google Secret Managermarmot_secret_store_googlemarmot_secret_store_google_secret
AWS Secrets Managermarmot_secret_store_awsmarmot_secret_store_aws_secret
Azure Key Vaultmarmot_secret_store_azuremarmot_secret_store_azure_secret
HashiCorp Vaultmarmot_secret_store_vaultmarmot_secret_store_vault_secret

Register a store

Each store authenticates to its backend as an identity named after the store. Grant that identity on the secrets it should read and nothing else. The guide for your cloud builds the trust relationship end to end.

resource "marmot_secret_store_google" "prod" {
name = "gcp-prod"
workload_identity_provider = google_iam_workload_identity_pool_provider.marmot.name
}

resource "google_secret_manager_secret_iam_member" "marmot_reads_orders_password" {
secret_id = google_secret_manager_secret.orders_db_password.id
role = "roles/secretmanager.secretAccessor"
member = "principal://iam.googleapis.com/${google_iam_workload_identity_pool.marmot.name}/subject/${marmot_secret_store_google.prod.subject}"
}

The store's name is its identity. Renaming it replaces the store and breaks every grant that named it, so name it after the account it reaches, not the first thing you use it for.

Register a secret

Declare the secret and the Marmot reference to it together, so they cannot drift.

resource "google_secret_manager_secret" "orders_db_password" {
secret_id = "orders-db-password"

replication {
auto {}
}
}

resource "marmot_secret_store_google_secret" "orders_db_password" {
store = marmot_secret_store_google.prod.id
project = google_secret_manager_secret.orders_db_password.project
secret_id = google_secret_manager_secret.orders_db_password.secret_id
}
BackendAddress fields
Googleproject, secret_id
AWSsecret_id as an ARN, or region and secret_id
Azurevault_uri, name
Vaultmount, name, key

Leave the version unset. Marmot then reads the current value on every run, and rotation happens entirely in your secret manager.

Use a secret

A pipeline names the secret in its secrets map, and Marmot fills the value in before each run. The value exists in memory for the run and is then discarded.

A principal with the reader role can also read a value directly. This is the only path in Marmot that returns plaintext, and it is how an agent gets a credential without that credential appearing in any configuration file.

Access control

RoleMayBinds on
secretStore.viewerSee a store and its secrets. No values.organization, secretStore
secretStore.userRegister secrets and attach them to pipelines. No values.organization, secretStore
secretStore.readerRead values.organization, secretStore
secretStore.adminCreate, edit and delete stores.organization

The boundary that matters is between user and reader. Writing a pipeline means saying where its password comes from, not seeing it, so almost nobody who writes pipelines needs the reader role.

resource "marmot_secret_store_iam_member" "data_engineering_uses_prod" {
secret_store_id = marmot_secret_store_google.prod.id
role = "secretStore.user"
member = "group:${marmot_team.data_engineering.id}"
}

resource "marmot_secret_store_iam_member" "copilot_reads_prod" {
secret_store_id = marmot_secret_store_google.prod.id
role = "secretStore.reader"
member = "serviceAccount:${marmot_service_account.copilot.id}"
}

Notes

  • A store in use cannot be deleted. Remove the pipeline references first.
  • Validate a new store from its page in your instance. It performs a real token exchange and reports the result, which beats finding a mistyped subject at the next scheduled run.
  • Values are never persisted. There is no cache to expire after a rotation.

Or skip the secret entirely

For AWS, Google Cloud and Azure sources, a pipeline can present its own identity and use no credential at all.

Keyless pipelines