Rails Credentials und Secrets 2026: Sichere Verwaltung von Umgebungsvariablen

Umfassende Anleitung zur sicheren Verwaltung von Credentials und Secrets in Ruby on Rails mit verschlüsselten Credentials, Environment-spezifischen Konfigurationen und Best Practices für die Produktionsumgebung.

Rails Credentials und sichere Secrets-Verwaltung

Die sichere Verwaltung von Secrets und Umgebungsvariablen gehört zu den kritischsten Aspekten jeder Rails-Anwendung. Ein kompromittierter API-Schlüssel oder ein offengelegtes Datenbankpasswort kann verheerende Folgen haben. Rails bietet mit dem Credentials-System eine elegante Lösung, die Sicherheit und Entwicklerfreundlichkeit vereint.

Rails 8 hat das Credentials-System weiter verbessert und bietet nun native Unterstützung für mehrere Umgebungen ohne zusätzliche Gems. Für bestehende Projekte mit Rails 7.1+ ist ein Upgrade unkompliziert möglich.

Warum das Rails Credentials-System nutzen?

Das klassische Speichern von Secrets in Umgebungsvariablen oder .env-Dateien birgt mehrere Risiken. Umgebungsvariablen können in Logs auftauchen, werden manchmal versehentlich in Container-Images eingebacken oder landen in Crash-Reports. Das Rails Credentials-System löst diese Probleme durch Verschlüsselung auf Dateisystem-Ebene.

ruby
# Traditioneller Ansatz mit Umgebungsvariablen - anfällig für Leaks
config.secret_key_base = ENV['SECRET_KEY_BASE']
config.api_key = ENV['EXTERNAL_API_KEY']

# Rails Credentials - verschlüsselt und sicher
config.secret_key_base = Rails.application.credentials.secret_key_base
config.api_key = Rails.application.credentials.dig(:external_service, :api_key)

Die Credentials werden mit einem Master-Key verschlüsselt, der niemals ins Repository eingecheckt wird. Selbst wenn ein Angreifer Zugriff auf die verschlüsselte Datei erhält, sind die Secrets ohne den Master-Key wertlos.

Credentials erstellen und bearbeiten

Rails stellt einen integrierten Editor zum Verwalten der Credentials bereit. Der Befehl entschlüsselt die Datei temporär, öffnet den Editor und verschlüsselt sie nach dem Speichern erneut.

bash
# Credentials mit dem Standard-Editor bearbeiten
RAILS_MASTER_KEY=your_master_key rails credentials:edit

# Einen spezifischen Editor verwenden
EDITOR="code --wait" rails credentials:edit

# Environment-spezifische Credentials bearbeiten (Rails 7.1+)
rails credentials:edit --environment production
rails credentials:edit --environment staging

Die Struktur der Credentials-Datei folgt dem YAML-Format und unterstützt beliebig tiefe Verschachtelungen:

yaml
# config/credentials.yml.enc (entschlüsselt)
secret_key_base: a1b2c3d4e5f6g7h8i9j0...

aws:
  access_key_id: AKIAIOSFODNN7EXAMPLE
  secret_access_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
  region: eu-central-1
  bucket: my-production-bucket

stripe:
  publishable_key: pk_live_...
  secret_key: sk_live_...
  webhook_secret: whsec_...

database:
  primary:
    host: db.example.com
    username: app_user
    password: secure_password_123
  replica:
    host: db-replica.example.com
    username: readonly_user
    password: readonly_password_456

redis:
  url: redis://:password@redis.example.com:6379/0

smtp:
  address: smtp.sendgrid.net
  port: 587
  user_name: apikey
  password: SG.xxxxx

Environment-spezifische Credentials

Moderne Rails-Anwendungen benötigen unterschiedliche Credentials für Development, Staging und Production. Rails unterstützt dies durch separate verschlüsselte Dateien pro Umgebung.

bash
# Struktur im config-Verzeichnis
config/
├── credentials.yml.enc           # Fallback für alle Umgebungen
├── credentials/
│   ├── development.yml.enc       # Nur für Development
│   ├── development.key
│   ├── staging.yml.enc           # Nur für Staging
│   ├── staging.key
│   ├── production.yml.enc        # Nur für Production
│   └── production.key
└── master.key                    # Fallback-Key

