Required by the Cryptography Policy and the Access Control Policy.

Rules

  • Never commit secrets to source control. Pre-commit hooks and PR-time secret scanning enforce this — see Secure Coding.
  • No secrets in plaintext config. Secrets are loaded from the secrets store at runtime.
  • No secrets in logs. Logging libraries are configured to redact known secret keys.
  • No secrets in error messages or stack traces.

Storage

Production secrets live in HashiCorp Vault — the secrets-of-record across both clouds. Vault holds static secrets (KV v2), dynamic secrets (DB credentials, cloud-IAM credentials), PKI material, and Transit-engine encryption keys for application-layer envelope encryption. AWS-hosted and Vultr-hosted workloads read secrets from Vault at runtime; no production secret is held outside Vault except (a) bootstrap credentials a workload needs before the Vault client is initialized, and (b) the Dashlane Developer vault for non-production developer secrets.

Hosting

Vault is self-hosted by Neuroscale on Vultr — Vault Server (OSS / Enterprise) running on Vultr Cloud Compute and / or VKE in a high-availability cluster across distinct Vultr regions. HashiCorp Inc. is the software licensor (Vault OSS / Enterprise) but is not a sub-processor: Neuroscale operates the Vault cluster end-to-end, and no Neuroscale customer or workforce data flows to HashiCorp. Because Vault runs on Vultr, a Vultr-side outage or master-account compromise has elevated impact: the Vultr Root Account Compromise Playbook treats Vault host integrity as a first-tier concern, and the RTO / RPO Matrix classifies Vault as Tier 1.

Auth methods

Workforce humans authenticate to Vault via Rippling SSO (OIDC) with MFA. Service-to-service auth is short-lived and bound to workload identity — no static service-account tokens in production:
  • AWS-hosted workloads — Vault AWS auth method (the IAM identity of the EC2 instance / ECS task / Lambda is verified by Vault using AWS STS, and Vault returns a short-lived token). The AWS workload reaches the Vultr-hosted Vault cluster over the public internet via TLS 1.3 with mTLS pinning, or via a Cloudflare One private route where deployed.
  • Vultr-hosted workloads on VKE — Vault Kubernetes auth method (service-account JWT → Vault token). VKE-side traffic to Vault stays within Vultr’s network.
  • Vultr-hosted workloads on Cloud Compute or Bare Metal (non-Kubernetes) — Vault AppRole with short-lived secret_id rotation, paired with response-wrapping for the bootstrap step.
  • CI / GitHub Actions — Vault JWT / OIDC auth method keyed to the GitHub OIDC provider; per-job tokens, no long-lived CI secrets.

Cross-cloud bootstrap

Where a workload cannot reach Vault before its client is initialized, a small bootstrap credential may be provisioned through the cloud’s instance metadata or container-orchestrator secrets — but only with CTO + CISO approval, only for the credential needed to authenticate to Vault, and only scoped to that one auth path. The bootstrap credential rotates at least every 30 days. Concretely:
  • AWS-side bootstrap — for an AWS workload that needs a Vault token before it can call AWS STS / the Vault AWS auth method, a one-shot AppRole secret_id may be injected via AWS Systems Manager Parameter Store or EC2 instance user-data; it is consumed once and replaced.
  • Vultr-side bootstrap — for a Vultr Cloud Compute or Bare Metal workload that runs outside VKE, the AppRole secret_id may be injected via Vultr instance metadata, configured at provisioning time, or via VKE secrets; same one-shot model.

Access and audit

All Vault access is audit-logged via Vault’s audit device, with logs forwarded to Better Stack and to AWS S3 (Object Lock) for WORM evidence. Vault root tokens are sealed in the CISO + CTO Dashlane vaults and used only for break-glass operations under the Vault break-glass procedure.

Application configuration and environment variables

Vault is the source for every production environment variable that holds a secret or sensitive value — including but not limited to: database connection strings and passwords, third-party API keys (Anthropic, OpenAI, xAI, Cerebras, Cloudflare, Stripe, etc.), OAuth client secrets, webhook signing keys, JWT signing keys, encryption peppers, internal service-to-service tokens, BYOK material received from customers. The application’s startup path must:
  1. Authenticate to Vault via a workload-bound auth method (per Auth methods above) — never with a long-lived static token.
  2. Read the values it needs from Vault (KV for static, Database / AWS / PKI engines for dynamic).
  3. Surface those values to the application in process memory only — typically by populating the runtime configuration object the application uses, or, where an env-var interface is unavoidable, by setting environment variables in the process being started by the orchestrator (not in the container image, not in the deployment manifest, not in CI logs).
