TLS controls for the LDAP connection

The LDAP connection now supports using a custom CA certificate chain or
skipping all TLS certificate checks.
This commit is contained in:
Emmanuel BENOîT 2021-02-08 23:23:16 +01:00
parent 12634b9ffa
commit 842a4be87e
3 changed files with 49 additions and 25 deletions

View file

@ -52,8 +52,7 @@ go build
To Do To Do
------ ------
* Allow unchecked TLS * Add TLS options (skip checks / specify CA) for the Graylog API.
* Actually make the CA certificate option work
* Read object ownership using `grn_permissions` to preserve privileges on users' * Read object ownership using `grn_permissions` to preserve privileges on users'
own objects own objects
* Read group member records from the LDAP server and extract their username * Read group member records from the LDAP server and extract their username

View file

@ -17,6 +17,9 @@ ldap:
# connection. Defaults to "no". # connection. Defaults to "no".
tls: yes tls: yes
# Skip server certificate check. Defaults to false.
tls_skip_verify: false
# CA certificate chain. Can be omitted if the systems' trusted CAs must be # CA certificate chain. Can be omitted if the systems' trusted CAs must be
# used, or if no TLS is being used. # used, or if no TLS is being used.
cachain: /path/to/ca/chain.pem cachain: /path/to/ca/chain.pem

68
main.go
View file

@ -3,6 +3,7 @@ package main
import ( import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"crypto/x509"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -23,13 +24,15 @@ type (
// LDAP server configuration // LDAP server configuration
LdapConfig struct { LdapConfig struct {
Host string Host string
Port uint16 Port uint16
Tls string Tls string
CaChain string TlsNoVerify bool `yaml:"tls_skip_verify"`
BindUser string `yaml:"bind_user"` TlsAllowCnOnly bool `yaml:"tls_allow_cn_only"`
BindPassword string `yaml:"bind_password"` CaChain string
MemberFields []string `yaml:"member_fields"` BindUser string `yaml:"bind_user"`
BindPassword string `yaml:"bind_password"`
MemberFields []string `yaml:"member_fields"`
} }
// Graylog server configuration // Graylog server configuration
@ -231,29 +234,48 @@ func getGroupMembers(group string, conn *ldap.Conn, fields []string) (members []
return return
} }
// Read the list of group members from the LDAP server for all groups in the mapping section. // Establish a connection to the LDAP server
func readLdapGroups(configuration Configuration) (groups GroupMembers) { func getLdapConnection(cfg LdapConfig) (conn *ldap.Conn) {
var scheme string tlsConfig := &tls.Config{
if configuration.Ldap.Tls == "yes" { InsecureSkipVerify: cfg.TlsNoVerify,
scheme = "ldaps" }
if cfg.Tls != "no" && cfg.CaChain != "" {
data, err := ioutil.ReadFile(cfg.CaChain)
if err != nil {
log.Fatalf("failed to read CA certificate chain from %s", cfg.CaChain)
}
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(data) {
log.Fatalf("could not add CA certificates from %s", cfg.CaChain)
}
tlsConfig.RootCAs = pool
}
var err error
dest := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
if cfg.Tls == "yes" {
conn, err = ldap.DialTLS("tcp", dest, tlsConfig)
} else { } else {
scheme = "ldap" conn, err = ldap.Dial("tcp", dest)
} }
url := fmt.Sprintf("%s://%s:%d", scheme, configuration.Ldap.Host, configuration.Ldap.Port)
conn, err := ldap.DialURL(url)
if err != nil { if err != nil {
log.Fatalf("failed to connect to LDAP server %s: %v", configuration.Ldap.Host, err) log.Fatalf("failed to connect to LDAP server %s: %v", cfg.Host, err)
} }
defer conn.Close()
if configuration.Ldap.Tls == "starttls" { if cfg.Tls == "starttls" {
tlsConfig := tls.Config{} err = conn.StartTLS(tlsConfig)
// FIXME missing support for CA chain if err != nil {
if err := conn.StartTLS(&tlsConfig); err != nil { conn.Close()
log.Fatalf("LDAP server %s, StartTLS failed: %v", configuration.Ldap.Host, err) log.Fatalf("LDAP server %s, StartTLS failed: %v", cfg.Host, err)
} }
} }
return
}
// Read the list of group members from the LDAP server for all groups in the mapping section.
func readLdapGroups(configuration Configuration) (groups GroupMembers) {
conn := getLdapConnection(configuration.Ldap)
defer conn.Close()
if configuration.Ldap.BindUser != "" { if configuration.Ldap.BindUser != "" {
err := conn.Bind(configuration.Ldap.BindUser, configuration.Ldap.BindPassword) err := conn.Bind(configuration.Ldap.BindUser, configuration.Ldap.BindPassword)