Skip to content
SumGuy's Ramblings
Go back

Vault vs Infisical: Secrets Management for Teams Who've Learned the Hard Way

The .env File Is Not a Secrets Manager, and Yet Here We Are

It starts innocently. One .env file. One database password. You add it to .gitignore and congratulate yourself on your operational security.

Six months later you have .env, .env.local, .env.staging, .env.production, and .env.backup-old scattered across four repos. You’ve copy-pasted DB_PASSWORD=SuperSecret123 so many times it’s practically a muscle memory. Two former contractors have it. You’ve forgotten which version is current. One of the repos might be public.

This is secrets sprawl, and it happens to everyone. The question isn’t whether to fix it — the question is which tool won’t make the cure worse than the disease.

The two serious contenders for self-hosters and small teams are HashiCorp Vault (the industry standard that will make you feel like you work at a bank) and Infisical (the modern alternative that won’t make you question your career choices).


The Secrets Sprawl Problem, Properly Quantified

Before getting into the tools, let’s agree on what “proper secrets management” actually needs to do:

A shared password manager technically ticks some of these boxes. It doesn’t tick “integration with your deployment pipeline at 2am,” which is when you’ll need it.


HashiCorp Vault: The Gold Standard (With a Learning Curve Like a Cliff)

Vault is what you use when security is a first-class concern and you have time to set it up properly. Financial services, healthcare, enterprises — Vault is everywhere at that scale for good reason.

What Vault Actually Does

The core model: Vault stores secrets (static or dynamic), you authenticate (via tokens, AppRole, Kubernetes service accounts, AWS IAM, and about fifteen other methods), and you get back the secret. Everything is audited.

The genuinely impressive feature is dynamic secrets. Instead of storing a database password, Vault talks directly to your database and generates a temporary credential with an expiry. Your app gets a username and password that exists for 24 hours, then gets revoked automatically. Even if someone exfiltrates the secret, it’s already dead.

Docker Compose Setup

services:
  vault:
    image: hashicorp/vault:latest
    restart: unless-stopped
    ports:
      - "8200:8200"
    environment:
      VAULT_DEV_ROOT_TOKEN_ID: "dev-only-token"
      VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200"
    cap_add:
      - IPC_LOCK
    volumes:
      - vault-data:/vault/data
      - ./vault/config:/vault/config
    command: vault server -config=/vault/config/vault.hcl

volumes:
  vault-data:

The IPC_LOCK capability is required — Vault uses it to prevent secrets from being swapped to disk.

For development, the VAULT_DEV_* variables spin up Vault in dev mode (not for production — it stores everything in memory and resets on restart). Production needs a proper vault.hcl config with storage backend (Raft is the recommended integrated option), TLS, and an unsealing strategy.

The Unseal Problem

This is where Vault’s model gets interesting. On startup, Vault is “sealed” — even with the right credentials, no secrets come out. You have to unseal it with unseal keys (or auto-unseal via AWS KMS, Azure Key Vault, etc.). The default setup uses Shamir’s Secret Sharing — 5 keys generated at init, 3 needed to unseal.

For a homelab, this is either fascinating (you’ve split your unseal keys across three YubiKeys like you’re launching nuclear missiles) or annoying (you rebooted the server and now everything is locked until you remember where you put those keys). Production environments usually configure auto-unseal with a cloud KMS.

Basic Secret Operations

# Store a secret
vault kv put secret/myapp/database \
  DB_HOST=postgres.internal \
  DB_PASSWORD=actual-secure-password \
  DB_NAME=myapp

# Read a secret
vault kv get secret/myapp/database

# Read just one field
vault kv get -field=DB_PASSWORD secret/myapp/database

App Integration (AppRole Auth)

# Create a policy
vault policy write myapp-policy - <<EOF
path "secret/data/myapp/*" {
  capabilities = ["read"]
}
EOF

# Create an AppRole
vault auth enable approle
vault write auth/approle/role/myapp \
  policies=myapp-policy \
  token_ttl=1h

# Get role ID and secret ID
vault read auth/approle/role/myapp/role-id
vault write -f auth/approle/role/myapp/secret-id

Your application uses those two values to authenticate and get a time-limited token.


Infisical: Modern, Opinionated, and Actually Has a UI

Infisical is what happens when someone looks at Vault and asks “what if we kept the good parts but made it usable by humans who have other jobs?”

It launched as a proper open-source alternative to commercial platforms like HashiCorp Vault Enterprise (the paid version) and Doppler. The self-hosted version is genuinely free. It has a UI that doesn’t look like it was designed for people who think terminal UIs are an aesthetic.

What Infisical Does Differently

Docker Compose Setup

services:
  infisical:
    image: infisical/infisical:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      ENCRYPTION_KEY: your-32-char-encryption-key-here
      AUTH_SECRET: your-jwt-secret-here
      MONGO_URL: mongodb://mongo:27017/infisical
      SITE_URL: https://infisical.yourdomain.com
    depends_on:
      - mongo
      - redis

  mongo:
    image: mongo:latest
    restart: unless-stopped
    volumes:
      - mongo-data:/data/db

  redis:
    image: redis:alpine
    restart: unless-stopped

volumes:
  mongo-data:

Note: Infisical recently migrated from MongoDB to PostgreSQL in newer versions. Check the current docs — the above may vary by version.

SDK Usage: The Part That Actually Matters

This is where Infisical genuinely shines. Fetching secrets at runtime takes about ten lines of code.

Node.js:

import InfisicalClient from "@infisical/sdk";

const client = new InfisicalClient({
  clientId: process.env.INFISICAL_CLIENT_ID,
  clientSecret: process.env.INFISICAL_CLIENT_SECRET,
});

const dbPassword = await client.getSecret({
  secretName: "DB_PASSWORD",
  projectId: "your-project-id",
  environment: "production",
});

console.log(dbPassword.secretValue);

Python:

from infisical_sdk import InfisicalSDKClient

client = InfisicalSDKClient(
    client_id=os.environ["INFISICAL_CLIENT_ID"],
    client_secret=os.environ["INFISICAL_CLIENT_SECRET"]
)

secret = client.getSecret(
    secret_name="DB_PASSWORD",
    project_id="your-project-id",
    environment="production"
)

The only values that need to be in your environment are the client ID and secret — and those are machine identity credentials, not your actual application secrets.


Head-to-Head Comparison

FeatureHashiCorp VaultInfisical
Setup complexityHighLow-Medium
UIBasicFull-featured
Dynamic secretsYes (databases, PKI, etc.)No
Secret versioningYesYes
Access controlVery granular (policies)RBAC
Audit loggingExcellentGood
SDK supportCommunity librariesOfficial SDKs
GitHub/GitLab syncVia CI stepNative
Self-hostableYesYes
LicenseBSL 1.1 (post-2023)MIT
Learning curveSteepModerate
Community sizeLargeGrowing
Auto-unseal complexityRequires KMSNot applicable
Best forEnterprise, complex security needsTeams, developer experience

When Vault Is Worth the Complexity

Vault earns its complexity in specific scenarios:

Dynamic database credentials: If you run a large application and want zero long-lived database passwords, Vault’s database secrets engine is unmatched. Every service gets a credential that auto-expires. Compromise one service and the attacker’s window is 24 hours.

PKI infrastructure: Vault can run an internal Certificate Authority. Issue certificates, rotate them, revoke them — all programmatically. For a microservices setup with mutual TLS, this is transformative.

Multi-cloud secrets: Vault integrates with AWS IAM, Azure AD, GCP IAM for secretless authentication — your EC2 instance’s IAM role authenticates to Vault and gets secrets without any hardcoded credentials.

Strict compliance requirements: SOC 2, PCI-DSS, HIPAA environments where audit trails and access control policies need to be airtight and demonstrably so.

If you’re a team of two running a SaaS with a Postgres database and a handful of API keys, Vault’s complexity is genuinely not worth it for the marginal security gain.


When Infisical Is the Right Call

Infisical is the right answer for:

The onboarding experience is genuinely the difference. With Vault, “we should set up secrets management” often becomes a multi-week project. With Infisical, you can have secrets out of your .env files and into the platform in an afternoon.


The Migration Path From .env Files

Regardless of which you pick, the migration process is roughly the same:

  1. Audit your .env files across all repos (yes, all of them)
  2. Categorize: which secrets are per-environment, which are shared
  3. Import to your secrets manager (Infisical has an import tool; Vault requires scripting)
  4. Update your applications to fetch secrets at startup
  5. Remove .env files from repos, update .gitignore
  6. Rotate all the secrets you just imported (they were compromised the moment they existed in .env files, sorry)

Step 6 is the one people skip and then regret.


The HashiCorp License Situation

It’s worth mentioning: HashiCorp switched Vault from MPL 2.0 to Business Source License 1.1 in 2023. BSL is not an open-source license by OSI definition. It restricts use in competing commercial products. For self-hosters and most companies, this doesn’t change anything — you can use Vault freely. But the community forked Vault into OpenBao (maintained by the Linux Foundation) if you want the fully open alternative.

Infisical remains MIT licensed.


The Practical Recommendation

Start with Infisical. It solves 90% of the secrets management problem with 20% of the operational overhead. Get your team off .env files, into proper environments, with secret versioning and audit logs.

When you hit the wall — you need dynamic database credentials, you’re running dozens of services with complex access control policies, or you have compliance requirements that need Vault’s audit capabilities — then invest in learning Vault properly.

The worst outcome is spending three weeks setting up Vault, finding it too complex, and going back to .env files because at least those work. The best outcome is solving the problem with a tool your team will actually use.

Your database password doesn’t need to be in 14 files. Pick the tool that makes it easy to fix that, and fix it.


Share this post on:

Previous Post
Systemd Socket Activation: Start Services Only When Someone Actually Knocks
Next Post
Docker BuildKit: Stop Waiting for Your Images to Build