Skip to content

Commit 7aa0c25

Browse files
authored
feat(vault): added userpass auth method (#798)
Signed-off-by: Philipp Reusch (pdrd) <philipp.reusch@stackit.cloud>
1 parent 6e8dca3 commit 7aa0c25

File tree

2 files changed

+74
-13
lines changed

2 files changed

+74
-13
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ Please see [pkg/providers](https://github.com/helmfile/vals/tree/master/pkg/prov
320320
- `ref+vault://PATH/TO/KVBACKEND[?address=VAULT_ADDR:PORT&token_file=PATH/TO/FILE&token_env=VAULT_TOKEN&namespace=VAULT_NAMESPACE]#/fieldkey`
321321
- `ref+vault://PATH/TO/KVBACKEND[?address=VAULT_ADDR:PORT&auth_method=approle&role_id=ce5e571a-f7d4-4c73-93dd-fd6922119839&secret_id=5c9194b9-585e-4539-a865-f45604bd6f56]#/fieldkey`
322322
- `ref+vault://PATH/TO/KVBACKEND[?address=VAULT_ADDR:PORT&auth_method=kubernetes&role_id=K8S-ROLE`
323+
- `ref+vault://PATH/TO/KVBACKEND[?address=VAULT_ADDR:PORT&auth_method=userpass&username=some-user&password_file=PATH/TO/FILE&password_env=VAULT_PASSWORD]#/fieldkey`
323324

324325
* `address` defaults to the value of the `VAULT_ADDR` envvar.
325326
* `namespace` defaults to the value of the `VAULT_NAMESPACE` envvar.
@@ -335,13 +336,16 @@ The `auth_method` or `VAULT_AUTH_METHOD` envar configures how `vals` authenticat
335336
* [approle](https://www.vaultproject.io/docs/auth/approle#via-the-api): it requires you pass on a `role_id` together with a `secret_id`.
336337
* [token](https://www.vaultproject.io/docs/auth/token): you just need creating and passing on a `VAULT_TOKEN`. If `VAULT_TOKEN` isn't set, token can be retrieved from `VAULT_TOKEN_FILE` env or `~/.vault-token` file.
337338
* [kubernetes](https://www.vaultproject.io/docs/auth/kubernetes): if you're running inside a Kubernetes cluster, you can use this option. It requires you [configure](https://www.vaultproject.io/docs/auth/kubernetes#configuration) a policy, a Kubernetes role, a service account and a JWT token. The login path can also be set using the environment variable `VAULT_KUBERNETES_MOUNT_POINT` (default is `/kubernetes`). You must also set `role_id` or `VAULT_ROLE_ID` envar to the Kubernetes role.
339+
* [userpass](https://developer.hashicorp.com/vault/docs/auth/userpass): you need to provide a username, e.g. via `VAULT_USERNAME`, and a password retrieved from the file `VAULT_PASSWORD_FILE` or from the env variable referred to in `VAULT_PASSWORD_ENV`. `VAULT_PASSWORD_ENV` takes precedence over `VAULT_PASSWORD_FILE`.
338340

339341
Examples:
340342

341343
- `ref+vault://mykv/foo?address=https://vault1.example.com:8200#/bar` reads the value for the field `bar` in the kv `foo` on Vault listening on `https://vault1.example.com` with the Vault token read from **the envvar `VAULT_TOKEN`, or the file `~/.vault_token` when the envvar is not set**
342344
- `ref+vault://mykv/foo?token_env=VAULT_TOKEN_VAULT1&namespace=ns1&address=https://vault1.example.com:8200#/bar` reads the value for the field `bar` from namespace `ns1` in the kv `foo` on Vault listening on `https://vault1.example.com` with the Vault token read from **the envvar `VAULT_TOKEN_VAULT1`**
343345
- `ref+vault://mykv/foo?token_file=~/.vault_token_vault1&address=https://vault1.example.com:8200#/bar` reads the value for the field `bar` in the kv `foo` on Vault listening on `https://vault1.example.com` with the Vault token read from **the file `~/.vault_token_vault1`**
344346
- `ref+vault://mykv/foo?role_id=my-kube-role#/bar` using the Kubernetes role to log in to Vault
347+
- `ref+vault://mykv/foo?auth_method=userpass&username=some-user&password_env=VAULT_PASSWORD#/bar` using `userpass` authentication with password read from env `VAULT_PASSWORD`
348+
- `ref+vault://mykv/foo?auth_method=userpass&username=some-user&password_file=PATH/TO/FILE#/bar` using `userpass` authentication with password read from file `VAULT_PASSWORD_FILE`
345349

346350
### AWS
347351

pkg/providers/vault/vault.go

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,19 @@ type provider struct {
2828
client *vault.Client
2929
log *log.Logger
3030

31-
Address string
32-
Namespace string
33-
Proto string
34-
Host string
35-
TokenEnv string
36-
TokenFile string
37-
AuthMethod string
38-
RoleId string
39-
SecretId string
40-
Version string
31+
Address string
32+
Namespace string
33+
Proto string
34+
Host string
35+
TokenEnv string
36+
TokenFile string
37+
AuthMethod string
38+
RoleId string
39+
SecretId string
40+
Username string
41+
PasswordEnv string
42+
PasswordFile string
43+
Version string
4144
}
4245

4346
func New(l *log.Logger, cfg api.StaticConfig) *provider {
@@ -66,6 +69,8 @@ func New(l *log.Logger, cfg api.StaticConfig) *provider {
6669
p.AuthMethod = "approle"
6770
} else if os.Getenv("VAULT_AUTH_METHOD") == "kubernetes" {
6871
p.AuthMethod = "kubernetes"
72+
} else if os.Getenv("VAULT_AUTH_METHOD") == "userpass" {
73+
p.AuthMethod = "userpass"
6974
} else {
7075
p.AuthMethod = "token"
7176
}
@@ -86,6 +91,18 @@ func New(l *log.Logger, cfg api.StaticConfig) *provider {
8691
p.SecretId = ""
8792
}
8893
}
94+
p.Username = cfg.String("username")
95+
if p.Username == "" {
96+
p.Username = os.Getenv("VAULT_USERNAME")
97+
}
98+
p.PasswordEnv = cfg.String("password_env")
99+
if p.PasswordEnv == "" {
100+
p.PasswordEnv = os.Getenv("VAULT_PASSWORD_ENV")
101+
}
102+
p.PasswordFile = cfg.String("password_file")
103+
if p.PasswordFile == "" {
104+
p.PasswordFile = os.Getenv("VAULT_PASSWORD_FILE")
105+
}
89106
p.Version = cfg.String("version")
90107

91108
return p
@@ -195,7 +212,7 @@ func (p *provider) ensureClient() (*vault.Client, error) {
195212
}
196213

197214
if p.TokenFile != "" {
198-
token, err := p.readTokenFile(p.TokenFile)
215+
token, err := p.readFile(p.TokenFile)
199216
if err != nil {
200217
return nil, err
201218
}
@@ -214,7 +231,7 @@ func (p *provider) ensureClient() (*vault.Client, error) {
214231
}
215232
}
216233
if tokenFile != "" {
217-
token, _ := p.readTokenFile(tokenFile)
234+
token, _ := p.readFile(tokenFile)
218235
if token != "" {
219236
cli.SetToken(token)
220237
}
@@ -276,14 +293,54 @@ func (p *provider) ensureClient() (*vault.Client, error) {
276293
return nil, fmt.Errorf("no auth info returned")
277294
}
278295

296+
cli.SetToken(resp.Auth.ClientToken)
297+
case "userpass":
298+
var password = ""
299+
300+
if p.PasswordEnv != "" {
301+
password = os.Getenv(p.PasswordEnv)
302+
if password == "" {
303+
return nil, fmt.Errorf("password_env configured to read vault password from envvar %q, but it isn't set", p.PasswordEnv)
304+
}
305+
} else if p.PasswordFile != "" {
306+
password, err = p.readFile(p.PasswordFile)
307+
if err != nil {
308+
return nil, err
309+
}
310+
}
311+
312+
if password == "" {
313+
return nil, fmt.Errorf("password missing for userpass authentication")
314+
}
315+
316+
data := map[string]interface{}{
317+
"password": password,
318+
}
319+
320+
mount_point, ok := os.LookupEnv("VAULT_LOGIN_MOUNT_POINT")
321+
if !ok {
322+
mount_point = "userpass"
323+
}
324+
325+
auth_path := filepath.Join("auth", mount_point, "login", p.Username)
326+
327+
resp, err := cli.Logical().Write(auth_path, data)
328+
if err != nil {
329+
return nil, err
330+
}
331+
332+
if resp.Auth == nil {
333+
return nil, fmt.Errorf("no auth info returned")
334+
}
335+
279336
cli.SetToken(resp.Auth.ClientToken)
280337
}
281338
p.client = cli
282339
}
283340
return p.client, nil
284341
}
285342

286-
func (p *provider) readTokenFile(path string) (string, error) {
343+
func (p *provider) readFile(path string) (string, error) {
287344
buff, err := os.ReadFile(path)
288345
if err != nil {
289346
return "", err

0 commit comments

Comments
 (0)