Files
charybdis/docs/security.md
T
Guillaume GRABÉ f1b1543f29
CI / Check (push) Successful in 13m13s
CI / Format (push) Successful in 48s
CI / Clippy (push) Successful in 12m13s
CI / Test (push) Successful in 12m45s
doc: update and cleanup
2026-06-09 11:26:47 +02:00

12 KiB

Security

Charybdis provides enterprise-grade security with mTLS authentication and RBAC authorization.

Overview

graph TB
    A[Client Request] -->|mTLS Handshake| B[TLS Layer]
    B -->|Certificate| C[Auth Interceptor]
    C -->|Extract Identity| D{Parse Certificate}
    D -->|CN, OU, O| E[Role Mapping]
    E -->|Role| F{Permission Check}
    F -->|Authorized| G[Entity Service]
    F -->|Denied| H[PermissionDenied Error]
    G -->|Audit Log| I[Security Events]
    
    style C fill:#f9d71c,stroke:#f9a825
    style F fill:#4A90E2,stroke:#2E5C8A

mTLS Authentication

Mutual TLS (mTLS) provides certificate-based client authentication.

How It Works

  1. Client presents X.509 certificate during TLS handshake
  2. Server validates certificate against trusted CA
  3. Charybdis extracts certificate identity (CN, OU, O)
  4. RBAC Engine maps identity to role
  5. Permissions are checked before allowing the request

Certificate Structure

Subject: CN=admin-user, OU=platform-team, O=Charybdis-Dev, C=US
Issuer: CN=Charybdis Root CA, O=Charybdis-Dev, C=US
Validity: Not Before: Nov  3 2025, Not After: Nov  3 2026

Fields Used for Authentication:

  • CN (Common Name) - User or service identifier
  • OU (Organizational Unit) - Team or role identifier
  • O (Organization) - Organization name

Configuration

Environment Variables

# Enable mTLS
export SECURITY_MTLS_ENABLED=true

# Server certificate and key
export SECURITY_MTLS_SERVER_CERT=./certs/server-cert.pem
export SECURITY_MTLS_SERVER_KEY=./certs/server-key.pem

# Client CA for verification
export SECURITY_MTLS_CLIENT_CA=./certs/ca.pem

# Enable RBAC
export SECURITY_RBAC_ENABLED=true

Generating Certificates

Development Certificates

Use the provided dev-cert script:

./deploy/scripts/generate-dev-certs.sh

This generates (under deploy/certs/):

  • ca.pem / ca-key.pem — Certificate Authority
  • server-cert.pem / server-key.pem — Server certificate
  • admin-cert.pem / admin-key.pem — Admin client (OU=platform-team)
  • Per-role client certs (OU=automation, OU=plugins)

For an individual client cert without regenerating everything, use ./deploy/scripts/generate-client-cert.sh.

Production Certificates

For production, use a proper PKI:

Options:

  • Internal PKI: HashiCorp Vault, cert-manager, step-ca
  • Public CA: Let's Encrypt (for internet-facing)
  • Enterprise CA: Your organization's certificate authority

Requirements:

  • Valid for at least 90 days
  • Issued by trusted CA
  • Proper subject alternative names (SANs)
  • Appropriate key usage extensions

Certificate Best Practices

DO:

  • Use short-lived certificates (24-90 days)
  • Implement automatic rotation
  • Monitor expiration dates
  • Use strong key lengths (2048+ bit RSA or 256+ bit ECC)
  • Store private keys securely
  • Use separate CAs for dev/prod

DON'T:

  • Use self-signed certs in production
  • Share private keys
  • Use the same certificate across environments
  • Ignore expiration warnings
  • Store keys in version control

RBAC Authorization

Role-Based Access Control (RBAC) enforces fine-grained permissions.

Role Mapping

Charybdis maps certificate attributes to roles:

Certificate OU → RBAC Role → Permissions

Default Roles

Role Certificate OU Description Permissions
platform platform-team Platform administrators Full access (CRUD + list)
automation automation CI/CD pipelines Create, read, update, list
plugin plugins Integration plugins Read, list only

Permissions

Permission Methods Description
entity:create CreateEntity Create new entities
entity:read GetEntity Read entity by ID
entity:update UpdateEntity, PartialUpdateEntity Modify entities
entity:delete DeleteEntity Delete entities
entity:list ListEntities List all entities

Permission Matrix

Role Create Read Update Delete List
platform
automation
plugin

Usage Examples

Admin Access (Full Permissions)

# Create entity
grpcurl \
  -cacert certs/ca.pem \
  -cert certs/admin-cert.pem \
  -key certs/admin-key.pem \
  -d '{"entity": {...}}' \
  localhost:50051 charybdis.entities.EntityService/CreateEntity

# ✅ SUCCESS

Automation Access (Limited)

# CI/CD can create
grpcurl \
  -cacert certs/ca.pem \
  -cert certs/ci-pipeline-cert.pem \
  -key certs/ci-pipeline-key.pem \
  -d '{"entity": {...}}' \
  localhost:50051 charybdis.entities.EntityService/CreateEntity

# ✅ SUCCESS

# But cannot delete
grpcurl \
  -cacert certs/ca.pem \
  -cert certs/ci-pipeline-cert.pem \
  -key certs/ci-pipeline-key.pem \
  -d '{"id": "..."}' \
  localhost:50051 charybdis.entities.EntityService/DeleteEntity

# ❌ Code: PermissionDenied
#    Message: Role 'automation' does not have permission 'entity:delete'

Plugin Access (Read-Only)

# Plugin can list
grpcurl \
  -cacert certs/ca.pem \
  -cert certs/defectdojo-plugin-cert.pem \
  -key certs/defectdojo-plugin-key.pem \
  -d '{}' \
  localhost:50051 charybdis.entities.EntityService/ListEntities

# ✅ SUCCESS

# But cannot create
grpcurl \
  -cacert certs/ca.pem \
  -cert certs/defectdojo-plugin-cert.pem \
  -key certs/defectdojo-plugin-key.pem \
  -d '{"entity": {...}}' \
  localhost:50051 charybdis.entities.EntityService/CreateEntity

# ❌ Code: PermissionDenied
#    Message: Role 'plugin' does not have permission 'entity:create'

Custom Role Configuration

Defining Custom Roles

Edit src/main.rs::setup_default_rbac_config():

let role_mappings = vec![
    // Custom developer role
    RoleMapping {
        role: "developer".to_string(),
        rules: vec![RoleRule {
            subject: SubjectMatch {
                cn: None,
                ou: Some("engineering".to_string()),
                o: None,
            },
        }],
    },
];

let mut permissions = HashMap::new();
permissions.insert(
    "developer".to_string(),
    vec![
        "entity:create".to_string(),
        "entity:read".to_string(),
        "entity:list".to_string(),
    ],
);

Certificate-Based Mapping

Map specific certificates to roles:

// Map by CN (specific user/service)
RoleRule {
    subject: SubjectMatch {
        cn: Some("jenkins-ci".to_string()),
        ou: None,
        o: None,
    },
}

// Map by Organization
RoleRule {
    subject: SubjectMatch {
        cn: None,
        ou: None,
        o: Some("External-Partner".to_string()),
    },
}

// Combined matching
RoleRule {
    subject: SubjectMatch {
        cn: Some("admin".to_string()),
        ou: Some("platform-team".to_string()),
        o: Some("MyCompany".to_string()),
    },
}

Audit Logging

All security events are logged for compliance and forensics.

Event Types

Event Logged Information
Authentication Success Identity (CN, OU, O), timestamp
Authentication Failure Reason, timestamp
Authorization Success Identity, role, method, duration
Authorization Denial Identity, role, method, required permission
Certificate Error Error details, certificate info

Log Format

2025-11-04T10:16:22Z INFO [AUDIT] Authorization Success
  identity: CN=admin-user, OU=platform-team
  role: platform
  method: /charybdis.entities.EntityService/CreateEntity
  permission: entity:create
  duration: 0.08ms

2025-11-04T10:16:25Z WARN [AUDIT] Authorization Denied
  identity: CN=defectdojo-plugin, OU=plugins
  role: plugin
  method: /charybdis.entities.EntityService/CreateEntity
  required_permission: entity:create
  reason: Role 'plugin' does not have permission 'entity:create'
  duration: 0.05ms

Audit Configuration

# Enable audit logging (default: true)
export SECURITY_RBAC_AUDIT_ENABLED=true

# Log all requests (default: true)
export SECURITY_RBAC_AUDIT_LOG_ALL_REQUESTS=true

# Log denied requests (default: true)
export SECURITY_RBAC_AUDIT_LOG_DENIED=true

Reverse Proxy Deployment

For environments where mTLS termination happens at a reverse proxy:

Architecture

graph LR
    A[Client] -->|mTLS| B[Reverse Proxy]
    B -->|HTTP + Cert Header| C[Charybdis]
    
    style B fill:#4A90E2,stroke:#2E5C8A

Proxy Configuration

Envoy

- name: envoy.filters.http.lua
  typed_config:
    inline_code: |
      function envoy_on_request(request_handle)
        local cert = request_handle:connection():ssl():peerCertificatePresented()
        if cert then
          request_handle:headers():add("x-client-cert", cert)
        end
      end

nginx

location / {
    proxy_set_header X-Client-Cert $ssl_client_cert;
    proxy_pass http://charybdis:50051;
}

Header Format

Charybdis accepts certificates in these headers:

  • x-forwarded-client-cert (Envoy/Istio standard)
  • x-client-cert (nginx)

Format: Base64-encoded DER certificate

Troubleshooting

Common Issues

1. Certificate Not Found

ERROR: Client certificate required but not provided

Causes:

  • Certificate not sent by client
  • Wrong certificate path
  • Certificate expired

Solutions:

# Verify certificate is valid
openssl x509 -in cert.pem -noout -text

# Check expiration
openssl x509 -in cert.pem -noout -dates

# Test TLS handshake
openssl s_client -connect localhost:50051 \
  -CAfile ca.pem -cert cert.pem -key key.pem

2. Permission Denied

Code: PermissionDenied
Message: Role 'X' does not have permission 'Y'

Causes:

  • Certificate OU doesn't match any role
  • Role lacks required permission

Solutions:

# Check certificate attributes
openssl x509 -in cert.pem -noout -subject

# Review role mappings in src/main.rs
# Verify permission requirements in docs

3. No Role Assigned

ERROR: No role assigned to identity: CN=..., OU=...

Causes:

  • Certificate OU not configured in role mappings
  • Typo in OU value

Solutions:

  • Add role mapping for the OU
  • Generate new certificate with correct OU
  • Check role mapping configuration

Security Hardening

Production Checklist

  • Use certificates from trusted CA
  • Enable mTLS (SECURITY_MTLS_ENABLED=true)
  • Enable RBAC (SECURITY_RBAC_ENABLED=true)
  • Implement certificate rotation (90 days max)
  • Monitor certificate expiration
  • Enable audit logging
  • Use TLS 1.3 only
  • Implement rate limiting
  • Set up intrusion detection
  • Regular security audits

Certificate Rotation

Implement automatic rotation:

#!/bin/bash
# rotate-certs.sh

# Generate new certificate
./generate-cert.sh

# Gracefully restart Charybdis
kill -HUP $(pidof charybdis)

# Verify new cert is active
sleep 5
openssl s_client -connect localhost:50051 < /dev/null | \
  openssl x509 -noout -dates

Monitoring

Monitor security metrics:

  • Authentication success/failure rate
  • Authorization denial rate
  • Certificate expiration warnings
  • Audit log anomalies
  • Failed login attempts

Compliance

Charybdis security features support compliance requirements:

Standard Supported Features
SOC 2 Audit logging, access control, encryption in transit
ISO 27001 Authentication, authorization, audit trails
PCI DSS Encryption, access control, logging
HIPAA Access control, audit logging, encryption

Next Steps

  • Plugins — configure plugins to use mTLS client certs
  • Architecture — interceptor placement and observability hooks

Security Questions? Open an issue (for vulnerabilities, use private disclosure).