Skip to content

Commit

Permalink
Merge pull request #58 from patoarvizu/single_vault_client_with_reauth
Browse files Browse the repository at this point in the history
Single vault client with reauth
  • Loading branch information
patoarvizu authored Jun 22, 2020
2 parents e58dd83 + c8d24ee commit 4342973
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 85 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Environment variable | Required? | Default | Description
---------------------|-----------|---------|------------
`VAULT_IAM_AWS_ACCESS_KEY_ID` | N | No default, but if not specified, a dynamic access key id will be retrieved at runtime using the standard AWS credentials provider chain, assuming one is available. | A static value to use as the access key ID for Vault login purposes.
`VAULT_IAM_AWS_SECRET_ACCESS_KEY` | N | No default, but if not specified, a dynamic secret access key will be retrieved at runtime using the standard AWS credentials provider chain, assuming one is available. | A static value to use as the secret access key for Vault login purposes.
`VAULT_IAM_ROLE` | N | No default, but if a role is not specified, Vault will try to guess the role name based on the principal name associated with the credentials (e.g. the IAM user name or role). **This is the name of a Vault role that must be previously configured, not the IAM role you may be authenticating with.**
`VAULT_IAM_ROLE` | N | No default, but if a role is not specified, Vault will try to guess the role name based on the principal name associated with the credentials (e.g. the IAM user name or role). | The name of a Vault role to assume with the IAM credentials provided. **This is the Vault role that must be previously configured, not the IAM role you may be authenticating with.**
`VAULT_IAM_AUTH_ENDPOINT` | N | `auth/aws/login` | The Vault endpoint to use for this authentication method

