Skip to content

Commit

Permalink
Adds support to Kubernetes authn for Vault (#64)
Browse files Browse the repository at this point in the history
Enables Kubernetes authentication for Vault to allow running `vals` from inside a container.
  • Loading branch information
digiserg authored Dec 19, 2021
1 parent b97f790 commit f333e05
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 7 deletions.
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,18 +182,28 @@ Please see [pkg/providers](https://github.com/variantdev/vals/tree/master/pkg/pr

- `ref+vault://PATH/TO/KVBACKEND[?address=VAULT_ADDR:PORT&token_file=PATH/TO/FILE&token_env=VAULT_TOKEN]#/fieldkey`
- `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`
- `ref+vault://PATH/TO/KVBACKEND[?address=VAULT_ADDR:PORT&auth_method=kubernetes&role_id=K8S-ROLE`

`address` defaults to the value of the `VAULT_ADDR` envvar.
`auth_method` default to `token` and can also be set to the value of the `VAULT_AUTH_METHOD` envar.
`role_id` defaults to the value of the `VAULT_ROLE_ID` envvar.
`secret_id` defaults to the value of the `VAULT_SECRET_ID` envvar.
`version` is the specific version of the secret to be obtained. Used when you want to get a previous content of the secret.
* `address` defaults to the value of the `VAULT_ADDR` envvar.
* `auth_method` default to `token` and can also be set to the value of the `VAULT_AUTH_METHOD` envar.
* `role_id` defaults to the value of the `VAULT_ROLE_ID` envvar.
* `secret_id` defaults to the value of the `VAULT_SECRET_ID` envvar.
* `version` is the specific version of the secret to be obtained. Used when you want to get a previous content of the secret.

### Authentication

The `auth_method` or `VAULT_AUTH_METHOD` envar configures how `vals` authenticates to HashiCorp Vault. Currently only these options are supported:

* [approle](https://www.vaultproject.io/docs/auth/approle#via-the-api): it requires you pass on a `role_id` together with a `secret_id`.
* [token](https://www.vaultproject.io/docs/auth/token): you just need creating and passing on a `VAULT_TOKEN`
* [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.

Examples:

- `ref+vault://mykv/foo#/bar?address=https://vault1.example.com:8200` 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**
- `ref+vault://mykv/foo#/bar?token_env=VAULT_TOKEN_VAULT1&address=https://vault1.example.com:8200` 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_VAULT1`**
- `ref+vault://mykv/foo#/bar?token_file=~/.vault_token_vault1&address=https://vault1.example.com:8200` 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`**
- `ref+vault://mykv/foo#/bar?role_id=my-kube-role` using the Kubernetes role to log in to Vault

### AWS

Expand Down
39 changes: 37 additions & 2 deletions pkg/providers/vault/vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import (
)

const (
FormatYAML = "yaml"
FormatRaw = "raw"
FormatYAML = "yaml"
FormatRaw = "raw"
kubernetesJwtTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"
)

// Test procedure:
Expand Down Expand Up @@ -61,6 +62,8 @@ func New(cfg api.StaticConfig) *provider {
if p.AuthMethod == "" {
if os.Getenv("VAULT_AUTH_METHOD") == "approle" {
p.AuthMethod = "approle"
} else if os.Getenv("VAULT_AUTH_METHOD") == "kubernetes" {
p.AuthMethod = "kubernetes"
} else {
p.AuthMethod = "token"
}
Expand Down Expand Up @@ -225,6 +228,38 @@ func (p *provider) ensureClient() (*vault.Client, error) {
return nil, fmt.Errorf("no auth info returned")
}

cli.SetToken(resp.Auth.ClientToken)
} else if p.AuthMethod == "kubernetes" {
fd, err := os.Open(kubernetesJwtTokenPath)
defer fd.Close()
if err != nil {
return nil, fmt.Errorf("unable to read file containing service account token: %w", err)
}
jwt, err := ioutil.ReadAll(fd)
if err != nil {
return nil, fmt.Errorf("unable to read file containing service account token: %w", err)
}

data := map[string]interface{}{
"jwt": string(jwt),
"role": p.RoleId,
}
mount_point, ok := os.LookupEnv("VAULT_KUBERNETES_MOUNT_POINT")
if !ok {
mount_point = "/kubernetes"
}

auth_path := filepath.Join("auth", mount_point, "login")

resp, err := cli.Logical().Write(auth_path, data)
if err != nil {
return nil, err
}

if resp.Auth == nil {
return nil, fmt.Errorf("no auth info returned")
}

cli.SetToken(resp.Auth.ClientToken)
}
p.client = cli
Expand Down

0 comments on commit f333e05

Please sign in to comment.