Der Zugriff auf die Credentials erfolgt identisch, Rails wählt automatisch die richtige Datei basierend auf RAILS_ENV:

ruby
# config/database.yml
production:
  primary:
    adapter: postgresql
    host: <%= Rails.application.credentials.dig(:database, :primary, :host) %>
    username: <%= Rails.application.credentials.dig(:database, :primary, :username) %>
    password: <%= Rails.application.credentials.dig(:database, :primary, :password) %>
    database: myapp_production
    pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

Credentials in der Anwendung nutzen

Der Zugriff auf Credentials ist an verschiedenen Stellen der Anwendung möglich. Die dig-Methode bietet sicheren Zugriff auf verschachtelte Werte und gibt nil zurück, wenn ein Pfad nicht existiert.

ruby
# In Initialisierern
# config/initializers/stripe.rb
Stripe.api_key = Rails.application.credentials.dig(:stripe, :secret_key)

# In Modellen oder Services
class PaymentService
  def initialize
    @api_key = Rails.application.credentials.dig(:payment_gateway, :api_key)
    @merchant_id = Rails.application.credentials.dig(:payment_gateway, :merchant_id)
  end
  
  def process_payment(amount, token)
    # Sichere Verwendung der Credentials
    client = PaymentClient.new(
      api_key: @api_key,
      merchant_id: @merchant_id
    )
    client.charge(amount: amount, source: token)
  end
end

# In Controllern (wenn nötig)
class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token
  
  def stripe
    payload = request.body.read
    sig_header = request.env['HTTP_STRIPE_SIGNATURE']
    webhook_secret = Rails.application.credentials.dig(:stripe, :webhook_secret)
    
    begin
      event = Stripe::Webhook.construct_event(payload, sig_header, webhook_secret)
      handle_event(event)
      head :ok
    rescue Stripe::SignatureVerificationError
      head :bad_request
    end
  end
end

Master-Key-Verwaltung in der Produktion

Der Master-Key ist der kritischste Teil des Systems. Er darf niemals ins Repository eingecheckt werden und muss sicher an die Produktionsumgebung übermittelt werden.

bash
# Option 1: Umgebungsvariable (empfohlen für Container)
export RAILS_MASTER_KEY="your-master-key-here"

# Option 2: Datei auf dem Server (für VM-basierte Deployments)
echo "your-master-key-here" > /var/www/myapp/shared/config/master.key
chmod 600 /var/www/myapp/shared/config/master.key

# Option 3: Secret Manager Integration (AWS, GCP, Azure)
# In einem Initialisierer oder vor dem Rails-Start
export RAILS_MASTER_KEY=$(aws secretsmanager get-secret-value \
  --secret-id rails/production/master-key \
  --query SecretString --output text)

Für Container-Orchestrierung wie Kubernetes empfiehlt sich die Verwendung von Secrets:

yaml
# kubernetes/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: rails-credentials
  namespace: production
type: Opaque
stringData:
  RAILS_MASTER_KEY: "your-master-key-here"
---
# kubernetes/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rails-app
spec:
  template:
    spec:
      containers:
        - name: rails
          image: myapp:latest
          envFrom:
            - secretRef:
                name: rails-credentials

Credentials validieren und testen

Um sicherzustellen, dass alle erforderlichen Credentials vorhanden sind, empfiehlt sich eine Validierung beim Anwendungsstart:

ruby
# config/initializers/credentials_validator.rb
class CredentialsValidator
  REQUIRED_CREDENTIALS = [
    [:secret_key_base],
    [:database, :primary, :password],
    [:stripe, :secret_key],
    [:stripe, :webhook_secret],
    [:aws, :access_key_id],
    [:aws, :secret_access_key]
  ].freeze

  def self.validate!
    return if Rails.env.test?
    
    missing = REQUIRED_CREDENTIALS.select do |path|
      Rails.application.credentials.dig(*path).blank?
    end

    if missing.any?
      missing_paths = missing.map { |p| p.join('.') }.join(', ')
      raise "Missing required credentials: #{missing_paths}"
    end
  end
end

Rails.application.config.after_initialize do
  CredentialsValidator.validate!
end

In Tests können Credentials gemockt werden, um keine echten Secrets zu benötigen:

ruby
# spec/rails_helper.rb
RSpec.configure do |config|
  config.before(:each) do
    allow(Rails.application.credentials).to receive(:dig)
      .with(:stripe, :secret_key).and_return('sk_test_mock')
    allow(Rails.application.credentials).to receive(:dig)
      .with(:stripe, :webhook_secret).and_return('whsec_mock')
  end
