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

Move default token helper to api #25744

Merged
merged 13 commits into from
Mar 4, 2024
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Vagrantfile
!command/agent/config/test-fixtures/*.hcl
!command/server/test-fixtures/**/*.hcl
!enos/**/*.hcl
!**/testdata/*.hcl

# Enos
.enos
Expand Down
68 changes: 32 additions & 36 deletions command/config/config.go → api/cliconfig/config.go
Original file line number Diff line number Diff line change
@@ -1,58 +1,45 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
// SPDX-License-Identifier: MPL-2.0

package config
package cliconfig

import (
"fmt"
"io/ioutil"
"os"

"github.com/hashicorp/go-multierror"
"github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/ast"
"github.com/hashicorp/vault/sdk/helper/hclutil"
homedir "github.com/mitchellh/go-homedir"
"github.com/mitchellh/go-homedir"
)

const (
// DefaultConfigPath is the default path to the configuration file
DefaultConfigPath = "~/.vault"
// defaultConfigPath is the default path to the configuration file
defaultConfigPath = "~/.vault"

// ConfigPathEnv is the environment variable that can be used to
// configPathEnv is the environment variable that can be used to
// override where the Vault configuration is.
ConfigPathEnv = "VAULT_CONFIG_PATH"
configPathEnv = "VAULT_CONFIG_PATH"
)

// Config is the CLI configuration for Vault that can be specified via
// a `$HOME/.vault` file which is HCL-formatted (therefore HCL or JSON).
type DefaultConfig struct {
type defaultConfig struct {
// TokenHelper is the executable/command that is executed for storing
// and retrieving the authentication token for the Vault CLI. If this
// is not specified, then vault's internal token store will be used, which
// stores the token on disk unencrypted.
TokenHelper string `hcl:"token_helper"`
}

// Config loads the configuration and returns it. If the configuration
// is already loaded, it is returned.
func Config() (*DefaultConfig, error) {
var err error
config, err := LoadConfig("")
if err != nil {
return nil, err
}

return config, nil
}

// LoadConfig reads the configuration from the given path. If path is
// loadConfig reads the configuration from the given path. If path is
// empty, then the default path will be used, or the environment variable
// if set.
func LoadConfig(path string) (*DefaultConfig, error) {
func loadConfig(path string) (*defaultConfig, error) {
if path == "" {
path = DefaultConfigPath
path = defaultConfigPath
}
if v := os.Getenv(ConfigPathEnv); v != "" {
if v := os.Getenv(configPathEnv); v != "" {
path = v
}

Expand All @@ -62,21 +49,21 @@ func LoadConfig(path string) (*DefaultConfig, error) {
return nil, fmt.Errorf("error expanding config path %q: %w", path, err)
}

contents, err := ioutil.ReadFile(path)
contents, err := os.ReadFile(path)
if err != nil && !os.IsNotExist(err) {
return nil, err
}

conf, err := ParseConfig(string(contents))
conf, err := parseConfig(string(contents))
if err != nil {
return nil, fmt.Errorf("error parsing config file at %q: %w; ensure that the file is valid; Ansible Vault is known to conflict with it.", path, err)
return nil, fmt.Errorf("error parsing config file at %q: %w; ensure that the file is valid; Ansible Vault is known to conflict with it", path, err)
}

return conf, nil
}

// ParseConfig parses the given configuration as a string.
func ParseConfig(contents string) (*DefaultConfig, error) {
// parseConfig parses the given configuration as a string.
func parseConfig(contents string) (*defaultConfig, error) {
root, err := hcl.Parse(contents)
if err != nil {
return nil, err
Expand All @@ -88,14 +75,23 @@ func ParseConfig(contents string) (*DefaultConfig, error) {
return nil, fmt.Errorf("failed to parse config; does not contain a root object")
}

valid := []string{
"token_helper",
valid := map[string]struct{}{
"token_helper": {},
}
if err := hclutil.CheckHCLKeys(list, valid); err != nil {
return nil, err

var validationErrors error
for _, item := range list.Items {
key := item.Keys[0].Token.Value().(string)
if _, ok := valid[key]; !ok {
validationErrors = multierror.Append(validationErrors, fmt.Errorf("invalid key %q on line %d", key, item.Assign.Line))
}
}

if validationErrors != nil {
return nil, validationErrors
}

var c DefaultConfig
var c defaultConfig
if err := hcl.DecodeObject(&c, list); err != nil {
return nil, err
}
Expand Down
14 changes: 6 additions & 8 deletions command/config_test.go → api/cliconfig/config_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
// SPDX-License-Identifier: MPL-2.0

package command
package cliconfig

import (
"path/filepath"
Expand All @@ -10,15 +10,13 @@ import (
"testing"
)

const FixturePath = "./test-fixtures"

func TestLoadConfig(t *testing.T) {
config, err := LoadConfig(filepath.Join(FixturePath, "config.hcl"))
config, err := loadConfig(filepath.Join("testdata", "config.hcl"))
if err != nil {
t.Fatalf("err: %s", err)
}

expected := &DefaultConfig{
expected := &defaultConfig{
TokenHelper: "foo",
}
if !reflect.DeepEqual(expected, config) {
Expand All @@ -27,7 +25,7 @@ func TestLoadConfig(t *testing.T) {
}

func TestLoadConfig_noExist(t *testing.T) {
config, err := LoadConfig("nope/not-once/.never")
config, err := loadConfig("nope/not-once/.never")
if err != nil {
t.Fatal(err)
}
Expand All @@ -38,7 +36,7 @@ func TestLoadConfig_noExist(t *testing.T) {
}

func TestParseConfig_badKeys(t *testing.T) {
_, err := ParseConfig(`
_, err := parseConfig(`
token_helper = "/token"
nope = "true"
`)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
# SPDX-License-Identifier: MPL-2.0

token_helper = "foo"
28 changes: 28 additions & 0 deletions api/cliconfig/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package cliconfig

import (
"github.com/hashicorp/vault/api/tokenhelper"
)

// DefaultTokenHelper returns the token helper that is configured for Vault.
// This helper should only be used for non-server CLI commands.
func DefaultTokenHelper() (tokenhelper.TokenHelper, error) {
config, err := loadConfig("")
if err != nil {
return nil, err
}

path := config.TokenHelper
if path == "" {
return tokenhelper.NewInternalTokenHelper()
}

path, err = tokenhelper.ExternalTokenHelperPath(path)
if err != nil {
return nil, err
}
return &tokenhelper.ExternalTokenHelper{BinaryPath: path}, nil
}
9 changes: 5 additions & 4 deletions api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,21 @@ require (
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2
github.com/hashicorp/hcl v1.0.0
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.5.0
github.com/natefinch/atomic v1.0.1
github.com/stretchr/testify v1.8.4
golang.org/x/net v0.17.0
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.7.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
github.com/mattn/go-colorable v0.1.6 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
Expand Down
18 changes: 11 additions & 7 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4r
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA=
github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw=
Expand Down Expand Up @@ -41,20 +42,23 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
Expand All @@ -79,8 +83,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
4 changes: 2 additions & 2 deletions command/token/helper.go → api/tokenhelper/helper.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
// SPDX-License-Identifier: MPL-2.0

package token
package tokenhelper

// TokenHelper is an interface that contains basic operations that must be
// implemented by a token helper
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
// SPDX-License-Identifier: MPL-2.0

package token
package tokenhelper

import (
"bytes"
Expand Down Expand Up @@ -110,16 +110,16 @@ func (h *ExternalTokenHelper) Path() string {

func (h *ExternalTokenHelper) cmd(op string) (*exec.Cmd, error) {
script := strings.ReplaceAll(h.BinaryPath, "\\", "\\\\") + " " + op
cmd, err := ExecScript(script)
cmd, err := execScript(script)
if err != nil {
return nil, err
}
cmd.Env = h.Env
return cmd, nil
}

// ExecScript returns a command to execute a script
func ExecScript(script string) (*exec.Cmd, error) {
// execScript returns a command to execute a script
func execScript(script string) (*exec.Cmd, error) {
var shell, flag string
if runtime.GOOS == "windows" {
shell = "cmd"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
// SPDX-License-Identifier: MPL-2.0

package token
package tokenhelper

import (
"fmt"
"io"
"io/ioutil"
"os"
"runtime"
"strings"
Expand Down Expand Up @@ -54,10 +53,10 @@ func TestExternalTokenHelperPath(t *testing.T) {
}

func TestExternalTokenHelper(t *testing.T) {
Test(t, testExternalTokenHelper(t))
test(t, testExternalTokenHelper())
}

func testExternalTokenHelper(t *testing.T) *ExternalTokenHelper {
func testExternalTokenHelper() *ExternalTokenHelper {
return &ExternalTokenHelper{BinaryPath: helperPath("helper"), Env: helperEnv()}
}

Expand All @@ -73,7 +72,7 @@ func helperPath(s ...string) string {
func helperEnv() []string {
var env []string

tf, err := ioutil.TempFile("", "vault")
tf, err := os.CreateTemp("", "vault")
if err != nil {
panic(err)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
// SPDX-License-Identifier: MPL-2.0

package token
package tokenhelper

import (
"bytes"
Expand Down
Loading
Loading