mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-21 23:20:24 +00:00
data providers: allow to disable SNI for TLS connections
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
8debde842c
commit
3ebdfa9b2d
8 changed files with 63 additions and 39 deletions
|
@ -211,6 +211,7 @@ The configuration file contains the following sections:
|
|||
- `password`, string. Database password. Leave empty for drivers `sqlite`, `bolt` and `memory`
|
||||
- `sslmode`, integer. Used for drivers `mysql` and `postgresql`. 0 disable TLS connections, 1 require TLS, 2 set TLS mode to `verify-ca` for driver `postgresql` and `skip-verify` for driver `mysql`, 3 set TLS mode to `verify-full` for driver `postgresql` and `preferred` for driver `mysql`
|
||||
- `root_cert`, string. Path to the root certificate authority used to verify that the server certificate was signed by a trusted CA
|
||||
- `disable_sni`, boolean. Allows to opt out Server Name Indication (SNI) for TLS connections. Default: `false`
|
||||
- `client_cert`, string. Path to the client certificate for two-way TLS authentication
|
||||
- `client_key`,string. Path to the client key for two-way TLS authentication
|
||||
- `connection_string`, string. Provide a custom database connection string. If not empty, this connection string will be used instead of building one using the previous parameters. Leave empty for drivers `bolt` and `memory`
|
||||
|
|
6
go.mod
6
go.mod
|
@ -37,7 +37,7 @@ require (
|
|||
github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126
|
||||
github.com/klauspost/compress v1.15.9
|
||||
github.com/lestrrat-go/jwx v1.2.25
|
||||
github.com/lib/pq v1.10.6
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/lithammer/shortuuid/v3 v3.0.7
|
||||
github.com/mattn/go-sqlite3 v1.14.15
|
||||
github.com/mhale/smtpd v0.8.0
|
||||
|
@ -68,9 +68,9 @@ require (
|
|||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
|
||||
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
|
||||
golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77
|
||||
golang.org/x/sys v0.0.0-20220907062415-87db552b00fd
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
|
||||
google.golang.org/api v0.94.0
|
||||
google.golang.org/api v0.95.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
)
|
||||
|
||||
|
|
11
go.sum
11
go.sum
|
@ -589,8 +589,9 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
|
||||
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
||||
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJVuvyJQQ8=
|
||||
github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
|
@ -977,8 +978,8 @@ golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77 h1:C1tElbkWrsSkn3IRl1GCW/gETw1TywWIPgwZtXTZbYg=
|
||||
golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220907062415-87db552b00fd h1:AZeIEzg+8RCELJYq8w+ODLVxFgLMMigSwO/ffKPEd9U=
|
||||
golang.org/x/sys v0.0.0-20220907062415-87db552b00fd/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@ -1119,8 +1120,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
|
|||
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||
google.golang.org/api v0.94.0 h1:KtKM9ru3nzQioV1HLlUf1cR7vMYJIpgls5VhAYQXIwA=
|
||||
google.golang.org/api v0.94.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
|
||||
google.golang.org/api v0.95.0 h1:d1c24AAS01DYqXreBeuVV7ewY/U8Mnhh47pwtsgVtYg=
|
||||
google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
|
|
@ -318,6 +318,7 @@ func Init() {
|
|||
ConnectionString: "",
|
||||
SQLTablesPrefix: "",
|
||||
SSLMode: 0,
|
||||
DisableSNI: false,
|
||||
RootCert: "",
|
||||
ClientCert: "",
|
||||
ClientKey: "",
|
||||
|
@ -1927,6 +1928,7 @@ func setViperDefaults() {
|
|||
viper.SetDefault("data_provider.username", globalConf.ProviderConf.Username)
|
||||
viper.SetDefault("data_provider.password", globalConf.ProviderConf.Password)
|
||||
viper.SetDefault("data_provider.sslmode", globalConf.ProviderConf.SSLMode)
|
||||
viper.SetDefault("data_provider.disable_sni", globalConf.ProviderConf.DisableSNI)
|
||||
viper.SetDefault("data_provider.root_cert", globalConf.ProviderConf.RootCert)
|
||||
viper.SetDefault("data_provider.client_cert", globalConf.ProviderConf.ClientCert)
|
||||
viper.SetDefault("data_provider.client_key", globalConf.ProviderConf.ClientKey)
|
||||
|
|
|
@ -330,6 +330,8 @@ type Config struct {
|
|||
// 2 set ssl mode to verify-ca for driver postgresql and skip-verify for driver mysql.
|
||||
// 3 set ssl mode to verify-full for driver postgresql and preferred for driver mysql.
|
||||
SSLMode int `json:"sslmode" mapstructure:"sslmode"`
|
||||
// Used for drivers mysql and postgresql. Set to true to disable SNI
|
||||
DisableSNI bool `json:"disable_sni" mapstructure:"disable_sni"`
|
||||
// Path to the root certificate authority used to verify that the server certificate was signed by a trusted CA
|
||||
RootCert string `json:"root_cert" mapstructure:"root_cert"`
|
||||
// Path to the client certificate for two-way TLS authentication
|
||||
|
@ -493,6 +495,9 @@ func (c *Config) IsDefenderSupported() bool {
|
|||
}
|
||||
|
||||
func (c *Config) requireCustomTLSForMySQL() bool {
|
||||
if config.DisableSNI {
|
||||
return config.SSLMode != 0
|
||||
}
|
||||
if config.RootCert != "" && util.IsFileInputValid(config.RootCert) {
|
||||
return config.SSLMode != 0
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -219,37 +220,8 @@ func getMySQLConnectionString(redactedPwd bool) (string, error) {
|
|||
}
|
||||
sslMode := getSSLMode()
|
||||
if sslMode == "custom" && !redactedPwd {
|
||||
tlsConfig := &tls.Config{}
|
||||
if config.RootCert != "" {
|
||||
rootCAs, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
rootCAs = x509.NewCertPool()
|
||||
}
|
||||
rootCrt, err := os.ReadFile(config.RootCert)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to load root certificate %#v: %v", config.RootCert, err)
|
||||
}
|
||||
if !rootCAs.AppendCertsFromPEM(rootCrt) {
|
||||
return "", fmt.Errorf("unable to parse root certificate %#v", config.RootCert)
|
||||
}
|
||||
tlsConfig.RootCAs = rootCAs
|
||||
}
|
||||
if config.ClientCert != "" && config.ClientKey != "" {
|
||||
clientCert := make([]tls.Certificate, 0, 1)
|
||||
tlsCert, err := tls.LoadX509KeyPair(config.ClientCert, config.ClientKey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to load key pair %#v, %#v: %v", config.ClientCert, config.ClientKey, err)
|
||||
}
|
||||
clientCert = append(clientCert, tlsCert)
|
||||
tlsConfig.Certificates = clientCert
|
||||
}
|
||||
if config.SSLMode == 2 {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
providerLog(logger.LevelInfo, "registering custom TLS config, root cert %#v, client cert %#v, client key %#v",
|
||||
config.RootCert, config.ClientCert, config.ClientKey)
|
||||
if err := mysql.RegisterTLSConfig("custom", tlsConfig); err != nil {
|
||||
return "", fmt.Errorf("unable to register tls config: %v", err)
|
||||
if err := registerMySQLCustomTLSConfig(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
connectionString = fmt.Sprintf("%v:%v@tcp([%v]:%v)/%v?charset=utf8mb4&interpolateParams=true&timeout=10s&parseTime=true&tls=%v&writeTimeout=60s&readTimeout=60s",
|
||||
|
@ -260,6 +232,45 @@ func getMySQLConnectionString(redactedPwd bool) (string, error) {
|
|||
return connectionString, nil
|
||||
}
|
||||
|
||||
func registerMySQLCustomTLSConfig() error {
|
||||
tlsConfig := &tls.Config{}
|
||||
if config.RootCert != "" {
|
||||
rootCAs, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
rootCAs = x509.NewCertPool()
|
||||
}
|
||||
rootCrt, err := os.ReadFile(config.RootCert)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load root certificate %#v: %v", config.RootCert, err)
|
||||
}
|
||||
if !rootCAs.AppendCertsFromPEM(rootCrt) {
|
||||
return fmt.Errorf("unable to parse root certificate %#v", config.RootCert)
|
||||
}
|
||||
tlsConfig.RootCAs = rootCAs
|
||||
}
|
||||
if config.ClientCert != "" && config.ClientKey != "" {
|
||||
clientCert := make([]tls.Certificate, 0, 1)
|
||||
tlsCert, err := tls.LoadX509KeyPair(config.ClientCert, config.ClientKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load key pair %#v, %#v: %v", config.ClientCert, config.ClientKey, err)
|
||||
}
|
||||
clientCert = append(clientCert, tlsCert)
|
||||
tlsConfig.Certificates = clientCert
|
||||
}
|
||||
if config.SSLMode == 2 || config.SSLMode == 3 {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
if !filepath.IsAbs(config.Host) && !config.DisableSNI {
|
||||
tlsConfig.ServerName = config.Host
|
||||
}
|
||||
providerLog(logger.LevelInfo, "registering custom TLS config, root cert %#v, client cert %#v, client key %#v, disable SNI? %v",
|
||||
config.RootCert, config.ClientCert, config.ClientKey, config.DisableSNI)
|
||||
if err := mysql.RegisterTLSConfig("custom", tlsConfig); err != nil {
|
||||
return fmt.Errorf("unable to register tls config: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *MySQLProvider) checkAvailability() error {
|
||||
return sqlCommonCheckAvailability(p.dbHandle)
|
||||
}
|
||||
|
|
|
@ -231,6 +231,9 @@ func getPGSQLConnectionString(redactedPwd bool) string {
|
|||
if config.ClientCert != "" && config.ClientKey != "" {
|
||||
connectionString += fmt.Sprintf(" sslcert='%v' sslkey='%v'", config.ClientCert, config.ClientKey)
|
||||
}
|
||||
if config.DisableSNI {
|
||||
connectionString += " sslsni=0"
|
||||
}
|
||||
} else {
|
||||
connectionString = config.ConnectionString
|
||||
}
|
||||
|
|
|
@ -190,6 +190,7 @@
|
|||
"username": "",
|
||||
"password": "",
|
||||
"sslmode": 0,
|
||||
"disable_sni": false,
|
||||
"root_cert": "",
|
||||
"client_cert": "",
|
||||
"client_key": "",
|
||||
|
|
Loading…
Reference in a new issue