Skip to content

Commit

Permalink
Merge PR #9060: Support reading Raft TLS flags from file
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored and andaley committed Jul 17, 2020
1 parent 0822ab1 commit bae5232
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ CHANGES:

IMPROVEMENTS:

* cli: Support reading TLS parameters from file for the `vault operator raft join` command. [[GH-9060](https://github.com/hashicorp/vault/pull/9060)]
* plugin: Add SDK method, `Sys.ReloadPlugin`, and CLI command, `vault plugin reload`,
for reloading plugins. [[GH-8777](https://github.com/hashicorp/vault/pull/8777)]
* sdk/framework: Support accepting TypeFloat parameters over the API [[GH-8923](https://github.com/hashicorp/vault/pull/8923)]
Expand Down
19 changes: 19 additions & 0 deletions command/base_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"strings"
"time"

"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/api"
kvbuilder "github.com/hashicorp/vault/internalshared/kv-builder"
"github.com/kr/text"
Expand Down Expand Up @@ -273,3 +275,20 @@ func humanDurationInt(i interface{}) interface{} {
// If we don't know what type it is, just return the original value
return i
}

// parseFlagFile accepts a flag value returns the contets of that value. If the
// value starts with '@', that indicates the value is a file and its content
// should be read and returned. Otherwise, the raw value is returned.
func parseFlagFile(raw string) (string, error) {
// check if the provided argument should be read from file
if len(raw) > 0 && raw[0] == '@' {
contents, err := ioutil.ReadFile(raw[1:])
if err != nil {
return "", errwrap.Wrapf("error reading file: {{err}}", err)
}

return string(contents), nil
}

return raw, nil
}
49 changes: 49 additions & 0 deletions command/base_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,52 @@ func TestTruncateToSeconds(t *testing.T) {
})
}
}

func TestParseFlagFile(t *testing.T) {
t.Parallel()

content := "some raw content"
tmpFile, err := ioutil.TempFile(os.TempDir(), "TestParseFlagFile")
if err != nil {
t.Fatalf("failed to create temporary file: %v", err)
}

defer os.Remove(tmpFile.Name())

if _, err := tmpFile.WriteString(content); err != nil {
t.Fatalf("failed to write to temporary file: %v", err)
}

cases := []struct {
value string
exp string
}{
{
"",
"",
},
{
content,
content,
},
{
fmt.Sprintf("@%s", tmpFile.Name()),
content,
},
}

for _, tc := range cases {
tc := tc

t.Run(tc.value, func(t *testing.T) {
content, err := parseFlagFile(tc.value)
if err != nil {
t.Fatalf("unexpected error parsing flag value: %v", err)
}

if content != tc.exp {
t.Fatalf("expected %s to be %s", content, tc.exp)
}
})
}
}
41 changes: 34 additions & 7 deletions command/operator_raft_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ Usage: vault operator raft join [options] <leader-api-addr>
Join the current node as a peer to the Raft cluster by providing the address
of the Raft leader node.
$ vault operator raft join "http://127.0.0.2:8200"
$ vault operator raft join "http://127.0.0.2:8200"
TLS certificate data can also be consumed from a file on disk by prefixing with
the "@" symbol. For example:
$ vault operator raft join "http://127.0.0.2:8200" \
-leader-ca-cert=@leader_ca.crt \
-leader-client-cert=@leader_client.crt \
-leader-client-key=@leader.key
` + c.Flags().Help()

Expand Down Expand Up @@ -114,6 +122,24 @@ func (c *OperatorRaftJoinCommand) Run(args []string) int {
return 1
}

leaderCACert, err := parseFlagFile(c.flagLeaderCACert)
if err != nil {
c.UI.Error(fmt.Sprintf("Failed to parse leader CA certificate: %s", err))
return 1
}

leaderClientCert, err := parseFlagFile(c.flagLeaderClientCert)
if err != nil {
c.UI.Error(fmt.Sprintf("Failed to parse leader client certificate: %s", err))
return 1
}

leaderClientKey, err := parseFlagFile(c.flagLeaderClientKey)
if err != nil {
c.UI.Error(fmt.Sprintf("Failed to parse leader client key: %s", err))
return 1
}

client, err := c.Client()
if err != nil {
c.UI.Error(err.Error())
Expand All @@ -122,9 +148,9 @@ func (c *OperatorRaftJoinCommand) Run(args []string) int {

resp, err := client.Sys().RaftJoin(&api.RaftJoinRequest{
LeaderAPIAddr: leaderAPIAddr,
LeaderCACert: c.flagLeaderCACert,
LeaderClientCert: c.flagLeaderClientCert,
LeaderClientKey: c.flagLeaderClientKey,
LeaderCACert: leaderCACert,
LeaderClientCert: leaderClientCert,
LeaderClientKey: leaderClientKey,
Retry: c.flagRetry,
NonVoter: c.flagNonVoter,
})
Expand All @@ -139,9 +165,10 @@ func (c *OperatorRaftJoinCommand) Run(args []string) int {
return OutputData(c.UI, resp)
}

out := []string{}
out = append(out, "Key | Value")
out = append(out, fmt.Sprintf("Joined | %t", resp.Joined))
out := []string{
"Key | Value",
fmt.Sprintf("Joined | %t", resp.Joined),
}
c.UI.Output(tableOutput(out, nil))

return 0
Expand Down

0 comments on commit bae5232

Please sign in to comment.