Repository navigation
feat(security): Migrate services to mTLS authentication (PKI-based) #725
Copy link
Copy link
Closed
Labels
Description
Feature: mTLS Service Authentication
Summary
Migrate from password-based service authentication to mutual TLS (mTLS) using the existing PKI infrastructure. This provides stronger security through certificate-based authentication.
Current State
Existing PKI Infrastructure ✅
AutoBot already has a comprehensive PKI system in src/pki/:
- PKIManager - Main orchestrator for certificate lifecycle
- CertificateGenerator - Creates CA and service certificates
- CertificateDistributor - Distributes certs to VMs via SSH
- ServiceConfigurator - Updates service configs for TLS
Redis TLS Support ✅
src/utils/redis_management/config.py already supports:
@dataclass
class RedisConfig:
ssl: bool = False
ssl_ca_certs: Optional[str] = None
ssl_certfile: Optional[str] = None
ssl_keyfile: Optional[str] = None
ssl_cert_reqs: str = "required"Auto-configuration when AUTOBOT_REDIS_TLS_ENABLED=true is set.
Connection Manager ✅
src/utils/redis_management/connection_manager.py already creates SSL contexts with client certificates:
ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
ssl_context.load_verify_locations(config.ssl_ca_certs)
ssl_context.load_cert_chain(config.ssl_certfile, config.ssl_keyfile)
pool_params["ssl"] = ssl_contextWhat's Missing
1. Environment Configuration
Update .env to enable TLS:
# TLS Mode
AUTOBOT_TLS_MODE=required
# Redis TLS
AUTOBOT_REDIS_TLS_ENABLED=true
AUTOBOT_REDIS_TLS_PORT=63802. Redis Server TLS Configuration
The ServiceConfigurator creates this config but it needs tls-auth-clients yes for mTLS:
# /etc/redis-stack.conf
tls-port 6380
port 0 # Disable non-TLS port
tls-cert-file /etc/autobot/certs/server-cert.pem
tls-key-file /etc/autobot/certs/server-key.pem
tls-ca-cert-file /etc/autobot/certs/ca-cert.pem
tls-auth-clients yes # Require client certificates (mTLS)
3. Ansible Integration
Update Redis role to deploy TLS configuration:
- Generate certificates during
enroll-node.yml - Configure Redis with TLS in
deploy-database.yml - Distribute client certs to all VMs that connect to Redis
4. Per-Service Certificates
Each VM needs its own client certificate:
| VM | Certificate | Common Name |
|---|---|---|
| main-host | certs/main-host/ |
autobot-main-host |
| frontend | certs/frontend/ |
autobot-frontend |
| npu-worker | certs/npu-worker/ |
autobot-npu-worker |
| ai-stack | certs/ai-stack/ |
autobot-ai-stack |
| browser | certs/browser/ |
autobot-browser |
Implementation Plan
Phase 1: Certificate Generation & Distribution
- Run PKI setup:
python -c "from src.pki import setup_pki; import asyncio; asyncio.run(setup_pki(force=True))" - Verify certificates generated in
certs/directory - Verify certificates distributed to
/etc/autobot/certs/on each VM
Phase 2: Redis mTLS Configuration
- Update
src/pki/configurator.py- settls-auth-clients yes - Update Redis config template to disable plain port (
port 0) - Run configurator to update Redis VM
- Restart Redis with TLS:
systemctl restart redis-stack-server - Verify TLS connection:
redis-cli --tls --cert ... --key ... --cacert ... ping
Phase 3: Backend mTLS Client Configuration
- Set
AUTOBOT_REDIS_TLS_ENABLED=truein.env - Verify
RedisConfig.__post_init__auto-loads cert paths - Restart backend and verify connection via circuit breaker logs
- Remove
REDIS_PASSWORDfrom.env(no longer needed)
Phase 4: Ansible Automation
- Update
ansible/roles/redis/templates/redis-stack.conf.j2for TLS - Add certificate distribution tasks to Redis role
- Update
ansible/playbooks/enroll-node.ymlto generate per-node certs - Add TLS verification to
ansible/playbooks/health-check.yml
Phase 5: Other Services (Future)
- FastAPI backend HTTPS
- NPU worker inter-service auth
- Celery broker TLS
- WebSocket TLS
Security Benefits
| Aspect | Password Auth | mTLS Auth |
|---|---|---|
| Credential exposure | Password in .env, logs, memory | Private key never transmitted |
| Authentication strength | Single shared secret | Per-service cryptographic identity |
| Revocation | Must rotate everywhere | Revoke single certificate |
| Audit trail | IP-based only | Certificate CN identifies client |
| Forward secrecy | No | Yes (with proper cipher suites) |
Rollback Plan
If issues arise:
- Set
AUTOBOT_REDIS_TLS_ENABLED=falsein.env - Re-enable Redis password:
redis-cli CONFIG SET requirepass <password> - Restart backend services
- Services fall back to password authentication
Related Issues
- Closes fix(ansible): Add Redis password and ensure systemd services auto-start #724 (Redis password and systemd services)
- Supersedes password-based Redis auth
Files to Modify
| File | Change |
|---|---|
.env |
Add AUTOBOT_REDIS_TLS_ENABLED=true |
src/pki/configurator.py |
Set tls-auth-clients yes, port 0 |
ansible/roles/redis/templates/redis-stack.conf.j2 |
Add TLS config |
ansible/roles/redis/tasks/main.yml |
Add cert distribution |
ansible/playbooks/enroll-node.yml |
Generate per-node certs |
Testing Checklist
- Redis accepts TLS connections only
- Backend connects with client certificate
- Non-TLS connections rejected
- Certificate expiration monitoring works
- Health checks pass
- Circuit breaker doesn't trip on TLS handshake
Labels
enhancementsecurityinfrastructure
Reactions are currently unavailable
Activity
fix(slm): Fix agent code quality issues (#726)
mrveiss commentedon Jan 29, 2026
Implementation Plan - Refined
Design document created:
docs/plans/2026-01-29-mtls-service-authentication-design.mdPhase 0: Cleanup (Pre-requisite)
ansible/inventory/group_vars/aiml.yml:363ansible/inventory/group_vars/all.yml:118main.pyin project rootdocker/directory (not used - services run natively)Phase 1: Certificate Generation & Distribution
PKIManager.setup(force=True)certs/directory/etc/autobot/certs/on all VMsPhase 2: Redis Dual-Auth Configuration
port 6379+tls-port 6380redis-cli --tls -p 6380 ... pingPhase 3: Backend mTLS Client (Main Host)
AUTOBOT_REDIS_TLS_ENABLED=truein.envPhase 4: Celery mTLS Client (Main Host)
backend/celery_app.pywith SSL contextrediss://Phase 5: AI Stack mTLS Client (VM4)
rediss://Phase 6: Disable Password Auth (MANUAL GATE)
Pre-requisites:
Actions:
port 0,tls-auth-clients yes, removerequirepassPhase 7: HTTPS for HTTP APIs
VITE_HTTP_PROTOCOL=httpsPhase 8: Ansible Automation
ansible/roles/redis/templates/redis-stack.conf.j2with TLSansible/playbooks/health-check.ymlfor TLSPer-VM Summary
main-host/frontend/npu-worker/redis/ai-stack/browser/Rollback Script
Emergency rollback script will be at
/usr/local/bin/autobot-tls-rollback.shmrveiss commentedon Jan 29, 2026
Phase 0: Cleanup Targets Identified
Detailed cleanup document:
docs/plans/2026-01-29-port-cleanup-targets.mdFiles to Modify
ansible/inventory/group_vars/all.ymlport: "8000:8099"rangeansible/inventory/group_vars/aiml.ymlport: "8090:8099"blockmain.py(root)main.py.deprecateddocker/DEPRECATED.mdnoticeTest/Script References to Update
These reference the legacy
main.pyand should point tobackend/main.py:tests/screenshots/test_security_endpoints.py:26scripts/utilities/settings_diagnostic_utility.py:164scripts/utilities/verify_backend_config.py:115scripts/utilities/fix_settings_loading.py:160Verification After Cleanup
Note on SLM References
References to port 8000 for SLM Server (172.16.168.19) are CORRECT and should NOT be changed:
ansible/roles/slm_agent/defaults/main.ymlslm-server/config.pyscripts/slm-agent-standalone.pySLM runs on a separate machine (VM0), not main-host.
mrveiss commentedon Jan 29, 2026
Phase 0: Cleanup Complete
Commit:
4728a935Completed Tasks
main.py→ renamed tomain.py.deprecatedmain.pywith deprecation warningdocker/DEPRECATED.mdexplaining services run natively${AUTOBOT_*_HOST}variables)Deferred Tasks
Script references to legacy
main.pyneed to be updated in a separate PR after converting scripts to use proper logging (pre-commit hook enforces logging standards).Files affected:
scripts/utilities/fix_settings_loading.pyscripts/utilities/settings_diagnostic_utility.pyscripts/utilities/verify_backend_config.pytests/screenshots/test_security_endpoints.pyFirewall Port Cleanup
Firewall rules for ports 8000-8099 and 8090-8099 should be cleaned up via SLM config management, not direct ansible file edits. TODO markers added to track this.
Ready for Phase 1
Phase 0 cleanup is complete. Ready to proceed with Phase 1: Certificate Generation & Distribution when authorized.
mrveiss commentedon Jan 29, 2026
Implementation Complete ✅
All phases of mTLS migration have been implemented and committed to
Dev_new_guibranch.Commits
4728a935- Phase 0: Port cleanup, main.py deprecation, docker DEPRECATED.md4d2e2654- Phase 2-3: Migration script, backend TLS support04b92647- Phase 4: Celery mTLS, Windows NPU worker TLS2e3b5ea8- Phase 5-6: Verification, password auth removalFiles Modified/Created
scripts/security/mtls-migrate.pybackend/main.pybackend/celery_app.pyresources/windows-npu-worker/app/utils/redis_client.pymain.pydocker/DEPRECATED.mddocs/plans/2026-01-29-mtls-service-authentication-design.mddocs/plans/2026-01-29-port-cleanup-targets.mdMigration Workflow
Key Features
--rollback redisor--rollback redis-fullReady for Testing
The implementation is ready for deployment. Existing PKI infrastructure (valid until Oct 2026) will be used.
docs: Add mTLS migration design and cleanup targets (#725)
chore: Phase 0 cleanup for mTLS migration (#725)
feat(security): Add mTLS migration tooling and backend TLS support (#725
feat(security): Add mTLS support to Celery and NPU worker (#725)
feat(security): Add comprehensive mTLS verification and cutover (#725)
docs: Update system-state.md for mTLS migration (#725)
fix(security): Update mTLS migration for on-demand app workflow (#725)
19 remaining items
feat(slm): Add TLS certificate management via SLM API (#725)
feat(frontend): Add TLS certificate management UI (#725)
fix(slm): Use stored credentials for SSH and sudo in deployments (#725)
fix(redis): Use SSLConnection class for TLS connection pools (#725)
chore(security): Exclude dev_creds_backup from version control (#725)
feat(ansible): Add Phase 4 mTLS automation playbooks (#725)
feat(security): Add TLS support to all services - Phase 5 (#725)
refactor: Consolidate generate_request_id + add ConfigRegistry (#751) (…
feat(ansible): Implement role-specific UFW firewall rules (least priv…
chore(backend): remove stale TODO comments referencing closed issues (#…
chore(scripts): restore the new-arrival guard, close its baseline bli…
fix(redis): pass the rendered config to the daemon and converge four …
fix(redis): pass the rendered config to the daemon and converge four …
fix(redis): pass the rendered config to the daemon and converge four …
fix(redis): pass the rendered config to the daemon and converge four …