Skip to content

Commit

Permalink
Support configuring all Vault connection details in flags (#138)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomhjp committed Feb 8, 2022
1 parent 664d6f9 commit 1f4c3a2
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 131 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
## Unreleased

IMPROVEMENTS:

* New flags to configure default Vault namespace and TLS details. [[GH-138](https://github.com/hashicorp/vault-csi-provider/pull/138)]
* `-vault-namespace`
* `-vault-tls-ca-cert`
* `-vault-tls-ca-directory`
* `-vault-tls-server-name`
* `-vault-tls-client-cert`
* `-vault-tls-client-key`
* `-vault-tls-skip-verify`

## 1.0.0 (January 25th, 2022)

CHANGES:
Expand Down
47 changes: 35 additions & 12 deletions internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,47 @@ import (
"github.com/hashicorp/vault/api"
)

func New(vaultAddress string, tlsConfig config.TLSConfig) (*api.Client, error) {
// New creates a Vault client configured for a specific SecretProviderClass (SPC).
// Config is read from environment variables first, then flags, then the SPC in
// ascending order of precedence.
func New(spcParameters config.Parameters, flagsConfig config.FlagsConfig) (*api.Client, error) {
cfg := api.DefaultConfig()
err := cfg.ConfigureTLS(&api.TLSConfig{
CACert: tlsConfig.CACertPath,
CAPath: tlsConfig.CADirectory,
ClientCert: tlsConfig.ClientCertPath,
ClientKey: tlsConfig.ClientKeyPath,
TLSServerName: tlsConfig.TLSServerName,
Insecure: tlsConfig.SkipVerify,
})
if cfg.Error != nil {
return nil, cfg.Error
}
if err := overlayConfig(cfg, flagsConfig.VaultAddr, flagsConfig.TLSConfig()); err != nil {
return nil, err
}
if err := overlayConfig(cfg, spcParameters.VaultAddress, spcParameters.VaultTLSConfig); err != nil {
return nil, err
}

client, err := api.NewClient(cfg)
if err != nil {
return nil, err
}
if vaultAddress != "" {
cfg.Address = vaultAddress

// Set Vault namespace if configured.
if flagsConfig.VaultNamespace != "" {
client.SetNamespace(flagsConfig.VaultNamespace)
}
if spcParameters.VaultNamespace != "" {
client.SetNamespace(spcParameters.VaultNamespace)
}

return client, nil
}

func overlayConfig(cfg *api.Config, vaultAddr string, tlsConfig api.TLSConfig) error {
err := cfg.ConfigureTLS(&tlsConfig)
if err != nil {
return err
}
if vaultAddr != "" {
cfg.Address = vaultAddr
}

return api.NewClient(cfg)
return nil
}

func Do(ctx context.Context, c *api.Client, req *api.Request) (*api.Secret, error) {
Expand Down
50 changes: 41 additions & 9 deletions internal/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"time"

"github.com/hashicorp/vault-csi-provider/internal/config"
"github.com/hashicorp/vault/api"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

Expand All @@ -31,30 +33,60 @@ func TestNew(t *testing.T) {

for _, tc := range []struct {
name string
cfg config.TLSConfig
cfg api.TLSConfig
}{
{
name: "file",
cfg: config.TLSConfig{
CACertPath: caPath,
cfg: api.TLSConfig{
CACert: caPath,
},
},
{
name: "directory",
cfg: config.TLSConfig{
CADirectory: "testdata",
cfg: api.TLSConfig{
CAPath: "testdata",
},
},
} {
_, err = New("https://vault:8200", tc.cfg)
_, err = New(config.Parameters{
VaultTLSConfig: tc.cfg,
}, config.FlagsConfig{})
require.NoError(t, err, tc.name)
}
}

func TestNew_Error(t *testing.T) {
_, err := New("https://vault:8200", config.TLSConfig{
CADirectory: "bad_directory",
func TestConfigPrecedence(t *testing.T) {
if originalVaultAddr, isSet := os.LookupEnv(api.EnvVaultAddress); isSet {
defer os.Setenv(api.EnvVaultAddress, originalVaultAddr)
}
err := os.Setenv(api.EnvVaultAddress, "from-env")
require.NoError(t, err)

client, err := New(config.Parameters{}, config.FlagsConfig{})
require.NoError(t, err)
assert.Equal(t, "from-env", client.Address())

client, err = New(config.Parameters{}, config.FlagsConfig{
VaultAddr: "from-flags",
})
require.NoError(t, err)
assert.Equal(t, "from-flags", client.Address())

client, err = New(config.Parameters{
VaultAddress: "from-parameters",
}, config.FlagsConfig{
VaultAddr: "from-flags",
})
require.NoError(t, err)
assert.Equal(t, "from-parameters", client.Address())
}

func TestNew_Error(t *testing.T) {
_, err := New(config.Parameters{
VaultTLSConfig: api.TLSConfig{
CAPath: "bad_directory",
},
}, config.FlagsConfig{})
require.Error(t, err)
}

Expand Down
77 changes: 44 additions & 33 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,51 @@ import (
"os"
"strconv"

"github.com/hashicorp/vault/api"
"gopkg.in/yaml.v3"
"k8s.io/apimachinery/pkg/types"
)

// Config represents all of the provider's configurable behaviour from the MountRequest proto message:
// Config represents all of the provider's configurable behaviour from the SecretProviderClass,
// transmitted in the MountRequest proto message:
// * Parameters from the `Attributes` field.
// * Plus the rest of the proto fields we consume.
// See sigs.k8s.io/secrets-store-csi-driver/provider/v1alpha1/service.pb.go
type Config struct {
Parameters
Parameters Parameters
TargetPath string
FilePermission os.FileMode
}

type FlagsConfig struct {
Endpoint string
Debug bool
Version bool
HealthAddr string

VaultAddr string
VaultMount string
VaultNamespace string

TLSCACertPath string
TLSCADirectory string
TLSServerName string
TLSClientCert string
TLSClientKey string
TLSSkipVerify bool
}

func (fc FlagsConfig) TLSConfig() api.TLSConfig {
return api.TLSConfig{
CACert: fc.TLSCACertPath,
CAPath: fc.TLSCADirectory,
ClientCert: fc.TLSClientCert,
ClientKey: fc.TLSClientKey,
TLSServerName: fc.TLSServerName,
Insecure: fc.TLSSkipVerify,
}
}

// Parameters stores the parameters specified in a mount request's `Attributes` field.
// It consists of the parameters section from the SecretProviderClass being mounted
// and pod metadata provided by the driver.
Expand All @@ -34,20 +65,11 @@ type Parameters struct {
VaultRoleName string
VaultKubernetesMountPath string
VaultNamespace string
VaultTLSConfig TLSConfig
VaultTLSConfig api.TLSConfig
Secrets []Secret
PodInfo PodInfo
}

type TLSConfig struct {
CACertPath string
CADirectory string
TLSServerName string
SkipVerify bool
ClientCertPath string
ClientKeyPath string
}

type PodInfo struct {
Name string
UID types.UID
Expand All @@ -63,31 +85,29 @@ type Secret struct {
SecretArgs map[string]interface{} `yaml:"secretArgs,omitempty"`
}

func Parse(parametersStr, targetPath, permissionStr string, defaultVaultAddr string, defaultVaultKubernetesMountPath string) (Config, error) {
func Parse(parametersStr, targetPath, permissionStr string) (Config, error) {
config := Config{
TargetPath: targetPath,
}

var err error
config.Parameters, err = parseParameters(parametersStr, defaultVaultAddr, defaultVaultKubernetesMountPath)
config.Parameters, err = parseParameters(parametersStr)
if err != nil {
return Config{}, err
}

err = json.Unmarshal([]byte(permissionStr), &config.FilePermission)
if err != nil {
if err := json.Unmarshal([]byte(permissionStr), &config.FilePermission); err != nil {
return Config{}, err
}

err = config.validate()
if err != nil {
if err := config.validate(); err != nil {
return Config{}, err
}

return config, nil
}

func parseParameters(parametersStr string, defaultVaultAddress string, defaultVaultKubernetesMountPath string) (Parameters, error) {
func parseParameters(parametersStr string) (Parameters, error) {
var params map[string]string
err := json.Unmarshal([]byte(parametersStr), &params)
if err != nil {
Expand All @@ -98,11 +118,11 @@ func parseParameters(parametersStr string, defaultVaultAddress string, defaultVa
parameters.VaultRoleName = params["roleName"]
parameters.VaultAddress = params["vaultAddress"]
parameters.VaultNamespace = params["vaultNamespace"]
parameters.VaultTLSConfig.CACertPath = params["vaultCACertPath"]
parameters.VaultTLSConfig.CADirectory = params["vaultCADirectory"]
parameters.VaultTLSConfig.CACert = params["vaultCACertPath"]
parameters.VaultTLSConfig.CAPath = params["vaultCADirectory"]
parameters.VaultTLSConfig.TLSServerName = params["vaultTLSServerName"]
parameters.VaultTLSConfig.ClientCertPath = params["vaultTLSClientCertPath"]
parameters.VaultTLSConfig.ClientKeyPath = params["vaultTLSClientKeyPath"]
parameters.VaultTLSConfig.ClientCert = params["vaultTLSClientCertPath"]
parameters.VaultTLSConfig.ClientKey = params["vaultTLSClientKeyPath"]
parameters.VaultKubernetesMountPath = params["vaultKubernetesMountPath"]
parameters.PodInfo.Name = params["csi.storage.k8s.io/pod.name"]
parameters.PodInfo.UID = types.UID(params["csi.storage.k8s.io/pod.uid"])
Expand All @@ -111,7 +131,7 @@ func parseParameters(parametersStr string, defaultVaultAddress string, defaultVa
if skipTLS, ok := params["vaultSkipTLSVerify"]; ok {
value, err := strconv.ParseBool(skipTLS)
if err == nil {
parameters.VaultTLSConfig.SkipVerify = value
parameters.VaultTLSConfig.Insecure = value
} else {
return Parameters{}, err
}
Expand All @@ -123,15 +143,6 @@ func parseParameters(parametersStr string, defaultVaultAddress string, defaultVa
return Parameters{}, err
}

// Set default values.
if parameters.VaultAddress == "" {
parameters.VaultAddress = defaultVaultAddress
}

if parameters.VaultKubernetesMountPath == "" {
parameters.VaultKubernetesMountPath = defaultVaultKubernetesMountPath
}

return parameters, nil
}

Expand Down
Loading

0 comments on commit 1f4c3a2

Please sign in to comment.