README
¶
ContainerVault
ContainerVault is a Go-based forward proxy layered on top of the official self-hosted Docker Registry, enhancing it with LDAP-based authentication and a web UI for navigating namespaces, repositories, tags, and detailed image information.
Features
- LDAP login with namespace-scoped access control.
- Docker registry proxy (TLS-terminated) with push/pull/delete enforcement.
- Web UI for repositories, tags, digests, layers, and history (includes tag delete and refresh).
- Huma v2 API under
/apifor the UI. - Docker Compose stack for local testing.
Quick start
- Build and start the stack:
docker compose up -d --build
- Open the UI (self-signed cert):
https://localhost/login
Docker Compose example
Minimal compose file (registry + ContainerVault):
version: "3.8"
services:
registry:
image: registry:2
container_name: registry
restart: always
volumes:
- ./data:/var/lib/registry
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
REGISTRY_HTTP_ADDR: :5000
REGISTRY_STORAGE_DELETE_ENABLED: true
container-vault:
build: ./
container_name: container-vault
restart: always
ports:
- "443:8443"
depends_on:
- registry
environment:
REGISTRY_UPSTREAM: http://registry:5000
LDAP configuration example (add to the ContainerVault service):
environment:
REGISTRY_UPSTREAM: http://registry:5000
LDAP_URL: ldaps://ldap:389
LDAP_BASE_DN: dc=glauth,dc=com
LDAP_USER_FILTER: (mail=%s)
LDAP_GROUP_ATTRIBUTE: memberOf
LDAP_GROUP_PREFIX: team
LDAP_USER_DOMAIN: "@example.com"
LDAP_STARTTLS: "false"
LDAP_SKIP_TLS_VERIFY: "true"
Permission model
Group names must end in one of the supported suffixes; groups without a suffix are ignored.
_r: read/pull only_rw: read + write (push)_rd: read + delete_rwd: read + write + delete
Group names are derived from LDAP DNs (e.g. cn=team1_rw,ou=groups,... -> team1_rw). The LDAP_GROUP_PREFIX filter is applied before suffix parsing.
Namespaces are mapped by stripping the permission suffix from the group name (e.g. team1_rwd -> namespace team1); only groups that start with the configured prefix and end with a supported suffix are considered.
Example: group team1_rwd maps to namespace team1, so a push looks like docker push localhost/team1/alpine:test.
API
All API endpoints are under /api and require a session cookie (cv_session), issued after login.
GET /api/dashboardGET /api/catalog?namespace=<ns>GET /api/repos?namespace=<ns>GET /api/tags?repo=<ns>/<repo>GET /api/taginfo?repo=<ns>/<repo>&tag=<tag>GET /api/taglayers?repo=<ns>/<repo>&tag=<tag>DELETE /api/tag?repo=<ns>/<repo>&tag=<tag>
OpenAPI/Docs endpoints are disabled by default in main.go (paths set to empty). To enable, set apiCfg.OpenAPIPath, apiCfg.DocsPath, and apiCfg.SchemasPath.
Registry proxy
Registry requests go through /v2/* and require HTTP Basic Auth. Access is restricted to namespaces derived from the authenticated LDAP groups and permission suffixes.
Configuration
LDAP settings are loaded from environment variables:
LDAP_URL(default:ldaps://ldap:389)LDAP_BASE_DN(default:dc=glauth,dc=com)LDAP_USER_FILTER(default:(mail=%s))LDAP_GROUP_ATTRIBUTE(default:memberOf)LDAP_GROUP_PREFIX(default:team)LDAP_USER_DOMAIN(default:@example.com)LDAP_STARTTLS(default:false)LDAP_SKIP_TLS_VERIFY(default:true)
TLS with Certmagic (optional):
CERTMAGIC_ENABLE(default:false)CERTMAGIC_DOMAINS(comma-separated, required when enabled)CERTMAGIC_EMAIL(optional ACME account email)CERTMAGIC_CA(custom ACME directory URL)CERTMAGIC_CA_ROOT(path to a PEM CA root cert for the ACME server)CERTMAGIC_STORAGE(path for cert storage; defaults to certmagic's standard location)CERTMAGIC_HTTP_PORT(alternate HTTP-01 port if your ACME server supports it)CERTMAGIC_TLS_ALPN_PORT(alternate TLS-ALPN port; defaults to 8443 to match the internal listener)
When Certmagic is enabled, ContainerVault uses ACME with TLS-ALPN challenge by default and serves with the managed certificate. The service listens on 8443 internally, so map host 443 to container 8443 for ACME validation.
The registry upstream URL is currently configured in config.go (default: http://registry:5000, matching docker-compose.yml).
Test with glauth/glauth LdapServer
Test LDAP users in testldap/default-config.cfg:
hackers/dogoodjohndoe/dogoodserviceuser/mysecret
Minimal compose file (ldap):
ldap:
image: glauth/glauth
container_name: ldap
restart: always
ports:
- "389:389"
volumes:
- ./testldap/default-config.cfg:/app/config/config.cfg
- ./testldap/key.pem:/app/config/key.pem
- ./testldap/cert.pem:/app/config/cert.pem
UI build
If you edit ui/ui.ts, rebuild the static assets:
npm --prefix ui run build:ui
The build outputs to static/.
Tests
Run unit and integration tests:
go test ./...
Integration tests use Docker/testcontainers, and the proxy push/pull test relies on the Docker CLI.
License
Unlicense. See LICENSE.
Documentation
¶
There is no documentation for this package.