---
title: "RR009 – Store Secrets in Rails Credentials, Not in Code"
impact: high
impactDescription: "Hardcoded secrets in source code are committed to Git history and exposed permanently even after deletion."
tags: [ruby, rails, security, secrets]
---

# RR009 – Store Secrets in Rails Credentials

## Rule

All secret values (API keys, tokens, signing secrets, passwords) must live in `config/credentials.yml.enc` or environment variables. Never hardcode them in source files, `config/initializers/`, or `database.yml`.

## Why

Once a secret is committed, it lives in Git history forever. Rotating it requires a force-push and re-access revocation. Rails credentials are encrypted at rest; the master key (`config/master.key` or `RAILS_MASTER_KEY`) is the only secret that must stay outside source control.

## Wrong

```ruby
# config/initializers/stripe.rb
Stripe.api_key = 'sk_live_XXXXXXXXXXXXX'    # ❌ hardcoded

# config/database.yml
production:
  password: 'my_db_password_123'            # ❌ hardcoded

# app/services/sendgrid_service.rb
API_KEY = 'SG.xxxxxxxxxxxx'                 # ❌ constant with embedded secret
```

## Correct

```bash
# Add / edit secrets (encrypts automatically)
bin/rails credentials:edit --environment production

# config/credentials/production.yml.enc (decrypted view)
stripe:
  api_key: sk_live_XXXXXXXXXXXXX
sendgrid:
  api_key: SG.xxxxxxxxxxxx
```

```ruby
# Access anywhere in application code
Stripe.api_key = Rails.application.credentials.stripe[:api_key]

# Or via environment variable (suitable for container deployments)
Stripe.api_key = ENV.fetch('STRIPE_API_KEY')

# config/database.yml (env var form)
production:
  password: <%= ENV['DATABASE_PASSWORD'] %>
```

## Notes

- `config/master.key` and `config/credentials/production.key` must be in `.gitignore` and never committed.
- In CI/CD, inject `RAILS_MASTER_KEY` as a masked environment variable, not in cleartext config.
- For team environments with multiple people needing access, prefer environment variables or a vault (e.g., HashiCorp Vault, AWS Secrets Manager) over shared credentials files.