Concrete patterns Neuroscale uses:
  • VKE / Kubernetes (preferred for Vultr workloads). Vault Agent Injector with annotations on the Pod spec — Vault Agent runs as an init/sidecar container, authenticates via the Vault Kubernetes auth method using the Pod’s service-account JWT, fetches secrets, and writes them to a tmpfs volume the application reads. The application’s container does not see a static Vault token, does not have secrets in its image, and does not have secrets in environment variables read by kubectl describe. Where a chart needs values via env vars, Vault Agent renders them with vault.hashicorp.com/agent-inject-template and the orchestrator sources the rendered file before exec.
  • AWS ECS / EC2 (preferred for AWS workloads). Vault Agent running on the host or in the task definition, authenticated via the Vault AWS auth method (the EC2 instance profile or ECS task role is verified by Vault using AWS STS). Secrets are written to a tmpfs mount; the application reads them at startup. AWS Systems Manager Parameter Store and AWS Secrets Manager are not used for production secrets — Vault is the single source of truth.
  • Vultr Cloud Compute or Bare Metal (non-Kubernetes). Vault Agent running on the host, authenticated via AppRole with response-wrapped secret_id rotation. Same tmpfs-rendered-template pattern as ECS.
  • CI / GitHub Actions. Vault JWT/OIDC auth method keyed to the GitHub OIDC provider; per-job tokens; vault kv get directly in the job. GitHub Actions Secrets are reserved for the bootstrap credential that authenticates the Actions runner to Vault — every other secret used by a job is fetched from Vault per-run.
Banned patterns (enforced by Code Review, Release Checklist, and Secure Coding):
  • Secret values committed to .env, config.yaml, values.yaml, container images, Helm charts, Terraform state, or any file checked into source. (.env.example with placeholder values is fine and committed; real values are not.)
  • Secrets baked into a container image at build time — including via ENV directives in a Dockerfile, build-time --build-arg, or a CI step that interpolates a secret into the image.
  • Secrets stored in plaintext in a Kubernetes Secret object that was created from a static manifest. (Kubernetes Secrets that are populated by Vault Agent at Pod startup are acceptable; static Secret manifests with values are not.)
  • Secrets passed via a deployment-tool environment block that ends up in shell history, deploy logs, or the orchestrator’s audit trail (e.g., kubectl set env, aws ecs update-service --environment …).
  • Secrets in CI logs — every CI step that touches a secret must use the runner’s masking and never echo or print it.
  • Defaults like os.environ.get("API_KEY", "dev-default") or secret or "fallback" — fail closed, not open.

Development

Development secrets live in Dashlane (Developer vault) with shared access for the appropriate team. Production secrets must not be stored in Dashlane. Local development uses .env files generated from the Dashlane developer vault — .env is always .gitignored, and .env.example (committed) carries placeholder values only. For developers running against a non-prod environment that uses Vault, a personal vault login -method=oidc (Rippling SSO) issues a short-lived token; per-team Vault policies scope the developer’s read access to non-prod paths only.

Vault break-glass

The Vault root token is sealed and used only when normal auth paths are unavailable (Vault sealed, IDP outage with no other admin path, or a compromise scenario). Break-glass use is logged in the IR ticket, all root-token-issued tokens are revoked at the end of the break-glass session, and the root token is rotated immediately after.

Rotation

  • Long-lived API keys — rotated annually, or on personnel change in the issuing/consuming team.
  • Service account keys — workload identity preferred; static keys rotated every 90 days.
  • Database passwords — rotated every 90 days, and on any suspected compromise or departure of personnel with access.
  • Compromise — immediate rotation; treat as a P0 / P1 incident depending on blast radius.

On compromise

If a secret is exposed (committed to source, leaked, suspected compromise):
  1. Open a security incident — see Incident Response.
  2. Rotate the secret in the secrets store.
  3. Audit access logs for any use of the compromised credential.
  4. Document remediation in the incident ticket.

Version history

VersionDateDescriptionAuthorApproved by
1.0May 8, 2026Initial versionCameron WolfeIshan Jadhwani