token/disk: implement unencrypted disk store
This commit is contained in:
parent
62e36ecb68
commit
27bc188758
|
@ -0,0 +1,89 @@
|
|||
package disk
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
// DefaultPath is the default path where the Vault token is stored.
|
||||
const DefaultPath = "~/.vault-token"
|
||||
|
||||
type Command struct{}
|
||||
|
||||
func (c *Command) Run(args []string) int {
|
||||
var path string
|
||||
f := flag.NewFlagSet("token-disk", flag.ContinueOnError)
|
||||
f.StringVar(&path, "path", DefaultPath, "")
|
||||
f.Usage = func() { fmt.Fprintf(os.Stderr, c.Help()+"\n") }
|
||||
if err := f.Parse(args); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "\n%s\n", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
path, err := homedir.Expand(path)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error expanding directory: %s\n", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case "get":
|
||||
f, err := os.Open(path)
|
||||
if os.IsNotExist(err) {
|
||||
return 0
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
return 1
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := io.Copy(os.Stdout, f); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
return 1
|
||||
}
|
||||
case "store":
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
return 1
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := io.Copy(f, os.Stdin); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
return 1
|
||||
}
|
||||
case "erase":
|
||||
if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *Command) Synopsis() string {
|
||||
return "Stores Vault tokens on disk"
|
||||
}
|
||||
|
||||
func (c *Command) Help() string {
|
||||
helpText := `
|
||||
Usage: vault token-disk [options] [operation]
|
||||
|
||||
Vault token helper (see vault config "token_helper") that writes
|
||||
authenticated tokens to disk unencrypted.
|
||||
|
||||
Options:
|
||||
|
||||
-path=path Path to store the token.
|
||||
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package disk
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/command/token"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
token.TestProcess(t)
|
||||
}
|
||||
|
||||
func TestHelperProcess(t *testing.T) {
|
||||
token.TestHelperProcessCLI(t, new(Command))
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package command
|
||||
|
||||
// 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 Config 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 token-disk will be used, which stores
|
||||
// the token on disk unencrypted.
|
||||
TokenHelper string `hcl:"token_helper"`
|
||||
}
|
|
@ -2,6 +2,7 @@ package token
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
|
@ -24,16 +25,23 @@ type Helper struct {
|
|||
// Erase deletes the contents from the helper.
|
||||
func (h *Helper) Erase() error {
|
||||
cmd := h.cmd("erase")
|
||||
return cmd.Run()
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error: %s\n\n%s", err, string(output))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get gets the token value from the helper.
|
||||
func (h *Helper) Get() (string, error) {
|
||||
var buf bytes.Buffer
|
||||
var buf, stderr bytes.Buffer
|
||||
cmd := h.cmd("get")
|
||||
cmd.Stdout = &buf
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf(
|
||||
"Error: %s\n\n%s", err, stderr.String())
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
|
@ -44,7 +52,12 @@ func (h *Helper) Store(v string) error {
|
|||
buf := bytes.NewBufferString(v)
|
||||
cmd := h.cmd("store")
|
||||
cmd.Stdin = buf
|
||||
return cmd.Run()
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error: %s\n\n%s", err, string(output))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Helper) cmd(op string) *exec.Cmd {
|
||||
|
|
|
@ -11,31 +11,7 @@ import (
|
|||
|
||||
func TestHelper(t *testing.T) {
|
||||
h := testHelper(t)
|
||||
if err := h.Store("foo"); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
v, err := h.Get()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if v != "foo" {
|
||||
t.Fatalf("bad: %#v", v)
|
||||
}
|
||||
|
||||
if err := h.Erase(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
v, err = h.Get()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if v != "" {
|
||||
t.Fatalf("bad: %#v", v)
|
||||
}
|
||||
Test(t, h.Path)
|
||||
}
|
||||
|
||||
func testHelper(t *testing.T) *Helper {
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package token
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// Test is a public function that can be used in other tests to
|
||||
// test that a helper is functioning properly.
|
||||
func Test(t *testing.T, path string) {
|
||||
h := &Helper{Path: path}
|
||||
if err := h.Store("foo"); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
v, err := h.Get()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if v != "foo" {
|
||||
t.Fatalf("bad: %#v", v)
|
||||
}
|
||||
|
||||
if err := h.Erase(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
v, err = h.Get()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if v != "" {
|
||||
t.Fatalf("bad: %#v", v)
|
||||
}
|
||||
}
|
||||
|
||||
// TestProcess is used to re-execute this test in order to use it as the
|
||||
// helper process. For this to work, the TestHelperProcess function must
|
||||
// exist.
|
||||
func TestProcess(t *testing.T, s ...string) {
|
||||
// Build the path to the CLI to execute
|
||||
cs := []string{"-test.run=TestHelperProcess", "--"}
|
||||
cs = append(cs, s...)
|
||||
path := fmt.Sprintf(
|
||||
"GO_WANT_HELPER_PROCESS=1 %s %s",
|
||||
os.Args[0],
|
||||
strings.Join(cs, " "))
|
||||
|
||||
// Run the tests
|
||||
Test(t, path)
|
||||
}
|
||||
|
||||
// TestHelperProcessCLI can be called to implement TestHelperProcess
|
||||
// for TestProcess that just executes a CLI command.
|
||||
func TestHelperProcessCLI(t *testing.T, cmd cli.Command) {
|
||||
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
|
||||
return
|
||||
}
|
||||
|
||||
args := os.Args
|
||||
for len(args) > 0 {
|
||||
if args[0] == "--" {
|
||||
args = args[1:]
|
||||
break
|
||||
}
|
||||
|
||||
args = args[1:]
|
||||
}
|
||||
|
||||
os.Exit(cmd.Run(args))
|
||||
}
|
16
commands.go
16
commands.go
|
@ -5,13 +5,16 @@ import (
|
|||
|
||||
"github.com/hashicorp/vault/builtin/logical/aws"
|
||||
"github.com/hashicorp/vault/builtin/logical/consul"
|
||||
tokenDisk "github.com/hashicorp/vault/builtin/token/disk"
|
||||
"github.com/hashicorp/vault/command"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// Commands is the mapping of all the available Consul commands.
|
||||
// Commands is the mapping of all the available Vault commands. CommandsInclude
|
||||
// are the commands to include for help.
|
||||
var Commands map[string]cli.CommandFactory
|
||||
var CommandsInclude []string
|
||||
|
||||
func init() {
|
||||
ui := &cli.BasicUi{
|
||||
|
@ -97,4 +100,15 @@ func init() {
|
|||
}, nil
|
||||
},
|
||||
}
|
||||
|
||||
// Build the commands to include in the help now
|
||||
CommandsInclude = make([]string, 0, len(Commands))
|
||||
for k, _ := range Commands {
|
||||
CommandsInclude = append(CommandsInclude, k)
|
||||
}
|
||||
|
||||
// The commands below are hidden from the help output
|
||||
Commands["token-disk"] = func() (cli.Command, error) {
|
||||
return &tokenDisk.Command{}, nil
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue