feat(auth): konfigurierbare TLS-Mindestversion fuer den Verzeichnisdienst
Domain Controller auf Windows Server 2012 R2 koennen TLS 1.2 per Registry deaktiviert haben. ad.min_tls_version (Default 1.2) erlaubt es, fuer solche Altsysteme auf 1.0/1.1 herunterzugehen; das Portal warnt dann bei jedem Start. Die Zertifikatspruefung bleibt in jedem Fall aktiv — fuer LDAP gibt es weiterhin keine Insecure-Option. Im Legacy-Modus kommen lediglich die CBC-SHA256-Suiten hinzu, die Go als unsicher einstuft; RC4, 3DES und Suiten ohne Forward Secrecy werden nie angeboten. README dokumentiert zusaetzlich die beiden anderen 2012-R2-Stolpersteine: SHA-1-signierte DC-Zertifikate (seit Go 1.24 nicht mehr umgehbar) und RSA-Schluesselaustausch (nur ueber GODEBUG=tlsrsakex=1). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBHF4R9EAejDJUMdwr6C68
This commit is contained in:
parent
a2bce25424
commit
0fc2d8808b
10 changed files with 299 additions and 25 deletions
|
|
@ -26,10 +26,36 @@ type ldapConn struct{ *ldap.Conn }
|
|||
|
||||
func (c ldapConn) Close() error { c.Conn.Close(); return nil }
|
||||
|
||||
// tlsConfigFor baut die TLS-Konfiguration. Verifikation ist immer aktiv —
|
||||
// für LDAP gibt es bewusst keine Insecure-Option.
|
||||
func tlsConfigFor(server, caFile string) (*tls.Config, error) {
|
||||
cfg := &tls.Config{ServerName: server, MinVersion: tls.VersionTLS12}
|
||||
// ParseTLSVersion übersetzt "1.0".."1.3" in die Konstante von crypto/tls.
|
||||
// Ein leerer oder unbekannter Wert ergibt TLS 1.2 — im Zweifel das Sichere.
|
||||
func ParseTLSVersion(s string) uint16 {
|
||||
switch s {
|
||||
case "1.0":
|
||||
return tls.VersionTLS10
|
||||
case "1.1":
|
||||
return tls.VersionTLS11
|
||||
case "1.3":
|
||||
return tls.VersionTLS13
|
||||
default:
|
||||
return tls.VersionTLS12
|
||||
}
|
||||
}
|
||||
|
||||
// tlsConfigFor baut die TLS-Konfiguration. Die Zertifikatsprüfung ist immer
|
||||
// aktiv — für LDAP gibt es bewusst keine Insecure-Option. Lediglich die
|
||||
// Protokoll-Mindestversion ist konfigurierbar, damit Altsysteme wie ein
|
||||
// Windows Server 2012 R2 ohne TLS 1.2 erreichbar bleiben.
|
||||
func tlsConfigFor(server, caFile string, minVersion uint16) (*tls.Config, error) {
|
||||
if minVersion == 0 {
|
||||
minVersion = tls.VersionTLS12
|
||||
}
|
||||
cfg := &tls.Config{ServerName: server, MinVersion: minVersion}
|
||||
if minVersion < tls.VersionTLS12 {
|
||||
// Go bietet die CBC-Suiten alter Schannel-Stacks nicht mehr von sich
|
||||
// aus an. Ohne sie scheitert der Handshake mit einem 2012 R2, der auf
|
||||
// TLS 1.0/1.1 festgenagelt ist, bereits an der Cipher-Auswahl.
|
||||
cfg.CipherSuites = legacyCipherSuites()
|
||||
}
|
||||
if caFile == "" {
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
@ -45,10 +71,32 @@ func tlsConfigFor(server, caFile string) (*tls.Config, error) {
|
|||
return cfg, nil
|
||||
}
|
||||
|
||||
// legacyCipherSuites ergänzt Gos sichere Vorgaben um die CBC-SHA256-Suiten,
|
||||
// die Go als unsicher einstuft und deshalb nicht von sich aus anbietet, die
|
||||
// aber auf alten Schannel-Stacks vorkommen.
|
||||
//
|
||||
// Die Suiten mit reinem RSA-Schlüsselaustausch (TLS_RSA_*) sind bewusst NICHT
|
||||
// dabei: Go schaltet sie seit 1.22 unabhängig von dieser Liste ab. Braucht ein
|
||||
// Domain Controller sie zwingend, hilft nur GODEBUG=tlsrsakex=1 in der
|
||||
// systemd-Unit — siehe README.
|
||||
//
|
||||
// Wird nur benutzt, wenn der Betreiber die Mindestversion ausdrücklich unter
|
||||
// TLS 1.2 gesetzt hat.
|
||||
func legacyCipherSuites() []uint16 {
|
||||
out := make([]uint16, 0, len(tls.CipherSuites())+2)
|
||||
for _, cs := range tls.CipherSuites() {
|
||||
out = append(out, cs.ID)
|
||||
}
|
||||
return append(out,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||
)
|
||||
}
|
||||
|
||||
// realDialer erzeugt die Dial-Funktion für den Produktivbetrieb.
|
||||
func realDialer(port int, tlsMode, caFile string, timeout time.Duration) func(context.Context, string) (conn, error) {
|
||||
func realDialer(port int, tlsMode, caFile string, minVersion uint16, timeout time.Duration) func(context.Context, string) (conn, error) {
|
||||
return func(ctx context.Context, server string) (conn, error) {
|
||||
tlsCfg, err := tlsConfigFor(server, caFile)
|
||||
tlsCfg, err := tlsConfigFor(server, caFile, minVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue