Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow usage of a environment variable or secret for sensitive params #47

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion ldapauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
"github.com/gorilla/sessions"
)

const defaultCacheKey = "super-secret-key"

// nolint
var (
store *sessions.CookieStore
Expand All @@ -46,6 +48,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"`
Expand All @@ -54,6 +57,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"`
Expand All @@ -77,7 +81,8 @@ func CreateConfig() *Config {
CacheCookieName: "ldapAuth_session_token",
CacheCookiePath: "",
CacheCookieSecure: false,
CacheKey: "super-secret-key",
CacheKey: defaultCacheKey,
CacheKeyLabel: "LDAP_AUTH_CACHE_KEY",
StartTLS: false,
CertificateAuthority: "",
InsecureSkipVerify: false,
Expand All @@ -86,6 +91,7 @@ func CreateConfig() *Config {
BaseDN: "",
BindDN: "",
BindPassword: "",
BindPasswordLabel: "LDAP_AUTH_BIND_PASSWORD",
ForwardUsername: true,
ForwardUsernameHeader: "Username",
ForwardAuthorization: false,
Expand All @@ -112,6 +118,19 @@ func New(ctx context.Context, next http.Handler, config *Config, name string) (h

LoggerINFO.Printf("Starting %s Middleware...", name)

if config.BindDN != "" && config.BindPassword == "" {
config.BindPassword = getSecret(config.BindPasswordLabel)
}

// 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
}
}

LogConfigParams(config)

// Create new session with CacheKey and CacheTimeout.
Expand Down Expand Up @@ -544,3 +563,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 {
secret := os.Getenv(strings.ToUpper(label))

if secret != "" {
return secret
}

b, err := os.ReadFile(fmt.Sprintf("/run/secrets/%s", strings.ToLower(label)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if maybe we should allow a file path there, just because that would not be usable on Windows. Furthermore, Docker Swarm and Docker Compose allow mounting secrets into other locations than /run/secrets

Copy link
Owner

@wiltonsr wiltonsr Aug 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Support for multiple paths could be a problem. We could detect the OS system and define the full path based on default values or direct read the file if the label starts with / and exists. But I prefer to maintain the plugin as simple as possible.

if err != nil {
LoggerERROR.Printf("could not load secret %s: %s", label, err)
return ""
}
return strings.TrimSpace(string(b))
}
32 changes: 32 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`_
Expand Down Expand Up @@ -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`

Expand Down