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
------
* Allow unchecked TLS
* Actually make the CA certificate option work
* Add TLS options (skip checks / specify CA) for the Graylog API.
* Read object ownership using `grn_permissions` to preserve privileges on users'
own objects
* Read group member records from the LDAP server and extract their username

View file

@ -17,6 +17,9 @@ ldap:
# connection. Defaults to "no".
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
# used, or if no TLS is being used.
cachain: /path/to/ca/chain.pem

62
main.go
View file

@ -3,6 +3,7 @@ package main
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"io"
@ -26,6 +27,8 @@ type (
Host string
Port uint16
Tls string
TlsNoVerify bool `yaml:"tls_skip_verify"`
TlsAllowCnOnly bool `yaml:"tls_allow_cn_only"`
CaChain string
BindUser string `yaml:"bind_user"`
BindPassword string `yaml:"bind_password"`
@ -231,30 +234,49 @@ func getGroupMembers(group string, conn *ldap.Conn, fields []string) (members []
return
}
// Establish a connection to the LDAP server
func getLdapConnection(cfg LdapConfig) (conn *ldap.Conn) {
tlsConfig := &tls.Config{
InsecureSkipVerify: cfg.TlsNoVerify,
}
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 {
conn, err = ldap.Dial("tcp", dest)
}
if err != nil {
log.Fatalf("failed to connect to LDAP server %s: %v", cfg.Host, err)
}
if cfg.Tls == "starttls" {
err = conn.StartTLS(tlsConfig)
if err != nil {
conn.Close()
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) {
var scheme string
if configuration.Ldap.Tls == "yes" {
scheme = "ldaps"
} else {
scheme = "ldap"
}
url := fmt.Sprintf("%s://%s:%d", scheme, configuration.Ldap.Host, configuration.Ldap.Port)
conn, err := ldap.DialURL(url)
if err != nil {
log.Fatalf("failed to connect to LDAP server %s: %v", configuration.Ldap.Host, err)
}
conn := getLdapConnection(configuration.Ldap)
defer conn.Close()
if configuration.Ldap.Tls == "starttls" {
tlsConfig := tls.Config{}
// FIXME missing support for CA chain
if err := conn.StartTLS(&tlsConfig); err != nil {
log.Fatalf("LDAP server %s, StartTLS failed: %v", configuration.Ldap.Host, err)
}
}
if configuration.Ldap.BindUser != "" {
err := conn.Bind(configuration.Ldap.BindUser, configuration.Ldap.BindPassword)
if err != nil {