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
|
|
@ -59,11 +59,15 @@ type OPNsenseConfig struct {
|
|||
}
|
||||
|
||||
type ADConfig struct {
|
||||
Domain string `yaml:"domain"`
|
||||
BaseDN string `yaml:"base_dn"`
|
||||
Servers []string `yaml:"servers"`
|
||||
Port int `yaml:"port"`
|
||||
TLSMode string `yaml:"tls_mode"` // "ldaps" (Default) oder "starttls"
|
||||
Domain string `yaml:"domain"`
|
||||
BaseDN string `yaml:"base_dn"`
|
||||
Servers []string `yaml:"servers"`
|
||||
Port int `yaml:"port"`
|
||||
TLSMode string `yaml:"tls_mode"` // "ldaps" (Default) oder "starttls"
|
||||
// MinTLSVersion ist die niedrigste akzeptierte TLS-Version zum
|
||||
// Verzeichnisdienst: "1.0", "1.1", "1.2" (Default) oder "1.3".
|
||||
// Unter 1.2 nur für Altsysteme, die nichts Besseres können.
|
||||
MinTLSVersion string `yaml:"min_tls_version"`
|
||||
BindUser string `yaml:"bind_user"`
|
||||
BindPassword string `yaml:"bind_password"`
|
||||
BindPasswordFile string `yaml:"bind_password_file"`
|
||||
|
|
@ -94,9 +98,10 @@ func Defaults() *Config {
|
|||
Title: "VPN-Portal",
|
||||
},
|
||||
AD: ADConfig{
|
||||
Port: 636,
|
||||
TLSMode: "ldaps",
|
||||
Timeout: Duration(8 * time.Second),
|
||||
Port: 636,
|
||||
TLSMode: "ldaps",
|
||||
MinTLSVersion: "1.2",
|
||||
Timeout: Duration(8 * time.Second),
|
||||
},
|
||||
Matching: MatchingConfig{CNPattern: "{username}"},
|
||||
Logging: LoggingConfig{
|
||||
|
|
|
|||
|
|
@ -13,6 +13,15 @@ import (
|
|||
// UsernamePlaceholder ist der Platzhalter in matching.cn_pattern.
|
||||
const UsernamePlaceholder = "{username}"
|
||||
|
||||
// MinTLSVersions sind die zulässigen Werte für ad.min_tls_version.
|
||||
var MinTLSVersions = []string{"1.0", "1.1", "1.2", "1.3"}
|
||||
|
||||
// MinTLSVersionIsWeak meldet, ob die konfigurierte Mindestversion unter dem
|
||||
// heutigen Stand der Technik liegt. Das Portal warnt dann bei jedem Start.
|
||||
func (a ADConfig) MinTLSVersionIsWeak() bool {
|
||||
return a.MinTLSVersion == "1.0" || a.MinTLSVersion == "1.1"
|
||||
}
|
||||
|
||||
// BaseDNFromDomain leitet DC=firma,DC=local aus firma.local ab.
|
||||
func BaseDNFromDomain(domain string) (string, error) {
|
||||
domain = strings.Trim(strings.TrimSpace(domain), ".")
|
||||
|
|
@ -101,6 +110,10 @@ func (c *Config) Validate() error {
|
|||
if !slices.Contains([]string{"ldaps", "starttls"}, c.AD.TLSMode) {
|
||||
errs = append(errs, fmt.Errorf("ad.tls_mode %q ist ungültig (erlaubt: ldaps, starttls)", c.AD.TLSMode))
|
||||
}
|
||||
if !slices.Contains(MinTLSVersions, c.AD.MinTLSVersion) {
|
||||
errs = append(errs, fmt.Errorf("ad.min_tls_version %q ist ungültig (erlaubt: %s)",
|
||||
c.AD.MinTLSVersion, strings.Join(MinTLSVersions, ", ")))
|
||||
}
|
||||
if c.AD.Port <= 0 || c.AD.Port > 65535 {
|
||||
errs = append(errs, fmt.Errorf("ad.port %d liegt außerhalb 1–65535", c.AD.Port))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,48 @@ func TestValidateCollectsMultipleErrors(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMinTLSVersionDefaultsTo12(t *testing.T) {
|
||||
cfg := validCfg(t)
|
||||
if cfg.AD.MinTLSVersion != "1.2" {
|
||||
t.Errorf("MinTLSVersion = %q, want Default 1.2", cfg.AD.MinTLSVersion)
|
||||
}
|
||||
if err := cfg.Validate(); err != nil {
|
||||
t.Fatalf("Default muss gültig sein: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAcceptsLegacyMinTLSVersions(t *testing.T) {
|
||||
// Alte Domain Controller (z. B. Windows Server 2012 R2 mit abgeschaltetem
|
||||
// TLS 1.2) müssen erreichbar bleiben.
|
||||
for _, v := range []string{"1.0", "1.1", "1.2", "1.3"} {
|
||||
cfg := validCfg(t)
|
||||
cfg.AD.MinTLSVersion = v
|
||||
if err := cfg.Validate(); err != nil {
|
||||
t.Errorf("min_tls_version %q muss zulässig sein: %v", v, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRejectsUnknownMinTLSVersion(t *testing.T) {
|
||||
for _, v := range []string{"1.4", "tls1.2", "TLSv1", "", "12"} {
|
||||
cfg := validCfg(t)
|
||||
cfg.AD.MinTLSVersion = v
|
||||
if err := cfg.Validate(); err == nil {
|
||||
t.Errorf("min_tls_version %q muss abgelehnt werden", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMinTLSVersionIsWeakBelow12(t *testing.T) {
|
||||
cfg := validCfg(t)
|
||||
for v, wantWeak := range map[string]bool{"1.0": true, "1.1": true, "1.2": false, "1.3": false} {
|
||||
cfg.AD.MinTLSVersion = v
|
||||
if got := cfg.AD.MinTLSVersionIsWeak(); got != wantWeak {
|
||||
t.Errorf("MinTLSVersionIsWeak() für %q = %v, want %v", v, got, wantWeak)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRejectsPatternWithoutPlaceholder(t *testing.T) {
|
||||
cfg := validCfg(t)
|
||||
cfg.Matching.CNPattern = "fester-cn"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue