Security Features¶
Felix is designed with security as a foundational principle, not an afterthought. This document covers current security features, planned enhancements, and best practices for secure deployments.
Security Philosophy¶
Felix's security model is built on three pillars:
- Encryption by default: All network communication is encrypted via QUIC/TLS
- Explicit boundaries: Tenant isolation, namespace scoping, region boundaries
- Auditable operations: All actions logged and traceable
Security Maturity
Felix is in early development. Core transport security and tenant-scoped RBAC are implemented. Encryption-at-rest and some advanced hardening features are still planned.
Transport Security¶
QUIC and TLS 1.3¶
Felix uses QUIC, which integrates TLS 1.3 natively:
Planned implementation:
- TLS 1.3 mandatory: No fallback to older TLS versions
- Encrypted by default: All connections are encrypted
- Modern cipher suites: ChaCha20-Poly1305, AES-128-GCM, AES-256-GCM
- Perfect forward secrecy: Ephemeral key exchange (ECDHE)
- Certificate validation: X.509 certificates validated by default
Protocol security:
graph TB
subgraph "QUIC Security Layers"
A[Application Data]
E[QUIC Encryption Layer]
P[UDP Packets]
end
A -->|Encrypt| E
E -->|Protected| P
style E fill:#ffeb3b
TLS Configuration¶
Server-side (broker):
# Broker TLS config
quic_bind: "0.0.0.0:5000"
tls_cert_path: "/etc/felix/tls/server.crt"
tls_key_path: "/etc/felix/tls/server.key"
tls_ca_cert_path: "/etc/felix/tls/ca.crt" # For mTLS (future)
Client-side:
use felix_client::ClientConfig;
// Production: validate certificates using the platform verifier
let quinn = quinn::ClientConfig::with_platform_verifier();
let config = ClientConfig::optimized_defaults(quinn);
// Development: configure Quinn with a test CA or custom verifier as needed
Certificate Management¶
Generating self-signed certificates (development):
# Generate CA
openssl req -x509 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 365 -nodes \
-subj "/CN=Felix Test CA"
# Generate server certificate
openssl req -newkey rsa:4096 -keyout server.key -out server.csr -nodes \
-subj "/CN=broker.example.com"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt -days 365
# Client trusts ca.crt
Production certificates:
Use certificates from trusted CA (Let's Encrypt, corporate PKI):
# Let's Encrypt with certbot
certbot certonly --standalone -d broker.example.com
# Felix broker config
tls_cert_path: "/etc/letsencrypt/live/broker.example.com/fullchain.pem"
tls_key_path: "/etc/letsencrypt/live/broker.example.com/privkey.pem"
Certificate rotation:
# Broker monitors certificate changes and reloads automatically (future)
# For now, restart broker after certificate renewal
# Kubernetes secret for automatic rotation
kubectl create secret tls felix-tls \
--cert=server.crt \
--key=server.key
Mutual TLS (mTLS)¶
Planned for broker-to-broker communication:
# Broker config
mtls_enabled: true
mtls_client_cert_path: /certs/broker-client.crt
mtls_client_key_path: /certs/broker-client.key
mtls_ca_cert_path: /certs/broker-ca.crt
# Verify peer certificates
mtls_verify_peer: true
mtls_allowed_common_names:
- broker-1.internal
- broker-2.internal
- broker-3.internal
Use cases: - Broker-to-broker replication - Control plane to broker communication - Cross-region bridges
Data Isolation¶
Multi-Tenancy Model¶
Felix enforces tenant isolation at the protocol level:
Scope hierarchy:
tenant_id → namespace → stream/cache → key
Example:
acme-corp → production → orders → order-123
Isolation guarantees (current):
- Wire protocol enforcement: All operations require tenant_id
- Broker validation: Unknown tenants rejected
- Namespace scoping: Namespaces independent per tenant
- Stream isolation: Streams cannot cross tenant boundaries
- Cache isolation: Cache entries scoped to tenant
Isolation guarantees (planned):
- Resource quotas: Per-tenant CPU, memory, bandwidth limits
- Rate limiting: Per-tenant publish/subscribe rate limits
- Audit logging: All tenant operations logged
Namespace Isolation¶
Within a tenant, namespaces provide further isolation:
// These are completely independent
use felix_wire::AckMode;
let publisher = client.publisher().await?;
publisher
.publish("acme", "production", "orders", data.to_vec(), AckMode::None)
.await?;
publisher
.publish("acme", "staging", "orders", data.to_vec(), AckMode::None)
.await?;
publisher
.publish("acme", "development", "orders", data.to_vec(), AckMode::None)
.await?;
Use cases:
- Environment isolation: production, staging, development
- Team isolation: team-a, team-b, team-c
- Application isolation: app-1, app-2, app-3
Authentication and Authorization¶
Felix implements token-based authentication with upstream OIDC and tenant-scoped RBAC enforced by brokers using Felix tokens.
Bootstrap Mode (Day-0)¶
New tenants need IdP issuers, signing keys, and initial RBAC before any admin tokens exist. Felix provides a one-time bootstrap mode for operators:
- Enable bootstrap on the control plane (disabled by default):
FELIX_BOOTSTRAP_ENABLED=true
FELIX_BOOTSTRAP_BIND_ADDR=127.0.0.1:9095
FELIX_BOOTSTRAP_TOKEN=<random secret>
- Call the internal endpoint (bound to the bootstrap address):
POST /internal/bootstrap/tenants/{tenant_id}/initialize
X-Felix-Bootstrap-Token: <secret>
Content-Type: application/json
{
"display_name": "Tenant One",
"idp_issuers": [
{
"issuer": "https://login.microsoftonline.com/<tenant>/v2.0",
"audiences": ["api://felix-controlplane"],
"discovery_url": null,
"jwks_url": null,
"claim_mappings": {
"subject_claim": "sub",
"groups_claim": "groups"
}
}
],
"initial_admin_principals": ["p:alice"]
}
- Disable bootstrap after the initial setup.
After bootstrap, admin actions require explicit Felix permissions:
- IdP issuer admin: tenant.manage:tenant:{tenant_id}
- RBAC list: rbac.view:<scoped object>
- RBAC policy writes: rbac.policy.manage:<scoped object>
- RBAC assignment writes: rbac.assignment.manage:<scoped object>
RBAC Object Grammar and Delegation¶
Canonical RBAC object formats:
- tenant:{tenant_id}
- namespace:{tenant_id}/{namespace}
- stream:{tenant_id}/{namespace}/{stream_or_*}
- cache:{tenant_id}/{namespace}/{cache_or_*}
Write-time protections:
- tenant:* is rejected
- non-tenant-scoped wildcards are rejected
- policy/assignment writes are rejected if target scope is broader than caller scope
This prevents common privilege-escalation footguns when delegating namespace or stream admins.
Supported Identity Providers¶
Felix supports any OIDC-compliant IdP that exposes a JWKS endpoint (via discovery or direct JWKS URL) and uses an allowed upstream OIDC signing algorithm.
Supported upstream OIDC JWT signing algorithms:
- ES256 (default)
- RS256, RS384, RS512
- PS256, PS384, PS512
Control plane configuration:
- YAML: oidc_allowed_algorithms: ["ES256"]
- Env: FELIX_CONTROLPLANE_OIDC_ALLOWED_ALGORITHMS=ES256,RS256,...
Common providers that work out of the box include:
- Microsoft Entra ID
- Okta
- Auth0
- Apple
Allowing Upstream IdPs Per Tenant¶
IdP trust is configured per tenant in the control plane store. Each tenant has an allowlist of issuers and audiences, plus optional claim mappings.
The control plane validates:
- iss matches an allowed issuer for the tenant
- aud matches one of the configured audiences
- signature via JWKS (cached with TTL)
- exp with clock skew and iat not in the future
Token Exchange (OIDC -> Felix)¶
Clients authenticate to the control plane with an upstream OIDC JWT and exchange it for a tenant-scoped Felix token.
POST /v1/tenants/{tenant_id}/token/exchange
Authorization: Bearer <oidc_jwt>
Content-Type: application/json
{
"requested": ["stream.publish", "cache.read"],
"resources": ["namespace:t1/payments", "stream:t1/payments/orders/*"]
}
Response:
Felix Token Claims¶
Felix tokens are JWTs minted by the control plane and validated by brokers.
iss:felix-authaud:felix-brokersub:principal_id(sha256 ofiss|sub)tid: tenant idexp,iatperms: effective permissions- Algorithm: EdDSA (Ed25519) only; Felix-issued tokens never use RSA. Tenant key rotation is published via JWKS.
RBAC Model (Casbin)¶
Casbin is used with domains for tenant scoping. Policies and groupings are stored per tenant.
Objects:
- tenant:{tenant_id}
- namespace:{tenant_id}/{namespace} or namespace:{tenant_id}/*
- stream:{tenant_id}/{namespace}/{stream} or stream:{tenant_id}/{namespace}/*
- cache:{tenant_id}/{namespace}/{cache} or cache:{tenant_id}/{namespace}/*
Actions:
- rbac.view, rbac.policy.manage, rbac.assignment.manage
- tenant.manage, ns.manage, stream.manage, cache.manage
- stream.publish, stream.subscribe
- cache.read, cache.write
Permission strings embedded in Felix tokens:
stream.publish:stream:t1/payments/orders
cache.read:cache:t1/payments/session
ns.manage:namespace:t1/payments
tenant.manage:tenant:t1
Inheritance Rules¶
tenant.manage:tenant:{T}implies tenant-scoped namespace/stream/cache permissions.ns.manage:namespace:{T}/{N}implies stream/cache manage + read/write within{N}.
Group-Based RBAC from IdP Claims¶
If tenant issuer config sets groups_claim, exchange maps each incoming group
to group:<name> (preserving group: prefix when already present) and adds a
transient grouping edge for evaluation:
This enables role assignment by group without per-user policy writes.
Broker Enforcement¶
Brokers validate Felix tokens (signature + claims) using tenant JWKS published by the control plane and enforce permissions locally using wildcard matching (keyMatch2 semantics).
sequenceDiagram
participant C as Client
participant CONTROLPLANE as Control Plane
participant B as Broker
C->>CONTROLPLANE: OIDC token exchange
CONTROLPLANE-->>C: Felix token (JWT)
C->>B: Connect with tenant_id + Felix token
B->>B: Verify JWT (iss/aud/exp/tid + signature)
B->>B: Match action+resource against perms
B-->>C: Allow or reject operation
Encryption at Rest (Planned)¶
Planned encryption for durable storage:
Envelope Encryption¶
encryption:
enabled: true
provider: kms # or local
master_key_id: "arn:aws:kms:us-west-2:123456789012:key/abc-123"
key_rotation_days: 90
Architecture:
graph LR
MK[Master Key<br/>KMS]
DEK[Data Encryption Key<br/>Per stream/tenant]
Data[Stream Data<br/>Encrypted]
MK -->|Encrypts| DEK
DEK -->|Encrypts| Data
style MK fill:#ffeb3b
style DEK fill:#fff3e0
style Data fill:#e3f2fd
Benefits:
- Master key never leaves KMS
- Data encryption keys rotatable
- Per-tenant or per-stream encryption
- Key audit trail in KMS
End-to-End Encryption (Planned)¶
Optional E2EE for sensitive data:
E2EE flow:
sequenceDiagram
participant P as Publisher
participant B as Broker
participant S as Subscriber
Note over P: Encrypt with stream key
P->>B: Publish (ciphertext)
Note over B: Routes ciphertext<br/>(cannot decrypt)
B->>S: Deliver (ciphertext)
Note over S: Decrypt with stream key
Properties:
- Publisher encrypts before sending
- Broker routes ciphertext (zero-knowledge)
- Subscriber decrypts after receiving
- Key management separate from broker
Network Security¶
Firewall Configuration¶
Inbound rules:
# Broker QUIC port
allow UDP 5000 from clients
# Metrics endpoint
allow TCP 8080 from monitoring
# Control plane (future)
allow TCP 9000 from control-plane
# Deny all other inbound
deny all
Outbound rules:
# Control plane sync (future)
allow TCP 9000 to control-plane
# External dependencies (KMS, etc.)
allow TCP 443 to kms.amazonaws.com
# Deny all other outbound
deny all
DDoS Protection¶
QUIC amplification prevention:
QUIC includes built-in protections:
- Address validation: Clients must prove IP ownership
- Stateless retry: Challenge-response before resource allocation
- Rate limiting: Per-source-IP connection limits
Application-level protection:
# Planned DoS protection config
protection:
max_connections_per_ip: 100
connection_rate_limit: 10/sec
publish_rate_limit: 1000/sec
burst_tolerance: 2x
Network Segmentation¶
Kubernetes network policies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: felix-broker
spec:
podSelector:
matchLabels:
app: felix-broker
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: application-namespace
ports:
- protocol: UDP
port: 5000
egress:
- to:
- namespaceSelector:
matchLabels:
name: control-plane-namespace
ports:
- protocol: TCP
port: 9000
Audit Logging (Planned)¶
Comprehensive audit trail:
{
"timestamp": "2026-01-15T10:30:45.123Z",
"event_type": "stream.create",
"principal": "admin@acme.com",
"principal_type": "user",
"tenant_id": "acme-corp",
"namespace": "production",
"resource": "stream:orders",
"action": "create",
"result": "success",
"metadata": {
"shards": 4,
"retention": "7d"
},
"source_ip": "10.0.1.45",
"user_agent": "felix-cli/0.1.0"
}
Audited events:
- Authentication attempts (success/failure)
- Authorization decisions (allow/deny)
- Resource creation/deletion
- Configuration changes
- Administrative operations
- Data access (optional, performance impact)
Audit log storage:
- Write-ahead append-only log
- Immutable after write
- Cryptographically signed (future)
- Long-term retention (years)
- Compliance-ready format
Compliance Features (Planned)¶
Data Residency¶
Regional constraints:
cluster:
region: eu-central-1
data_residency:
allow_cross_region: false
allowed_regions:
- eu-central-1
- eu-west-1
Enforcement:
- Data never leaves configured region
- Cross-region bridges require explicit configuration
- Audit trail for any cross-region data movement
GDPR Compliance¶
Right to erasure:
Data processing agreement:
- Tenant controls where data is processed
- Explicit consent for cross-region bridges
- Data retention policies enforced
- Audit trail for data access
HIPAA Compliance¶
Requirements (planned):
- ✓ Encryption in transit (TLS 1.3)
- Encryption at rest (planned)
- Access controls (RBAC planned)
- Audit logging (planned)
- Business associate agreement
- Physical security (infrastructure-dependent)
Security Best Practices¶
Deployment Security¶
- Use TLS certificates from trusted CA: Don't use self-signed in production
- Enable certificate verification: Never disable certificate verification in production clients
- Rotate certificates regularly: Before expiration, ideally every 90 days
- Use network policies: Restrict network access to broker
- Isolate broker pods: Dedicated node pool or namespace
- Enable audit logging: Track all administrative operations
- Monitor for anomalies: Unusual access patterns, failed auth attempts
- Principle of least privilege: Grant minimal necessary permissions
- Secure credential storage: Use secrets management (Vault, K8s secrets)
- Regular security updates: Keep Felix and dependencies up-to-date
Operational Security¶
Secure configuration:
# Good: explicit configuration
tls_cert_path: "/etc/felix/tls/server.crt"
tls_key_path: "/etc/felix/tls/server.key"
api_key_hash: "$2b$12$..." # Bcrypt hash, not plaintext
# Bad: insecure configuration
debug_mode: true # Not in production
log_payloads: true # Exposes sensitive data
Secrets management:
# Kubernetes secrets
kubectl create secret tls felix-tls \
--cert=server.crt \
--key=server.key
kubectl create secret generic felix-api-keys \
--from-literal=admin-key=felix_admin_key_xxx
Access control:
# Restrict who can deploy Felix
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: felix-deployers
subjects:
- kind: User
name: ops-team@acme.com
roleRef:
kind: Role
name: felix-deployer
apiGroup: rbac.authorization.k8s.io
Application Security¶
Client-side security:
use felix_client::{Client, ClientConfig};
use felix_wire::AckMode;
use std::net::SocketAddr;
// 1. Configure TLS via Quinn
let quinn = quinn::ClientConfig::with_platform_verifier();
let config = ClientConfig::optimized_defaults(quinn);
// 2. Connect
let addr: SocketAddr = "127.0.0.1:5000".parse()?;
let client = Client::connect(addr, "localhost", config).await?;
let publisher = client.publisher().await?;
// 3. Handle errors securely
match publisher
.publish("tenant", "ns", "stream", data.to_vec(), AckMode::PerMessage)
.await
{
Ok(()) => {},
Err(e) => {
// Don't log sensitive data in errors
error!("Publish failed: {}", e);
// Sanitize error before returning to user
return Err("Publish failed");
}
}
// 4. Don't log credentials or sensitive payloads
// Bad:
info!("Publishing: api_key={}, payload={:?}", api_key, data);
// Good:
info!("Publishing to stream={}", stream_name);
Vulnerability Disclosure¶
Security issues: Report to security@felix.example.com (update with actual contact)
PGP key: [Link to PGP key for encrypted communication]
Response timeline:
- Acknowledgement: Within 24 hours
- Initial assessment: Within 72 hours
- Resolution target: Within 30 days for critical issues
CVE process: Security vulnerabilities will be assigned CVE identifiers and published after fixes are available.
Security Roadmap¶
Short-term (next 6 months):
- Authorization framework (RBAC)
- API key authentication
- Audit logging
- Per-tenant rate limiting
Medium-term (6-12 months):
- Encryption at rest
- JWT/OIDC integration
- mTLS for broker-to-broker
- Advanced audit features
Long-term (12+ months):
- End-to-end encryption
- Hardware security module (HSM) integration
- FIPS 140-2 compliance
- Security certification (SOC 2, ISO 27001)
Threat Model¶
Threats Felix protects against:
- ✓ Eavesdropping: TLS 1.3 encryption
- ✓ Man-in-the-middle: Certificate validation
- ✓ Connection hijacking: QUIC connection IDs
- ✓ Replay attacks: TLS 1.3 anti-replay
- Unauthorized access: Authorization (planned)
- Data tampering: Integrity checks (planned)
- Denial of service: Rate limiting (planned)
Threats outside Felix's scope:
- Physical security (infrastructure responsibility)
- Client-side malware
- Social engineering
- DNS hijacking (use DNSSEC)
- BGP hijacking (infrastructure)
Security Contacts and Resources¶
Security team: security@felix.example.com
Bug bounty: (Planned)
Security advisories: GitHub Security Advisories
Security policy: SECURITY.md
Security is Shared Responsibility
Felix provides security features, but secure deployments require proper configuration, network security, access controls, and operational practices. Review this guide regularly and apply defense-in-depth principles.