{"id":49870389,"url":"https://github.com/docker-secret-operator/dso","last_synced_at":"2026-06-02T07:00:57.059Z","repository":{"id":349710500,"uuid":"1200129469","full_name":"docker-secret-operator/dso","owner":"docker-secret-operator","description":"Zero-persistence secret injection for Docker. CNCF Sandbox project. AWS, Azure, Vault support.","archived":false,"fork":false,"pushed_at":"2026-05-17T11:14:34.000Z","size":71909,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-17T11:30:44.938Z","etag":null,"topics":["cncf","cncf-sandbox","devops","docker","docker-plugin","kubernetes","secret-management","security"],"latest_commit_sha":null,"homepage":"https://dso.skycloudops.in","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/docker-secret-operator.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":"THREAT_MODEL.md","audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":"MAINTAINERS.md","copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-03T04:18:19.000Z","updated_at":"2026-05-17T11:14:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/docker-secret-operator/dso","commit_stats":null,"previous_names":["docker-secret-operator/dso"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/docker-secret-operator/dso","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/docker-secret-operator%2Fdso","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/docker-secret-operator%2Fdso/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/docker-secret-operator%2Fdso/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/docker-secret-operator%2Fdso/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/docker-secret-operator","download_url":"https://codeload.github.com/docker-secret-operator/dso/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/docker-secret-operator%2Fdso/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33810343,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-02T02:00:07.132Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cncf","cncf-sandbox","devops","docker","docker-plugin","kubernetes","secret-management","security"],"created_at":"2026-05-15T06:15:46.032Z","updated_at":"2026-06-02T07:00:57.052Z","avatar_url":"https://github.com/docker-secret-operator.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Docker Secret Operator (DSO)\n\n**Runtime secret injection and automatic rotation for Docker Compose — as a Docker CLI Plugin**\n\n[![Latest Release](https://img.shields.io/github/v/release/docker-secret-operator/dso?label=latest)](https://github.com/docker-secret-operator/dso/releases/latest)\n[![License](https://img.shields.io/github/license/docker-secret-operator/dso)](LICENSE)\n[![Go Report](https://goreportcard.com/badge/github.com/docker-secret-operator/dso)](https://goreportcard.com/report/github.com/docker-secret-operator/dso)\n[![Code Coverage](https://codecov.io/gh/docker-secret-operator/dso/branch/main/graph/badge.svg)](https://codecov.io/gh/docker-secret-operator/dso)\n\n\u003e **Current version: v3.5.17**  \n\u003e **Status**: CNCF Sandbox Ready ✅  \n\u003e **Governance**: [View GOVERNANCE.md](GOVERNANCE.md) | **Roadmap**: [View ROADMAP.md](ROADMAP.md)\n\n---\n\n## What is DSO?\n\nDSO is a runtime secret injection daemon for Docker and Docker Compose. It solves a concrete operational problem: **how to rotate secrets in containerized applications safely without exposing them to the host filesystem or Docker's metadata layers**.\n\n**In 30 seconds:**\n- Inject secrets from AWS Secrets Manager, Azure Key Vault, HashiCorp Vault, or local encrypted storage\n- Automatically rotate containers when secrets change — zero-downtime rolling swap by default\n- Keep secrets out of logs, `docker inspect`, and host disk\n- Single Docker host per agent (no Kubernetes required)\n\n---\n\n## Core Features\n\n| Feature | Description |\n|---------|-------------|\n| **Zero-Persistence** | Plaintext secrets never written to disk; held only in process memory and tmpfs |\n| **Rolling Rotation** | Zero-downtime blue-green container swap — new container starts, health-checked, old container stops |\n| **Multi-Provider** | Works with AWS Secrets Manager, Azure Key Vault, HashiCorp Vault, or local encrypted storage |\n| **Non-Root Operation** | Members of the `dso` group can run all standard commands without `sudo` |\n| **Deterministic Rollback** | Failed rotations automatically restore the previous container state |\n| **TCP Proxy** | DSO owns host port bindings (e.g. MySQL 3306) so traffic is never interrupted during rotation |\n| **Crash Recovery** | Agent restarts automatically recover orphaned containers and resume incomplete rotations |\n| **Production-Ready** | systemd integration, crash recovery, Prometheus metrics, comprehensive monitoring |\n| **No Swarm/Kubernetes** | Works with standard `docker compose` on any machine |\n\n---\n\n## Quick Start\n\n### For Local Development (2-3 minutes)\n\n```bash\n# 1. Install DSO\ncurl -fsSL https://raw.githubusercontent.com/docker-secret-operator/dso/main/scripts/install.sh | bash\n\n# 2. Run setup wizard for local mode\ndocker dso setup --mode local\n\n# 3. Initialize the local vault\ndocker dso init\n\n# 4. Store a secret\ndocker dso secret set myapp/db_password\n\n# 5. Add secret references to docker-compose.yaml\n# services:\n#   app:\n#     image: myapp:latest\n#     environment:\n#       DB_PASSWORD: dso://myapp/db_password\n\n# 6. Deploy\ndocker dso up -d\n\n# 7. Verify\ndocker dso doctor\ndocker dso status\n```\n\n### For Production (Agent Mode with Cloud Provider)\n\n```bash\n# 1. Install DSO system-wide\ncurl -fsSL https://raw.githubusercontent.com/docker-secret-operator/dso/main/scripts/install.sh | sudo bash\n\n# 2. Bootstrap agent mode (auto-detects cloud provider, configures systemd service)\nsudo docker dso bootstrap agent\n\n# 3. Configure your secrets\nsudo vi /etc/dso/dso.yaml\n\n# 4. Start the agent\nsudo systemctl start dso-agent\nsudo systemctl enable dso-agent\n\n# 5. Verify everything is healthy\ndocker dso doctor\ndocker dso status\n```\n\n### Local Development (no systemd)\n\n```bash\n# 1. Install DSO\ncurl -fsSL https://raw.githubusercontent.com/docker-secret-operator/dso/main/scripts/install.sh | bash\n\n# 2. Run setup wizard for local mode\ndocker dso setup --mode local\n\n# 3. Initialize the local vault\ndocker dso init\n\n# 4. Set a secret\ndocker dso secret set app/db_password\n\n# 5. Use in docker-compose.yaml\n# services:\n#   postgres:\n#     image: postgres:15\n#     environment:\n#       POSTGRES_PASSWORD_FILE: dsofile://app/db_password\n\n# 6. Deploy\ndocker dso up -d\n\n# 7. Verify\ndocker dso doctor\n```\n\n### Advanced: Non-interactive Setup\n\n```bash\n# Local mode (non-interactive)\ncurl -fsSL https://raw.githubusercontent.com/docker-secret-operator/dso/main/scripts/install.sh | bash\ndocker dso setup --mode local --non-interactive\ndocker dso init\n\n# Agent mode (non-interactive)\ncurl -fsSL https://raw.githubusercontent.com/docker-secret-operator/dso/main/scripts/install.sh | sudo bash\nsudo docker dso bootstrap agent --non-interactive --provider aws\n```\n\n---\n\n## How It Works\n\n```\nSecret Backend (AWS / Azure / Vault / Local)\n    ↓ polling every 30s–5m (adaptive)\nDSO Agent detects secret change\n    ↓\nAcquire distributed lock (prevent concurrent rotation)\n    ↓\nCreate new container with updated secret env\n    ↓\nHealth check new container\n    ↓\nAtomic swap (rename old → backup, new → active)\n    ↓\nDSO TCP Proxy re-routes traffic to new container\n    ↓\nStop old container\n    ↓\nRollback on failure (auto-restore previous state)\n```\n\n**Result**: Secrets never written to host disk. Zero-downtime rolling rotation completes in ~30 seconds. Failed rotations automatically restore the previous state.\n\n---\n\n## Installation\n\n### Prerequisites\n\n- **Docker** 20.10+ with `docker compose`\n- **Linux** (amd64, arm64) — macOS supported for local mode only\n- **systemd** — required for Cloud/Agent mode\n- **Non-root access** — add your user to the `dso` group after setup:\n  ```bash\n  sudo usermod -aG dso $USER\n  # log out and back in to apply\n  ```\n\n### Install\n\n```bash\n# System-wide install (recommended for production)\ncurl -fsSL https://raw.githubusercontent.com/docker-secret-operator/dso/main/scripts/install.sh | sudo bash\n\n# User install (local development only)\ncurl -fsSL https://raw.githubusercontent.com/docker-secret-operator/dso/main/scripts/install.sh | bash\n\n# Verify\ndocker dso version\ndocker dso doctor\n```\n\nSee **[Getting Started Guide](docs/getting-started.md)** for detailed setup instructions.\n\n---\n\n## Configuration\n\nConfiguration lives at `/etc/dso/dso.yaml` (Cloud/Agent mode) or `./dso.yaml` (Local mode).  \nMembers of the `dso` group can read and edit `/etc/dso/dso.yaml` without `sudo`.\n\n### Cloud Mode — AWS Example\n\n```yaml\n# /etc/dso/dso.yaml\nversion: v1.0.0\nmode: agent\n\nproviders:\n  aws:\n    type: aws\n    region: us-east-1\n    auth:\n      method: iam_role        # Uses EC2 instance role — no credentials in config\n    retry:\n      attempts: 3\n      backoff: \"1s\"\n\nagent:\n  cache: true\n  watch:\n    mode: polling\n    polling_interval: \"30s\"   # How often to check for secret changes\n  rotation:\n    enabled: true\n    strategy: rolling         # Zero-downtime blue-green swap (default)\n    health_check_timeout: \"30s\"\n\ndefaults:\n  inject:\n    type: env\n  rotation:\n    enabled: true\n    strategy: rolling\n\nsecrets:\n  - name: database_credentials\n    provider: aws\n    rotation:\n      enabled: true\n      strategy: rolling       # rolling | restart | signal | none\n    targets:\n      containers:\n        - mysql               # Container name (matches dso.reloader label)\n    mappings:\n      MYSQL_ROOT_PASSWORD: prod/mysql/root_password\n      MYSQL_PASSWORD: prod/mysql/app_password\n```\n\n### Cloud Mode — HashiCorp Vault Example\n\n```yaml\nversion: v1.0.0\nmode: agent\n\nproviders:\n  vault:\n    type: vault\n    auth:\n      method: token\n      params:\n        address: https://vault.example.com:8200\n        token: \"${VAULT_TOKEN}\"\n\nagent:\n  watch:\n    mode: polling\n    polling_interval: \"30s\"\n\nsecrets:\n  - name: app_secrets\n    provider: vault\n    mappings:\n      DB_PASSWORD: secret/data/prod/database/password\n      API_KEY: secret/data/prod/api/key\n```\n\n### Local Mode\n\n```yaml\n# ./dso.yaml\nversion: v1.0.0\nmode: local\n\nproviders:\n  local:\n    type: local\n    vault_file: ~/.dso/vault.enc\n    master_key_file: ~/.dso/master.key\n\nsecrets: {}\n```\n\nSee **[Configuration Reference](docs/configuration.md)** for all options.\n\n---\n\n## Docker Compose Integration\n\nLabel your containers so DSO knows which ones to manage:\n\n```yaml\n# docker-compose.yaml\nservices:\n  mysql:\n    image: mysql:8\n    labels:\n      dso.reloader: \"true\"                  # DSO will manage this container\n      dso.secrets: \"database_credentials\"   # Which secret to inject\n      dso.update.strategy: \"rolling\"        # Zero-downtime swap (default)\n      dso.host_ports: \"3306:3306\"           # DSO TCP Proxy owns this port binding\n    environment:\n      MYSQL_ROOT_PASSWORD: \"\"               # Injected at runtime by DSO\n      MYSQL_PASSWORD: \"\"\n    expose:\n      - \"3306\"                              # Expose internally; DSO proxy handles host binding\n\n  app:\n    image: myapp:latest\n    labels:\n      dso.reloader: \"true\"\n      dso.secrets: \"database_credentials\"\n      dso.update.strategy: \"rolling\"\n    environment:\n      DB_PASSWORD: \"\"                       # Injected at runtime by DSO\n```\n\nStart with:\n```bash\ndocker dso compose up    # Injects DSO labels and starts containers\n```\n\n---\n\n## Non-Root Access\n\nAfter running `docker dso setup` or `docker dso bootstrap agent`, all DSO directories and the agent socket are group-owned by `dso`:\n\n| Path | Permissions | Notes |\n|------|------------|-------|\n| `/etc/dso/` | `0775 root:dso` | Group members can list and read |\n| `/etc/dso/dso.yaml` | `0664 root:dso` | Group members can read and edit |\n| `/run/dso/dso.sock` | `0660 root:dso` | Group members can connect to agent |\n\nAdd your user to the `dso` group once and all DSO commands work without `sudo`:\n\n```bash\nsudo usermod -aG dso $USER\nnewgrp dso                   # Apply immediately without logout\n\n# These now work without sudo:\ndocker dso watch\ndocker dso status\ndocker dso compose up\nvi /etc/dso/dso.yaml\n\n# These still require sudo (system-level operations):\nsudo docker dso system enable\nsudo systemctl restart dso-agent\n```\n\n---\n\n## Architecture Overview\n\n```\nSecret Backends (AWS / Azure / Vault / Local)\n                ↓  polling / webhooks\n        DSO Agent Process  (systemd: dso-agent.service)\n    ┌──────────────────────────────────┐\n    │  Trigger Engine  (polling loop)  │\n    │  Reloader Controller             │\n    │  TCP Proxy Manager               │\n    │  State Tracker + Lock Manager    │\n    │  Provider Plugin System          │\n    │  Crash Recovery                  │\n    └──────────────────────────────────┘\n         │              │              │\n    IPC Socket     REST API      Docker Plugin Socket\n  /run/dso/dso.sock  :8471      /run/docker/plugins/dso.sock\n         │\n    Docker Host Containers\n```\n\n**Ports \u0026 Sockets**:\n\n| Endpoint | Default | Purpose |\n|----------|---------|---------|\n| `127.0.0.1:8471` | TCP | REST API — health, metrics, events, webhook |\n| `/run/dso/dso.sock` | Unix | IPC — CLI→agent communication |\n| `/run/docker/plugins/dso.sock` | Unix | Docker V2 secret driver plugin |\n| Dynamic (e.g. `3306`) | TCP | DSO TCP Proxy — owns container host port bindings |\n\n**Design principles**:\n- Single agent per Docker host\n- Timer-based adaptive polling (backs off up to 4× when no changes detected)\n- Blue-green rolling rotation with atomic container swap\n- Local state persistence for crash recovery\n- Plugin-based provider system (separate binaries per provider)\n\nSee **[Architecture Guide](docs/architecture.md)** for details.\n\n---\n\n## Operations\n\n### Monitor Status\n\n```bash\n# Real-time status\ndocker dso status\n\n# Watch metrics continuously\ndocker dso status --watch\n\n# JSON output for scripting\ndocker dso status --json\n```\n\n### Watch Rotations Live\n\n```bash\n# Live event stream (Docker events + DSO rotation events)\ndocker dso watch\n\n# With raw event payloads\ndocker dso watch --debug\n```\n\n### View Logs\n\n```bash\n# Follow agent logs (via journald)\ndocker dso system logs -f\n\n# View errors only\ndocker dso system logs -p err\n\n# Last hour\ndocker dso system logs --since 1h\n\n# Via REST API (when journald unavailable)\ndocker dso system logs --api --api-addr http://localhost:8471\n```\n\n### Health Check\n\n```bash\n# CLI health check\ndocker dso doctor\n\n# Full diagnostics\ndocker dso doctor --level full\n\n# REST health endpoint\ncurl http://localhost:8471/health\n\n# Validate config\ndocker dso config validate\n```\n\n### Service Management\n\n```bash\n# Start / stop / restart\nsudo systemctl start dso-agent\nsudo systemctl stop dso-agent\nsudo systemctl restart dso-agent\n\n# Enable / disable autostart\nsudo docker dso system enable\nsudo docker dso system disable\n\n# View service status\nsudo docker dso system status\n```\n\nSee **[Operational Guide](docs/operational-guide.md)** for day-2 operations, monitoring, and recovery procedures.\n\n---\n\n## Rotation Strategies\n\n| Strategy | Behaviour | Use Case |\n|----------|-----------|---------|\n| `rolling` | Zero-downtime blue-green swap. New container starts, health-checked, old container stops. DSO TCP Proxy holds port bindings. | **Default — production databases, APIs** |\n| `restart` | Stop old container, start new container with updated env. Brief downtime. | Stateless services where downtime is acceptable |\n| `signal` | Send SIGHUP to running container (no restart). | Applications that reload config on SIGHUP |\n| `none` | Update secret cache only, no container action. | Manual rotation workflows |\n\nConfigure per-secret or globally in `dso.yaml`:\n\n```yaml\ndefaults:\n  rotation:\n    strategy: rolling           # applies to all secrets unless overridden\n\nsecrets:\n  - name: api_keys\n    rotation:\n      strategy: signal          # override for this secret only\n```\n\nOr per-container via label:\n\n```yaml\nlabels:\n  dso.update.strategy: \"rolling\"\n```\n\n---\n\n## Limitations\n\nDSO is optimized for **single-host Docker Compose environments**:\n\n| Limit | Details |\n|-------|---------|\n| **Scope** | Single Docker host per agent (no multi-host coordination) |\n| **State** | Local persistence only (no distributed consensus) |\n| **Locking** | File-based locking (scales to ~100s of secrets) |\n| **Recovery** | Some edge cases require manual operator recovery (documented) |\n| **Isolation** | Assumes Docker daemon is trusted and secure |\n\n**Not recommended for**: Kubernetes (use ExternalSecrets Operator), multi-host setups, 1000+ secrets per agent, multi-tenant strict isolation.\n\n---\n\n## Security Model\n\n**Core principle**: Plaintext secrets never touch the host filesystem.\n\n- Secrets held only in process memory and container tmpfs\n- AES-256-GCM encryption for local vault\n- Log redaction (secrets never appear in logs)\n- File injection invisible to `docker inspect`\n- Agent IPC socket restricted to `root:dso` group (`0660`)\n- Docker plugin socket restricted to root only (`0600`)\n- Automatic cleanup on container stop/restart\n\nSee **[Security Model](SECURITY.md)** for detailed threat analysis and guarantees.\n\n---\n\n## Examples\n\nWorking examples for common providers:\n\n- **Local Development** — [examples/](examples/)\n- **AWS Secrets Manager** — [examples/aws-compose/](examples/aws-compose/)\n- **Azure Key Vault** — [examples/azure-compose/](examples/azure-compose/)\n- **HashiCorp Vault** — [examples/hashicorp-vault/](examples/hashicorp-vault/)\n- **Huawei Cloud KMS** — [examples/huawei-compose/](examples/huawei-compose/)\n\n---\n\n## Documentation\n\n| Document | Purpose |\n|----------|---------|\n| **[Getting Started](docs/getting-started.md)** | Installation \u0026 first deployment |\n| **[CLI Reference](docs/cli.md)** | Complete command reference |\n| **[Configuration](docs/configuration.md)** | YAML schema \u0026 all options |\n| **[Providers](docs/providers.md)** | Provider-specific setup guides |\n| **[Architecture](docs/architecture.md)** | System design \u0026 internals |\n| **[Operational Guide](docs/operational-guide.md)** | Day-2 operations \u0026 monitoring |\n| **[Recovery Procedures](docs/RECOVERY_PROCEDURES.md)** | Failure recovery \u0026 troubleshooting |\n| **[Security Model](SECURITY.md)** | Threat analysis \u0026 guarantees |\n| **[Persistence Model](docs/PERSISTENCE_MODEL.md)** | What data DSO persists |\n\n---\n\n## Support \u0026 Contributing\n\n- **Issues**: [Report bugs](https://github.com/docker-secret-operator/dso/issues)\n- **Discussions**: [Community Q\u0026A](https://github.com/docker-secret-operator/dso/discussions)\n- **Security**: umairmd385@gmail.com\n- **Contributing**: [CONTRIBUTING.md](CONTRIBUTING.md)\n\n---\n\n## License\n\nDSO is licensed under the **[Apache 2.0](LICENSE)**.\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdocker-secret-operator%2Fdso","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdocker-secret-operator%2Fdso","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdocker-secret-operator%2Fdso/lists"}