Securing Docker Registry with LDAP Authentication Using Goma Gateway

Jonas KanindaJonas Kaninda
4 min read

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 Gateway

  • lldap: LDAP server

  • registry: Docker Registry

  • okapi-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:

  1. Replace LLDAP_JWT_SECRET and LLDAP_KEY_SEED with strong random values

  2. Change 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

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.

0
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.