Securing Docker Registry with LDAP Authentication Using Goma Gateway


Introduction
Securing a self-hosted Docker Registry is crucial, especially in production environments. LDAP (Lightweight Directory Access Protocol) is a widely adopted standard for managing user authentication and access control across services.
In this tutorial, we’ll use Goma Gateway to secure a Docker Registry using LLDAP for authentication. Goma makes it easy to protect routes with built-in middleware and declarative configuration.
Prerequisites
Docker and Docker Compose installed
Basic understanding of:
Docker networking
Reverse proxies
LDAP concepts
Architecture Overview
1. What Is Goma Gateway?
Goma Gateway is a lightweight, high-performance, and security-first API Gateway built for modern cloud-native infrastructure. With a developer-friendly configuration, Goma supports powerful middleware, observability, and advanced protocols out of the box.
Key Features
Built-in authentication: Basic, JWT, OAuth2, LDAP, and ForwardAuth
Rate limiting, HTTP caching, and bot detection
Observability: Prometheus metrics, route health checks
Protocol support: REST, gRPC, TCP, UDP
TLS support: Let’s Encrypt and custom certificates
GitHub: jkaninda/goma-gateway
2. What Is LLDAP?
LLDAP is a lightweight, opinionated LDAP server designed to simplify authentication. It’s easy to deploy and comes with a minimal web UI for managing users and groups.
GitHub: lldap/lldap
3. Configure Local Hosts
Edit your /etc/hosts
file to define virtual domains:
127.0.0.1 lldap.example.com registry.example.com okapi-api.example.com
Replace example.com
With your domain, if needed.
4. Create a Docker Network
Create a shared Docker network for all services:
docker network create web
5. Docker Compose Setup
Create a compose.yaml
file with the following services:
gateway
: Goma Gatewaylldap
: LDAP serverregistry
: Docker Registryokapi-api
: A test API service
services:
gateway:
image: jkaninda/goma-gateway
container_name: gateway
restart: always
volumes:
- ./goma.yml:/etc/goma/goma.yml
- ./extra:/etc/goma/extra
- ./certs:/etc/goma/certs
ports:
- 80:80
- 443:443
networks: [web]
lldap:
image: lldap/lldap:stable
container_name: lldap
restart: always
environment:
- UID=1
- GID=1
- TZ=Europe/Paris
- LLDAP_JWT_SECRET=REPLACE_WITH_RANDOM
- LLDAP_KEY_SEED=REPLACE_WITH_RANDOM
- LLDAP_LDAP_BASE_DN=dc=example,dc=com
- LLDAP_LDAP_USER_PASS=adminPasword
ports:
- "3890:3890"
volumes:
- data:/data
networks: [web]
registry:
image: registry:3.0.0
container_name: registry
restart: always
volumes:
- registry:/var/lib/registry
networks: [web]
okapi-api:
image: jkaninda/okapi-example
container_name: okapi-api
restart: always
networks: [web]
volumes:
data: {}
registry: {}
networks:
web:
external: true
Important Security Notes:
Replace
LLDAP_JWT_SECRET
andLLDAP_KEY_SEED
with strong random valuesChange default
LLDAP_LDAP_USER_PASS
6. Goma Gateway Configuration
Create a file named goma.yml
in the project root:
version: 2
gateway:
entryPoints:
web:
address: "[::]:80"
webSecure:
address: "[::]:443"
tls:
keys: []
# Uncomment for custom certs:
# - cert: /etc/goma/certs/cert.crt
# key: /etc/goma/certs/server.key.pem
log:
level: info
networking:
transport:
insecureSkipVerify: true
monitoring:
enableMetrics: true
metricsPath: /metrics
enableLiveness: true
enableRouteHealthCheck: true
includeRouteHealthErrors: true
extraConfig:
directory: /etc/goma/extra
watch: true
certManager:
provider: acme
acme:
# Uncomment to enable Let’s Encrypt
# email: admin@example.com
storageFile: /etc/letsencrypt/acme.json
7. Define Routes and Middlewares
Create a folder named extra
and add two files: routes.yml
and middlewares.yml
.
extra/routes.yml
routes:
- name: lldap
path: /
hosts: [lldap.example.com]
target: http://lldap:17170
middlewares: [enforceHttps]
- name: registry
path: /
hosts: [registry.example.com]
rewrite: ''
target: http://registry:5000
middlewares: [enforceHttps]
- name: okapi-api
path: /
hosts: [okapi-api.example.com]
rewrite: ''
target: http://okapi-api:8080
middlewares: [enforceHttps]
extra/middlewares.yml
middlewares:
- name: enforceHttps
type: redirectScheme
rule:
scheme: https
permanent: true
8. Deployment
Launch all services:
docker compose up -d
9. Insecure Registry Configuration
If you haven't configured TLS yet, Docker needs to allow connections to the insecure registry (development only):
Create or edit /etc/docker/daemon.json
:
{
"insecure-registries": ["registry.example.com"]
}
Restart Docker:
sudo systemctl restart docker
Tip: Use Let’s Encrypt or a custom certificate for production environments.
10. Access Your Services
LDAP UI: https://lldap.example.com Login with
admin / adminPasword
. Then:Create a group:
registry_users
Create a user:
bind_user
(add tolldap_strict_readonly
)Create another user and assign them to
registry_users
Okapi API: https://okapi-api.example.com/api/books
Docker Registry API: https://registry.example.com/v2/_catalog
11. Enable LDAP Authentication
Update middlewares.yml
with LDAP auth middleware:
- name: ldap-auth
type: ldap
paths:
- /.*
rule:
forwardUsername: true
realm: restricted
url: ldap://lldap:3890
baseDN: dc=example,dc=com
bindDN: uid=bind_user,ou=people,dc=example,dc=com
bindPass: bind_user_password
userFilter: "(&(objectclass=person)(memberof=cn=registry_users,ou=groups,dc=example,dc=com)(uid=%s))"
startTLS: false
insecureSkipVerify: true
connPool:
size: 150
burst: 100
ttl: 30s
Then apply it in routes.yml
:
- name: registry
path: /
hosts: [registry.example.com]
rewrite: ''
target: http://registry:5000
middlewares:
- enforceHttps
- ldap-auth
- name: okapi-api
path: /
hosts: [okapi-api.example.com]
rewrite: ''
target: http://okapi-api:8080
middlewares:
- enforceHttps
- ldap-auth
12. Test the Registry
Pull the Nginx image:
docker pull nginx:latest
Tag the image:
docker tag nginx:latest registry.example.com/nginx:latest
Push to your registry:
docker push registry.example.com/nginx:latest
You should be prompted for credentials, and only LDAP-authorized users will be able to push or pull.
Conclusion
You’ve successfully secured your Docker Registry using Goma Gateway and LLDAP. With just a few declarative configs and containers, you now have a robust, LDAP-backed authentication layer for your registry and a reusable pattern for protecting any internal API or service.
Feel free to extend this setup to protect other services and APIs with Goma’s flexible middleware system.
Subscribe to my newsletter
Read articles from Jonas Kaninda directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Jonas Kaninda
Jonas Kaninda
I’m a Software Engineer with over 5 years of hands-on experience building scalable, reliable systems. My expertise spans Kotlin, Spring Boot, Go (Golang), MySQL, PostgreSQL, and Linux systems, with a strong focus on DevOps, Docker, and Kubernetes. Programming is more than a job, it's my passion. I’m driven by curiosity, constantly exploring new tools, frameworks, and architectural patterns to stay at the forefront of the tech landscape. I'm a strong advocate of Open Source and enjoy building tools that simplify infrastructure and developer workflows. My OSS contributions include solutions for database backup/migration, encryption, API Gateway management, and Kubernetes Operators. My current interests revolve around: Cloud-native architecture Microservices and API frameworks DevOps & GitOps practices SRE and DevSecOps principles I bring experience in designing, deploying, and maintaining modern software systems, with a deep understanding of CI/CD pipelines, infrastructure automation, and container orchestration. I thrive in both collaborative environments and independent work—always aiming for clean, maintainable code and high-impact solutions.