Systemd Ansible Deployment
ContextUnity defines a 100% native systemd deployment pipeline managed neutrally and idempotently via Ansible configuration management. Containers are strictly deprecated for operational service runtimes inside production deployments, ensuring host reliability and bare-metal speed native memory management.
Declarative Pipeline
- Host Environment Prep: The
infrastructure/ansiblerole bootstraps your host (LXC, VM, bare metal), installing system dependencies such asuv, Git, and core service components (PostgreSQL, Redis, Temporal). - ContextUnity Sourcing: The codebase is synced to
/opt/contextunity/usingrsyncorgit. - Dependency Isolation: The role sets up a separate virtual environment (
.venv) forpackages/coreand for each service inside/opt/contextunity/{svc}/and installs packages viauv pip install. - YAML Config Rendering: Jinja2 templates (
{service}.yml.j2) are rendered to the service working directory (/opt/contextunity/{service}/{service}.yml). Secret keys are strictly kept out of this layer. - Encrypted Credentials provisioning: Non-plaintext secrets are encrypted at deploy time via
systemd-credsand stored in/etc/credstore.encrypted/. - Service Life Cycle: Service unit descriptors are deployed to
/etc/systemd/system/contextunity-{svc}.serviceand enabled/restarted.
Systemd Process Orchestration
ContextUnity services execute directly within their respective virtual environments:
[Service]Type=simpleUser=contextunityGroup=contextunityWorkingDirectory=/opt/contextunity/brainEnvironmentFile=/opt/contextunity/brain/.envExecStart=/opt/contextunity/brain/.venv/bin/contextbrain serveRestart=on-failureRestartSec=5sTimeoutStopSec=30KillMode=mixedKillSignal=SIGTERM- Graceful Shutdown: Every service handles
SIGTERMcleanly (viagraceful_shutdown()async handlers) and shuts down gracefully within theTimeoutStopSeclimit. - Logging: Standard output and error are piped to
journaldfor central telemetry collection and monitoring.
Systemd Credentials (Secret Hardening)
ContextUnity utilizes systemd-creds for encrypting secrets at rest. Plaintext secrets are strictly prohibited in configuration files or .env files in production. Instead, secrets are encrypted by Ansible during deployment to /etc/credstore.encrypted/ and decrypted dynamically at service startup by systemd into memory-only paths under CREDENTIALS_DIRECTORY.
How it works
-
Ansible provisions encrypted credentials during deployment:
# In cu_service role — deploy_one.yml- name: Provision encrypted systemd credentialsshell: |printf '%s' '{{ item.value }}' | systemd-creds encrypt \--name={{ item.name }} - \/etc/credstore.encrypted/{{ svc }}_{{ item.name }}loop: "{{ svc_cfg.credentials | default([]) }}"no_log: true -
Systemd unit loads credentials at service start:
# In service.j2 templateLoadCredentialEncrypted=shield_master_key:/etc/credstore.encrypted/shield_shield_master_key -
Automatic Resolution: When loading configs, the core config factory automatically retrieves mapped keys (e.g.
shield_master_key) via_read_credential(), which checks the systemd path first:# In contextunity.core.config.env:# Checks $CREDENTIALS_DIRECTORY/shield_master_key first, falls back to env var SHIELD_MASTER_KEYsecret = _read_credential("shield_master_key")
Managed Secrets Inventory
| Service | Credential Name | Env Fallback Variable | Purpose |
|---|---|---|---|
| Shield | shield_master_key | SHIELD_MASTER_KEY | Authority master key |
| Shield | shield_encryption_key | SHIELD_ENCRYPTION_KEY | Payload database encryptor |
| Router | openai_api_key | OPENAI_API_KEY | OpenAI API access |
| Router | inception_api_key | INCEPTION_API_KEY | Inception API access |
| Router | langfuse_secret_key | LANGFUSE_SECRET_KEY | Langfuse monitoring key |
| Brain | brain_database_url | BRAIN_DATABASE_URL | PostgreSQL connection string |
| View | django_secret_key | DJANGO_SECRET_KEY | Django session signing |
| All | redis_secret_key | REDIS_SECRET_KEY | Redis payload encryptor |
| All | cu_project_secret | CU_PROJECT_SECRET | ContextToken signature secret |
Ansible Configuration
Secrets are defined securely inside inventory groups (using Ansible Vault for encryption) and mapped inside cu_service_config in group_vars/all/vars.yml:
cu_service_config: shield: description: "ContextShield -- Security Authority" exec: "contextshield serve --port {{ service_ports.shield }}" port: "{{ service_ports.shield }}" env_template: shield.env.j2 config_template: shield.yml.j2 credentials: - { name: shield_master_key, value: "{{ shield_master_key }}" } - { name: shield_encryption_key, value: "{{ vault_shield_encryption_key }}" } - { name: redis_secret_key, value: "{{ redis_secret_key }}" } - { name: cu_project_secret, value: "{{ view_project_secret }}" }Security Hardening
All deployed service units enforce process isolation and hardening guidelines:
[Service]NoNewPrivileges=trueProtectSystem=strictReadWritePaths=/tmp /var/log/contextunity /opt/contextunity/corePrivateTmp=trueCombined with systemd-creds, this guarantees that:
- Secrets are encrypted at rest on disk inside
/etc/credstore.encrypted/(with strict0700root permissions). - Secrets are decrypted only in memory by the systemd service supervisor.
- Secrets are never exposed in plaintext
.envfiles, logs, or process environment tables.