From 4c4b8693f11dcca2b19d110c6461243d9c31ccf7 Mon Sep 17 00:00:00 2001 From: Thibault Piron Date: Sat, 5 Aug 2023 15:58:58 +0200 Subject: [PATCH 1/3] feat: allow usage of a environment variable or secret for sensitive params Signed-off-by: Thibault Piron --- ldapauth.go | 36 ++++++++++++++++++++++++++++++++++++ readme.md | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/ldapauth.go b/ldapauth.go index 4f05ebf..b9734cc 100644 --- a/ldapauth.go +++ b/ldapauth.go @@ -46,6 +46,7 @@ type Config struct { CacheCookiePath string `json:"cacheCookiePath,omitempty" yaml:"cacheCookiePath,omitempty"` CacheCookieSecure bool `json:"cacheCookieSecure,omitempty" yaml:"cacheCookieSecure,omitempty"` CacheKey string `json:"cacheKey,omitempty" yaml:"cacheKey,omitempty"` + CacheKeyLabel string `json:"cacheKeyLabel,omitempty" yaml:"cacheKeyLabel,omitempty"` StartTLS bool `json:"startTls,omitempty" yaml:"startTls,omitempty"` CertificateAuthority string `json:"certificateAuthority,omitempty" yaml:"certificateAuthority,omitempty"` InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty"` @@ -54,6 +55,7 @@ type Config struct { BaseDN string `json:"baseDn,omitempty" yaml:"baseDn,omitempty"` BindDN string `json:"bindDn,omitempty" yaml:"bindDn,omitempty"` BindPassword string `json:"bindPassword,omitempty" yaml:"bindPassword,omitempty"` + BindPasswordLabel string `json:"bindPasswordLabel,omitempty" yaml:"bindPasswordLabel,omitempty"` ForwardUsername bool `json:"forwardUsername,omitempty" yaml:"forwardUsername,omitempty"` ForwardUsernameHeader string `json:"forwardUsernameHeader,omitempty" yaml:"forwardUsernameHeader,omitempty"` ForwardAuthorization bool `json:"forwardAuthorization,omitempty" yaml:"forwardAuthorization,omitempty"` @@ -78,6 +80,7 @@ func CreateConfig() *Config { CacheCookiePath: "", CacheCookieSecure: false, CacheKey: "super-secret-key", + CacheKeyLabel: "LDAP_AUTH_CACHE_KEY", StartTLS: false, CertificateAuthority: "", InsecureSkipVerify: false, @@ -86,6 +89,7 @@ func CreateConfig() *Config { BaseDN: "", BindDN: "", BindPassword: "", + BindPasswordLabel: "LDAP_AUTH_BIND_PASSWORD", ForwardUsername: true, ForwardUsernameHeader: "Username", ForwardAuthorization: false, @@ -112,6 +116,22 @@ func New(ctx context.Context, next http.Handler, config *Config, name string) (h LoggerINFO.Printf("Starting %s Middleware...", name) + if config.BindDN != "" && config.BindPassword == "" { + bindPasswordLabel := "LDAP_AUTH_BIND_PASSWORD" + if config.BindPasswordLabel != "" { + bindPasswordLabel = config.BindPasswordLabel + } + config.BindPassword = getSecret(bindPasswordLabel) + } + + if config.CacheKey != "" { + cacheKeyLabel := "LDAP_AUTH_CACHE_KEY" + if config.CacheKeyLabel != "" { + cacheKeyLabel = config.CacheKeyLabel + } + config.CacheKey = getSecret(cacheKeyLabel) + } + LogConfigParams(config) // Create new session with CacheKey and CacheTimeout. @@ -544,3 +564,19 @@ func LogConfigParams(config *Config) { LoggerDEBUG.Printf(fmt.Sprint(typeOfS.Field(i).Name, " => '", v.Field(i).Interface(), "'")) } } + +// retrieve a secret value from environment variable or secret on the FS +func getSecret(label string) string { + bindPassword := os.Getenv(strings.ToUpper(label)) + + if bindPassword != "" { + return bindPassword + } + + b, err := os.ReadFile(fmt.Sprintf("/run/secrets/%s", strings.ToLower(label))) + if err != nil { + LoggerERROR.Printf("could not load secret %s: %s", label, err) + return "" + } + return strings.TrimSpace(string(b)) +} diff --git a/readme.md b/readme.md index a886831..0aa2e66 100644 --- a/readme.md +++ b/readme.md @@ -161,6 +161,23 @@ Needs `traefik` >= [`v2.8.5`](https://github.com/traefik/traefik/releases/tag/v2 _Optional, Default: `super-secret-key`_ The key used to encrypt session cookie information. You `must` use a strong value here. +You can also use a secret or a environment variable, see `cacheKeyLabel`. + + +#### `cacheKeyLabel` + +_Optional, Default: `"LDAP_AUTH_CACHE_KEY"`_ + +Only used when `cacheKey` is not set. +This allow the user to choose the name or the environment variable or the file name. +To be consistent with other traefik plugins, the environment variable should be upper case, and file name lower case. + +Example: +cacheKeyLabel=my_cache_key_label +The environment variable `MY_CACHE_KEY_LABEL` or a file containing the password should be mounted to `/run/secrets/my_cache_key_label`. +Typically, with docker you can use a secret named `my_cache_key_label`. + +The environment variable will be used if both options are set. ##### `startTLS` _Optional, Default: `false`_ @@ -239,6 +256,21 @@ The domain name to bind to in order to authenticate to the LDAP server when runn _Optional, Default: `""`_ The password corresponding to the `bindDN` specified when running in [`Search Mode`](#search-mode), is used in order to authenticate to the LDAP server. +You can also use a secret or a environment variable, see `bindPasswordLabel`. + +##### `bindPasswordLabel` +_Optional, Default: `"LDAP_AUTH_BIND_PASSWORD"`_ + +Only used when `bindDN` is not empty, and `bindPassword` is not set. +This allow the user to choose the name or the environment variable or the file name. +To be consistent with other traefik plugins, the environment variable should be upper case, and file name lower case. + +Example: +bindPasswordLabel=my_bind_password_label +The environment variable `MY_BIND_PASSWORD_LABEL` or a file containing the password should be mounted to `/run/secrets/my_bind_password_label`. +Typically, with docker you can use a secret named `my_bind_password_label`. + +The environment variable will be used if both options are set. ##### `forwardUsername` From 74d22936e082fc0a0af50cfe87ef9a1e42caaee5 Mon Sep 17 00:00:00 2001 From: Thibault Piron Date: Wed, 23 Aug 2023 11:45:55 +0200 Subject: [PATCH 2/3] refactor: use proper variable name in getSecret --- ldapauth.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ldapauth.go b/ldapauth.go index b9734cc..5692dac 100644 --- a/ldapauth.go +++ b/ldapauth.go @@ -567,10 +567,10 @@ func LogConfigParams(config *Config) { // retrieve a secret value from environment variable or secret on the FS func getSecret(label string) string { - bindPassword := os.Getenv(strings.ToUpper(label)) + secret := os.Getenv(strings.ToUpper(label)) - if bindPassword != "" { - return bindPassword + if secret != "" { + return secret } b, err := os.ReadFile(fmt.Sprintf("/run/secrets/%s", strings.ToLower(label))) From a28a99da86e290054c204b444a9ca5b67b29e517 Mon Sep 17 00:00:00 2001 From: Thibault Piron Date: Wed, 23 Aug 2023 12:39:22 +0200 Subject: [PATCH 3/3] fix: conditions to retrieve bindPassword adn cacheKey from secrets --- ldapauth.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/ldapauth.go b/ldapauth.go index 5692dac..8dc380d 100644 --- a/ldapauth.go +++ b/ldapauth.go @@ -24,6 +24,8 @@ import ( "github.com/gorilla/sessions" ) +const defaultCacheKey = "super-secret-key" + // nolint var ( store *sessions.CookieStore @@ -79,7 +81,7 @@ func CreateConfig() *Config { CacheCookieName: "ldapAuth_session_token", CacheCookiePath: "", CacheCookieSecure: false, - CacheKey: "super-secret-key", + CacheKey: defaultCacheKey, CacheKeyLabel: "LDAP_AUTH_CACHE_KEY", StartTLS: false, CertificateAuthority: "", @@ -117,19 +119,16 @@ func New(ctx context.Context, next http.Handler, config *Config, name string) (h LoggerINFO.Printf("Starting %s Middleware...", name) if config.BindDN != "" && config.BindPassword == "" { - bindPasswordLabel := "LDAP_AUTH_BIND_PASSWORD" - if config.BindPasswordLabel != "" { - bindPasswordLabel = config.BindPasswordLabel - } - config.BindPassword = getSecret(bindPasswordLabel) + config.BindPassword = getSecret(config.BindPasswordLabel) } - if config.CacheKey != "" { - cacheKeyLabel := "LDAP_AUTH_CACHE_KEY" - if config.CacheKeyLabel != "" { - cacheKeyLabel = config.CacheKeyLabel + // if CacheKey is the default value we try to set it from secret + if config.CacheKey == defaultCacheKey { + cacheKey := getSecret(config.CacheKeyLabel) + // we could not retrieve the secret, so we keep the default value + if cacheKey != "" { + config.CacheKey = cacheKey } - config.CacheKey = getSecret(cacheKeyLabel) } LogConfigParams(config)