From 9ebad9bec2c3dbcbd2c0c3acac90a49e53fa1eb9 Mon Sep 17 00:00:00 2001 From: James Elliott Date: Fri, 6 Aug 2021 15:35:14 +1000 Subject: [PATCH] fix(storage): set sane default connection timeout (#2256) This sets a sane default connection timeout for SQL connections. --- config.template.yml | 2 ++ docs/configuration/storage/mariadb.md | 12 +++++++++ docs/configuration/storage/mysql.md | 13 ++++++++++ docs/configuration/storage/postgres.md | 12 +++++++++ internal/configuration/config.template.yml | 2 ++ internal/configuration/schema/storage.go | 27 +++++++++++++++++---- internal/configuration/validator/const.go | 2 ++ internal/configuration/validator/storage.go | 14 ++++++++--- internal/storage/mysql_provider.go | 4 +++ internal/storage/postgres_provider.go | 2 ++ 10 files changed, 82 insertions(+), 8 deletions(-) diff --git a/config.template.yml b/config.template.yml index ef53de1cf..3b8529c8a 100644 --- a/config.template.yml +++ b/config.template.yml @@ -498,6 +498,7 @@ storage: username: authelia ## Password can also be set using a secret: https://www.authelia.com/docs/configuration/secrets.html password: mypassword + timeout: 5s ## ## PostgreSQL (Storage Provider) @@ -509,6 +510,7 @@ storage: # username: authelia # ## Password can also be set using a secret: https://www.authelia.com/docs/configuration/secrets.html # password: mypassword + # timeout: 5s # sslmode: disable ## diff --git a/docs/configuration/storage/mariadb.md b/docs/configuration/storage/mariadb.md index 047bcba25..43a36f191 100644 --- a/docs/configuration/storage/mariadb.md +++ b/docs/configuration/storage/mariadb.md @@ -84,3 +84,15 @@ required: yes The password paired with the username used to connect to the database. Can also be defined using a [secret](../secrets.md) which is also the recommended way when running as a container. + +### timeout +
+type: duration +{: .label .label-config .label-purple } +default: 5s +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +
+ +The SQL connection timeout. diff --git a/docs/configuration/storage/mysql.md b/docs/configuration/storage/mysql.md index 9a0e7528a..acb98f0b6 100644 --- a/docs/configuration/storage/mysql.md +++ b/docs/configuration/storage/mysql.md @@ -20,6 +20,7 @@ storage: database: authelia username: authelia password: mypassword + timeout: 5s ``` ## Options @@ -84,3 +85,15 @@ required: yes The password paired with the username used to connect to the database. Can also be defined using a [secret](../secrets.md) which is also the recommended way when running as a container. + +### timeout +
+type: duration +{: .label .label-config .label-purple } +default: 5s +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +
+ +The SQL connection timeout. diff --git a/docs/configuration/storage/postgres.md b/docs/configuration/storage/postgres.md index abb97aa90..525aeeb91 100644 --- a/docs/configuration/storage/postgres.md +++ b/docs/configuration/storage/postgres.md @@ -80,6 +80,18 @@ required: yes The password paired with the username used to connect to the database. Can also be defined using a [secret](../secrets.md) which is also the recommended way when running as a container. +### timeout +
+type: duration +{: .label .label-config .label-purple } +default: 5s +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +
+ +The SQL connection timeout. + ### sslmode
type: string diff --git a/internal/configuration/config.template.yml b/internal/configuration/config.template.yml index ef53de1cf..3b8529c8a 100644 --- a/internal/configuration/config.template.yml +++ b/internal/configuration/config.template.yml @@ -498,6 +498,7 @@ storage: username: authelia ## Password can also be set using a secret: https://www.authelia.com/docs/configuration/secrets.html password: mypassword + timeout: 5s ## ## PostgreSQL (Storage Provider) @@ -509,6 +510,7 @@ storage: # username: authelia # ## Password can also be set using a secret: https://www.authelia.com/docs/configuration/secrets.html # password: mypassword + # timeout: 5s # sslmode: disable ## diff --git a/internal/configuration/schema/storage.go b/internal/configuration/schema/storage.go index 168b61bc3..ecb2a65ca 100644 --- a/internal/configuration/schema/storage.go +++ b/internal/configuration/schema/storage.go @@ -1,5 +1,7 @@ package schema +import "time" + // LocalStorageConfiguration represents the configuration when using local storage. type LocalStorageConfiguration struct { Path string `koanf:"path"` @@ -7,11 +9,12 @@ type LocalStorageConfiguration struct { // SQLStorageConfiguration represents the configuration of the SQL database. type SQLStorageConfiguration struct { - Host string `koanf:"host"` - Port int `koanf:"port"` - Database string `koanf:"database"` - Username string `koanf:"username"` - Password string `koanf:"password"` + Host string `koanf:"host"` + Port int `koanf:"port"` + Database string `koanf:"database"` + Username string `koanf:"username"` + Password string `koanf:"password"` + Timeout time.Duration `koanf:"timeout"` } // MySQLStorageConfiguration represents the configuration of a MySQL database. @@ -31,3 +34,17 @@ type StorageConfiguration struct { MySQL *MySQLStorageConfiguration `koanf:"mysql"` PostgreSQL *PostgreSQLStorageConfiguration `koanf:"postgres"` } + +// DefaultPostgreSQLStorageConfiguration represents the default PostgreSQL configuration. +var DefaultPostgreSQLStorageConfiguration = PostgreSQLStorageConfiguration{ + SQLStorageConfiguration: SQLStorageConfiguration{ + Timeout: 5 * time.Second, + }, +} + +// DefaultMySQLStorageConfiguration represents the default MySQL configuration. +var DefaultMySQLStorageConfiguration = MySQLStorageConfiguration{ + SQLStorageConfiguration: SQLStorageConfiguration{ + Timeout: 5 * time.Second, + }, +} diff --git a/internal/configuration/validator/const.go b/internal/configuration/validator/const.go index 699697bf5..55006f4bc 100644 --- a/internal/configuration/validator/const.go +++ b/internal/configuration/validator/const.go @@ -204,6 +204,7 @@ var ValidKeys = []string{ "storage.mysql.database", "storage.mysql.username", "storage.mysql.password", + "storage.mysql.timeout", // PostgreSQL Storage Keys. "storage.postgres.host", @@ -211,6 +212,7 @@ var ValidKeys = []string{ "storage.postgres.database", "storage.postgres.username", "storage.postgres.password", + "storage.postgres.timeout", "storage.postgres.sslmode", // FileSystem Notifier Keys. diff --git a/internal/configuration/validator/storage.go b/internal/configuration/validator/storage.go index d1596757e..e130132ac 100644 --- a/internal/configuration/validator/storage.go +++ b/internal/configuration/validator/storage.go @@ -14,7 +14,7 @@ func ValidateStorage(configuration schema.StorageConfiguration, validator *schem switch { case configuration.MySQL != nil: - validateSQLConfiguration(&configuration.MySQL.SQLStorageConfiguration, validator) + validateMySQLConfiguration(&configuration.MySQL.SQLStorageConfiguration, validator) case configuration.PostgreSQL != nil: validatePostgreSQLConfiguration(configuration.PostgreSQL, validator) case configuration.Local != nil: @@ -22,7 +22,11 @@ func ValidateStorage(configuration schema.StorageConfiguration, validator *schem } } -func validateSQLConfiguration(configuration *schema.SQLStorageConfiguration, validator *schema.StructValidator) { +func validateMySQLConfiguration(configuration *schema.SQLStorageConfiguration, validator *schema.StructValidator) { + if configuration.Timeout == 0 { + configuration.Timeout = schema.DefaultMySQLStorageConfiguration.Timeout + } + if configuration.Password == "" || configuration.Username == "" { validator.Push(errors.New("the SQL username and password must be provided")) } @@ -33,7 +37,11 @@ func validateSQLConfiguration(configuration *schema.SQLStorageConfiguration, val } func validatePostgreSQLConfiguration(configuration *schema.PostgreSQLStorageConfiguration, validator *schema.StructValidator) { - validateSQLConfiguration(&configuration.SQLStorageConfiguration, validator) + validateMySQLConfiguration(&configuration.SQLStorageConfiguration, validator) + + if configuration.Timeout == 0 { + configuration.Timeout = schema.DefaultPostgreSQLStorageConfiguration.Timeout + } if configuration.SSLMode == "" { configuration.SSLMode = testModeDisabled diff --git a/internal/storage/mysql_provider.go b/internal/storage/mysql_provider.go index 83aaffd79..a34f74333 100644 --- a/internal/storage/mysql_provider.go +++ b/internal/storage/mysql_provider.go @@ -3,6 +3,7 @@ package storage import ( "database/sql" "fmt" + "time" _ "github.com/go-sql-driver/mysql" // Load the MySQL Driver used in the connection string. @@ -68,6 +69,9 @@ func NewMySQLProvider(configuration schema.MySQLStorageConfiguration) *MySQLProv connectionString += fmt.Sprintf("/%s", configuration.Database) } + connectionString += "?" + connectionString += fmt.Sprintf("timeout=%ds", int32(configuration.Timeout/time.Second)) + db, err := sql.Open("mysql", connectionString) if err != nil { provider.log.Fatalf("Unable to connect to SQL database: %v", err) diff --git a/internal/storage/postgres_provider.go b/internal/storage/postgres_provider.go index ce85678ed..ac59dcd3c 100644 --- a/internal/storage/postgres_provider.go +++ b/internal/storage/postgres_provider.go @@ -4,6 +4,7 @@ import ( "database/sql" "fmt" "strings" + "time" _ "github.com/jackc/pgx/v4/stdlib" // Load the PostgreSQL Driver used in the connection string. @@ -73,6 +74,7 @@ func NewPostgreSQLProvider(configuration schema.PostgreSQLStorageConfiguration) args = append(args, fmt.Sprintf("sslmode=%s", configuration.SSLMode)) } + args = append(args, fmt.Sprintf("connect_timeout=%d", int32(configuration.Timeout/time.Second))) connectionString := strings.Join(args, " ") db, err := sql.Open("pgx", connectionString)