end

# Oder mit einem Test-Credentials-Set
# spec/support/test_credentials.rb
module TestCredentials
  def self.configure!
    credentials = ActiveSupport::OrderedOptions.new
    credentials.stripe = ActiveSupport::OrderedOptions.new
    credentials.stripe.secret_key = 'sk_test_mock'
    credentials.stripe.webhook_secret = 'whsec_mock'
    
    allow(Rails.application).to receive(:credentials).and_return(credentials)
  end
end

Bereit für deine Ruby on Rails-Interviews?

Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.

Migration von Umgebungsvariablen zu Credentials

Für bestehende Projekte, die noch Umgebungsvariablen verwenden, ist eine schrittweise Migration empfehlenswert:

ruby
# Übergangsphase: Beide Methoden unterstützen
# config/initializers/external_services.rb
module ExternalServices
  class << self
    def stripe_key
      # Credentials haben Priorität, Fallback auf ENV
      Rails.application.credentials.dig(:stripe, :secret_key) ||
        ENV['STRIPE_SECRET_KEY']
    end

    def aws_access_key
      Rails.application.credentials.dig(:aws, :access_key_id) ||
        ENV['AWS_ACCESS_KEY_ID']
    end
  end
end

# Nach vollständiger Migration: Strikt nur Credentials
module ExternalServices
  class << self
    def stripe_key
      Rails.application.credentials.dig(:stripe, :secret_key) ||
        raise('Stripe secret key not configured in credentials')
    end
  end
end

Sicherheits-Best-Practices

Die Implementierung eines robusten Credentials-Systems erfordert die Beachtung mehrerer Sicherheitsaspekte:

ruby
# Niemals Credentials in Logs ausgeben
# config/initializers/filter_parameters.rb
Rails.application.config.filter_parameters += [
  :password, :secret, :token, :_key, :crypt, :salt,
  :certificate, :otp, :ssn, :api_key, :access_key,
  :credentials, :master_key
]

# Sichere Fehlerbehandlung ohne Secret-Leaks
class ApiClient
  def initialize
    @api_key = Rails.application.credentials.dig(:api, :key)
  end

  def fetch_data
    response = HTTParty.get(
      'https://api.example.com/data',
      headers: { 'Authorization' => "Bearer #{@api_key}" }
    )
    response.parsed_response
  rescue StandardError => e
    # Niemals den API-Key im Fehler loggen
    Rails.logger.error("API request failed: #{e.message}")
    raise ApiError, 'External service unavailable'
  end
end

Key-Rotation implementieren

Regelmäßige Key-Rotation erhöht die Sicherheit. Rails unterstützt dies durch die gleichzeitige Gültigkeit mehrerer Keys:

ruby
# config/credentials.yml.enc
aws:
  access_key_id: NEW_KEY_ID
  secret_access_key: NEW_SECRET
  # Alter Key für Übergangsphase
  legacy_access_key_id: OLD_KEY_ID
  legacy_secret_access_key: OLD_SECRET

# Service mit Fallback-Logik
class S3Service
  def client
    @client ||= begin
      Aws::S3::Client.new(
        access_key_id: credentials(:access_key_id),
        secret_access_key: credentials(:secret_access_key),
        region: Rails.application.credentials.dig(:aws, :region)
      )
    end
  end

  private

  def credentials(key)
    Rails.application.credentials.dig(:aws, key) ||
      Rails.application.credentials.dig(:aws, :"legacy_#{key}")
  end
end

Fazit

Das Rails Credentials-System bietet eine sichere und elegante Lösung für die Verwaltung sensibler Konfigurationsdaten. Durch die Verwendung verschlüsselter Dateien, environment-spezifischer Credentials und einer durchdachten Key-Verwaltung lassen sich Secrets effektiv schützen. Die Migration von klassischen Umgebungsvariablen zu Rails Credentials reduziert das Risiko von Secret-Leaks erheblich und verbessert gleichzeitig die Entwicklerergonomie durch einen zentralen Konfigurationsort.

Tags

#Ruby on Rails
#Sicherheit
#Credentials
#Secrets
#Umgebungsvariablen
#DevOps

Teilen

Verwandte Artikel