**NOTE:** the remote Vault instance will also require runtime permissions to perform the IAM validation actions. Those credentials cannot be set by the operator and must be set directly in the target Vault cluster by other means. Refer to the official Vault [documentation](https://www.vaultproject.io/docs/auth/aws#recommended-vault-iam-policy) for the recommended IAM policy.
Expand Down
17 changes: 6 additions & 11 deletions pkg/controller/kmsvaultsecret/kmsvaultsecret_approleauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package kmsvaultsecret
import (
"errors"
"os"

vaultapi "github.com/hashicorp/vault/api"
)

const (
Expand All @@ -13,18 +11,14 @@ const (

type VaultAppRoleAuth struct{}

func (k8s VaultAppRoleAuth) login(vaultConfig *vaultapi.Config) (string, error) {
func (auth VaultAppRoleAuth) login() error {
roleId, ok := os.LookupEnv("VAULT_APPROLE_ROLE_ID")
if !ok {
return "", errors.New("Environment variable VAULT_APPROLE_ROLE_ID not set")
return errors.New("Environment variable VAULT_APPROLE_ROLE_ID not set")
}
secretId, ok := os.LookupEnv("VAULT_APPROLE_SECRET_ID")
if !ok {
return "", errors.New("Environment variable VAULT_APPROLE_SECRET_ID not set")
}
vaultClient, err := vaultapi.NewClient(vaultConfig)
if err != nil {
return "", err
return errors.New("Environment variable VAULT_APPROLE_SECRET_ID not set")
}
data := map[string]interface{}{
"role_id": roleId,
Expand All @@ -36,7 +30,8 @@ func (k8s VaultAppRoleAuth) login(vaultConfig *vaultapi.Config) (string, error)
}
secretAuth, err := vaultClient.Logical().Write(appRoleEndpoint, data)
if err != nil {
return "", err
return err
}
return secretAuth.Auth.ClientToken, nil
vaultClient.SetToken(secretAuth.Auth.ClientToken)
return nil
}
52 changes: 35 additions & 17 deletions pkg/controller/kmsvaultsecret/kmsvaultsecret_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,27 @@ import (
)

type VaultAuthMethod interface {
login(*vaultapi.Config) (string, error)
login() error
}

func renewToken(m VaultAuthMethod) error {
tokenLookup, err := vaultClient.Auth().Token().LookupSelf()
if err == nil {
expiration := tokenLookup.Data["expire_time"]
t, err := time.Parse(time.RFC3339, expiration.(string))
if err == nil {
now := time.Now()
if t.After(now) {
return nil
}
renewable, _ := tokenLookup.TokenIsRenewable()
if renewable {
vaultClient.Auth().Token().RenewSelf(0)
return nil
}
}
}
return m.login()
}

type KVWriter interface {
Expand All @@ -54,6 +74,8 @@ const (
var log = logf.Log.WithName("controller_kmsvaultsecret")
var rec record.EventRecorder
var reqLogger logr.Logger
var vaultClient *vaultapi.Client
var vaultAuthMethod VaultAuthMethod

func Add(mgr manager.Manager) error {
rec = mgr.GetEventRecorderFor("kms-vault-controller")
Expand All @@ -75,6 +97,17 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
return err
}

vaultClient, err = vaultapi.NewClient(vaultapi.DefaultConfig())
if err != nil {
return err
}

vaultAuthMethod = vaultAuthentication(VaultAuthenticationMethod)
err = vaultAuthMethod.login()
if err != nil {
return err
}

return nil
}

Expand Down Expand Up @@ -108,7 +141,7 @@ func (r *ReconcileKMSVaultSecret) Reconcile(request reconcile.Request) (reconcil
instance.Spec.Secrets = append(instance.Spec.Secrets, partialSecretInstance.Spec.Secrets...)
}

vaultClient, err := getAuthenticatedVaultClient(VaultAuthenticationMethod)
err = renewToken(vaultAuthMethod)
if err != nil {
reqLogger.Error(err, "Error getting authenticated Vault client")
return reconcile.Result{RequeueAfter: time.Second * 15}, err
Expand Down Expand Up @@ -200,21 +233,6 @@ func convertContextMap(context map[string]string) map[string]*string {
return m
}

func getAuthenticatedVaultClient(vaultAuthenticationMethod string) (*vaultapi.Client, error) {
vaultConfig := vaultapi.DefaultConfig()
vaultClient, err := vaultapi.NewClient(vaultConfig)
if err != nil {
return nil, err
}
loginToken, err := vaultAuthentication(vaultAuthenticationMethod).login(vaultConfig)
if err != nil {
return nil, err
}
vaultClient.SetToken(loginToken)
vaultClient.Auth()
return vaultClient, nil
}

func vaultAuthentication(vaultAuthenticationMethod string) VaultAuthMethod {
switch vaultAuthenticationMethod {
case K8sAuthenticationMethod:
Expand Down
15 changes: 5 additions & 10 deletions pkg/controller/kmsvaultsecret/kmsvaultsecret_githubauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package kmsvaultsecret
import (
"errors"
"os"

vaultapi "github.com/hashicorp/vault/api"
)

const (
Expand All @@ -13,14 +11,10 @@ const (

type VaultGitHubAuth struct{}

func (k8s VaultGitHubAuth) login(vaultConfig *vaultapi.Config) (string, error) {
func (auth VaultGitHubAuth) login() error {
githubToken, ok := os.LookupEnv("VAULT_GITHUB_TOKEN")
if !ok {
return "", errors.New("Environment variable VAULT_GITHUB_TOKEN not set")
}
vaultClient, err := vaultapi.NewClient(vaultConfig)
if err != nil {
return "", err
return errors.New("Environment variable VAULT_GITHUB_TOKEN not set")
}
data := map[string]interface{}{
"token": githubToken,
Expand All @@ -31,7 +25,8 @@ func (k8s VaultGitHubAuth) login(vaultConfig *vaultapi.Config) (string, error) {
}
secretAuth, err := vaultClient.Logical().Write(githubAuthEndpoint, data)
if err != nil {
return "", err
return err
}
return secretAuth.Auth.ClientToken, nil
vaultClient.SetToken(secretAuth.Auth.ClientToken)
return nil
}
20 changes: 7 additions & 13 deletions pkg/controller/kmsvaultsecret/kmsvaultsecret_iamauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"os"

vaultapi "github.com/hashicorp/vault/api"
awsauth "github.com/hashicorp/vault/builtin/credential/aws"
)

Expand All @@ -14,7 +13,7 @@ const (

type VaultIAMAuth struct{}

func (k8s VaultIAMAuth) login(vaultConfig *vaultapi.Config) (string, error) {
func (auth VaultIAMAuth) login() error {
logger := log.WithValues("Auth", "IAM")
authIAMAWSAccessKeyId, ok := os.LookupEnv("VAULT_IAM_AWS_ACCESS_KEY_ID")
if !ok {
Expand All @@ -32,28 +31,23 @@ func (k8s VaultIAMAuth) login(vaultConfig *vaultapi.Config) (string, error) {
if !ok {
iamAuthEndpoint = iamAuthDefaultEndpoint
}
vaultClient, err := vaultapi.NewClient(vaultConfig)
if err != nil {
return "", err
}
credentials, err := awsauth.RetrieveCreds(authIAMAWSAccessKeyId, authIAMAWSSecretAccessKey, "")
if err != nil {
return "", err
return err
}
// TODO: Support passing header value
loginData, err := awsauth.GenerateLoginData(credentials, "", "")
if err != nil {
return "", err
return err
}
if loginData == nil {
return "", errors.New("Couldn't generate IAM login data")
return errors.New("Couldn't generate IAM login data")
}
loginData["role"] = authIAMRole
logger.Info("Login data", "loginData", loginData)
secretAuth, err := vaultClient.Logical().Write(iamAuthEndpoint, loginData)
logger.Info("secret auth", "secretAuth", secretAuth)
if err != nil {
return "", err
return err
}
return secretAuth.Auth.ClientToken, nil
vaultClient.SetToken(secretAuth.Auth.ClientToken)
return nil
}
15 changes: 5 additions & 10 deletions pkg/controller/kmsvaultsecret/kmsvaultsecret_k8sauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ package kmsvaultsecret
import (
"io/ioutil"
"os"

vaultapi "github.com/hashicorp/vault/api"
)

type VaultK8sAuth struct{}

func (k8s VaultK8sAuth) login(vaultConfig *vaultapi.Config) (string, error) {
func (auth VaultK8sAuth) login() error {
var vaultK8sRole string
vaultK8sRole, roleSet := os.LookupEnv("VAULT_K8S_ROLE")
if !roleSet {
Expand All @@ -20,21 +18,18 @@ func (k8s VaultK8sAuth) login(vaultConfig *vaultapi.Config) (string, error) {
if !endpointSet {
vaultK8sLoginEndpoint = "auth/kubernetes/login"
}
vaultClient, err := vaultapi.NewClient(vaultConfig)
if err != nil {
return "", err
}
vaultToken, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
if err != nil {
return "", err
return err
}
data := map[string]interface{}{
"jwt": string(vaultToken),
"role": vaultK8sRole,
}
secretAuth, err := vaultClient.Logical().Write(vaultK8sLoginEndpoint, data)
if err != nil {
return "", err
return err
}
return secretAuth.Auth.ClientToken, nil
vaultClient.SetToken(secretAuth.Auth.ClientToken)
return nil
}
9 changes: 4 additions & 5 deletions pkg/controller/kmsvaultsecret/kmsvaultsecret_tokenauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ package kmsvaultsecret
import (
"errors"
"os"

vaultapi "github.com/hashicorp/vault/api"
)

type VaultTokenAuth struct{}

func (k8s VaultTokenAuth) login(vaultConfig *vaultapi.Config) (string, error) {
func (auth VaultTokenAuth) login() error {
vaultToken, set := os.LookupEnv("VAULT_TOKEN")
if !set {
return "", errors.New("VAULT_TOKEN environment variable not found")
return errors.New("VAULT_TOKEN environment variable not found")
}
return vaultToken, nil
vaultClient.SetToken(vaultToken)
return nil
}
21 changes: 8 additions & 13 deletions pkg/controller/kmsvaultsecret/kmsvaultsecret_userpassauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package kmsvaultsecret

import (
"errors"
"fmt"
"os"

vaultapi "github.com/hashicorp/vault/api"
)

const (
Expand All @@ -13,26 +12,22 @@ const (

type VaultUserpassAuth struct{}

func (k8s VaultUserpassAuth) login(vaultConfig *vaultapi.Config) (string, error) {
func (auth VaultUserpassAuth) login() error {
vaultUsername, usernameSet := os.LookupEnv("VAULT_USERNAME")
if !usernameSet {
return "", errors.New("Environment variable VAULT_USERNAME not set")
return errors.New("Environment variable VAULT_USERNAME not set")
}
vaultPassword, passwordSet := os.LookupEnv("VAULT_PASSWORD")
if !passwordSet {
return "", errors.New("Environment variable VAULT_PASSWORD not set")
}
vaultClient, err := vaultapi.NewClient(vaultConfig)
if err != nil {
return "", err
return errors.New("Environment variable VAULT_PASSWORD not set")
}
data := map[string]interface{}{
"username": vaultUsername,
"password": vaultPassword,
}
secretAuth, err := vaultClient.Logical().Write(userpassLoginEndpoint, data)
secretAuth, err := vaultClient.Logical().Write(fmt.Sprintf("%s/%s", userpassLoginEndpoint, vaultUsername), data)
if err != nil {
return "", err
return err
}
return secretAuth.Auth.ClientToken, nil
vaultClient.SetToken(secretAuth.Auth.ClientToken)
return nil
}
5 changes: 0 additions & 5 deletions test/manifests/global/operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,6 @@ spec:
value: "https://vault.vault:8200"
- name: VAULT_SKIP_VERIFY
value: "true"
- name: VAULT_TOKEN
valueFrom:
secretKeyRef:
name: vault-unseal-keys
key: vault-root
- name: kms-vault-validating-webhook
image: patoarvizu/kms-vault-operator:latest
imagePullPolicy: IfNotPresent
Expand Down

0 comments on commit 4342973

Please sign in to comment.