Skip to content

Add Active Directory winbind NTLM backend and Kerberos/KDC proxy fixes - #206

Open
etomm wants to merge 19 commits into
bolkedebruin:masterfrom
etomm:master
Open

etomm wants to merge 19 commits into
bolkedebruin:masterfrom
etomm:master

Conversation

@etomm

@etomm etomm commented Oct 24, 2026

Copy link
Copy Markdown

Summary

This PR adds Active Directory-backed NTLM authentication via Samba winbind, improves Kerberos negotiation handling, and fixes KDC proxy behavior for large Kerberos responses.

What changed

  • Added a configurable NTLM backend selection:
    • file backend remains the default
    • new winbind backend delegates authentication to Samba ntlm_auth
  • Added validation for NTLM config and tests for file/winbind configuration
  • Added backend abstraction for NTLM handshakes
  • Improved NTLM session lifecycle handling to avoid leaked or reused contexts
  • Added dynamic SPNEGO/keytab handling for Kerberos
  • Updated NTLM/Negotiate dispatch logic to distinguish NTLMSSP from Kerberos tokens
  • Fixed KDC proxy TCP/UDP handling and length-prefixed Kerberos messages
  • Added CI/devcontainer improvements and GHCR Docker publishing updates
  • Updated docs for NTLM winbind and Kerberos/KDC proxy setup

Why

  • Enables NTLM authentication against Microsoft Active Directory without storing passwords on the gateway
  • Fixes edge cases around large Kerberos tickets / PAC responses
  • Makes Kerberos and NTLM coexist more cleanly in stacked auth setups

liveinvalley and others added 13 commits October 1, 2026 11:11
Provides a Go 1.25 development container with the PAM headers and C
toolchain needed to build cmd/auth via cgo. Runs `make mod` on creation
since go.sum is not committed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NTLMAuth now only decodes the gRPC payload, dispatches on the NTLMSSP
message type and keeps one handshake context per session. The actual
verification moves behind a Backend/Context interface. The existing
go-ntlm based verifier against the configured user list becomes
LocalBackend; NewNTLMAuth keeps its signature and behavior.

Contexts are closed when a handshake finishes, restarts or expires from
the session cache, so backends can hold per-handshake resources.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WinbindBackend starts Samba's ntlm_auth in squid-2.5-ntlmssp helper mode
for every handshake and relays the NEGOTIATE and AUTHENTICATE messages
to it. ntlm_auth asks winbindd, which performs pass-through
authentication against an Active Directory domain controller, so the
helper never needs passwords or NT hashes.

Every exchange is bounded by a timeout, and the child process is
terminated when the handshake ends. --domain and
--require-membership-of are passed through, and the reported
DOMAIN\user name can optionally be stripped to the bare account name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ntlm.Backend selects between the existing "file" backend (default) and
the new "winbind" backend. Ntlm.Winbind configures the ntlm_auth path,
domain, required group membership, timeout and user name handling.

The configuration is validated at startup: unknown backends, a missing
ntlm_auth binary or a non-positive timeout are fatal. Validation lives
in Configuration.Validate so it can be unit tested, and Load no longer
accumulates state across calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A shell script speaking the squid-2.5-ntlmssp protocol stands in for
ntlm_auth, so the tests run without a domain. They cover successful and
rejected logons, command line flags, domain stripping, restarted
handshakes, timeouts with a hung helper, BH replies, a missing binary
and idempotent Close.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Document the winbind backend: domain join prerequisites, smb.conf
example, privileged pipe access, configuration keys, group restriction,
user name format, limitations, systemd changes and a troubleshooting
table for common NT_STATUS codes. Mention the option in the README and
the changelog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dockerfile.auth-winbind builds rdpgw-auth from the local source tree on
Alpine with samba-winbind, samba-winbind-clients (ntlm_auth) and krb5.
The entrypoint either starts winbindd in the container or uses a
domain-joined host's winbind, waits for it to answer, and runs
rdpgw-auth as UID 1001. The existing images are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o.sum

- Restructure workflow triggers: go.yml and docker-image.yml now run on
  pull requests (PR head) and version tags (v*) instead of every push to
  master, reducing duplicate CI work.
- Add concurrency groups with cancel-in-progress so new commits to an
  open PR supersede older in-progress runs.
- CodeQL now runs only on a weekly schedule (Wednesdays 22:22 UTC) on
  the default branch.
- Switch Docker builds from Docker Hub to GitHub Container Registry
  (ghcr.io), build from local source context instead of cloning a
  remote repo, and use go version 1.25.
- Track go.sum in version control for reproducible builds.
…and document Kerberos auth and DNS

- Fix map-to-slice panic when merging UDP and TCP KDC lists
- Use DialTimeout with per-KDC deadline instead of blocking Dial
- Read framed Kerberos messages (4-byte length prefix) over both UDP and TCP
- Return first successful reply instead of waiting on all KDCs
- Drain remaining reply channels to avoid goroutine leaks
- Add unit tests for UDP/TCP reply reading, end-to-end handler, fallback, and port defaulting
- Enrich identity log with HTTP method and URL path
- Document KDC Proxy transport (TCP over UDP preference) and DNS requirements
…ment NTLM authentication

- Add automatic AD domain join when AD_JOIN_USER and AD_JOIN_PASSWORD are set
- Wait cleanly for manual net ads join when secrets.tdb is missing instead of crashlooping
- Persist Samba state in /var/lib/samba across container restarts
- Add comprehensive Docker and Kubernetes deployment documentation for winbind NTLM auth
…tence settings with documentation

- Remove mutual exclusion check preventing NTLM and Kerberos stacking
- Introduce NegotiateAuthDispatcher to route raw NTLMSSP Negotiate tokens to NTLM handler and SPNEGO tokens to Kerberos/SPNEGO handler
- Add unit tests for NegotiateAuthDispatcher
- Document stacked authentication setup in Kerberos guide
…t, and documentation

- Implement DynamicKeytabProvider and DynamicSPNEGOKRB5Authenticate to automatically reload keytabs when modified on disk
- Automatically detect GatewayAddress from configuration and ensure corresponding SPN (HTTP/<GatewayAddress>) is present in keytab
- Add support for additional KERBEROS_SPNS environment variable
- Document dynamic keytab loading and automated SPN configuration in Kerberos guide
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants