mirror of https://github.com/status-im/consul.git
Added -relay-factor param to keyring operations
This commit is contained in:
parent
ed5bf524ba
commit
5d888f5303
|
@ -121,31 +121,44 @@ func (a *Agent) keyringProcess(args *structs.KeyringRequest) (*structs.KeyringRe
|
||||||
return &reply, nil
|
return &reply, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseRelayFactor validates and converts the given relay factor to uint8
|
||||||
|
func ParseRelayFactor(n int) (uint8, error) {
|
||||||
|
if n < 0 || n > 5 {
|
||||||
|
return 0, fmt.Errorf("Relay factor must be in range: [0, 5]")
|
||||||
|
}
|
||||||
|
return uint8(n), nil
|
||||||
|
}
|
||||||
|
|
||||||
// ListKeys lists out all keys installed on the collective Consul cluster. This
|
// ListKeys lists out all keys installed on the collective Consul cluster. This
|
||||||
// includes both servers and clients in all DC's.
|
// includes both servers and clients in all DC's.
|
||||||
func (a *Agent) ListKeys(token string) (*structs.KeyringResponses, error) {
|
func (a *Agent) ListKeys(token string, relayFactor uint8) (*structs.KeyringResponses, error) {
|
||||||
args := structs.KeyringRequest{Operation: structs.KeyringList}
|
args := structs.KeyringRequest{Operation: structs.KeyringList}
|
||||||
args.Token = token
|
parseKeyringRequest(&args, token, relayFactor)
|
||||||
return a.keyringProcess(&args)
|
return a.keyringProcess(&args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallKey installs a new gossip encryption key
|
// InstallKey installs a new gossip encryption key
|
||||||
func (a *Agent) InstallKey(key, token string) (*structs.KeyringResponses, error) {
|
func (a *Agent) InstallKey(key, token string, relayFactor uint8) (*structs.KeyringResponses, error) {
|
||||||
args := structs.KeyringRequest{Key: key, Operation: structs.KeyringInstall}
|
args := structs.KeyringRequest{Key: key, Operation: structs.KeyringInstall}
|
||||||
args.Token = token
|
parseKeyringRequest(&args, token, relayFactor)
|
||||||
return a.keyringProcess(&args)
|
return a.keyringProcess(&args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseKey changes the primary encryption key used to encrypt messages
|
// UseKey changes the primary encryption key used to encrypt messages
|
||||||
func (a *Agent) UseKey(key, token string) (*structs.KeyringResponses, error) {
|
func (a *Agent) UseKey(key, token string, relayFactor uint8) (*structs.KeyringResponses, error) {
|
||||||
args := structs.KeyringRequest{Key: key, Operation: structs.KeyringUse}
|
args := structs.KeyringRequest{Key: key, Operation: structs.KeyringUse}
|
||||||
args.Token = token
|
parseKeyringRequest(&args, token, relayFactor)
|
||||||
return a.keyringProcess(&args)
|
return a.keyringProcess(&args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveKey will remove a gossip encryption key from the keyring
|
// RemoveKey will remove a gossip encryption key from the keyring
|
||||||
func (a *Agent) RemoveKey(key, token string) (*structs.KeyringResponses, error) {
|
func (a *Agent) RemoveKey(key, token string, relayFactor uint8) (*structs.KeyringResponses, error) {
|
||||||
args := structs.KeyringRequest{Key: key, Operation: structs.KeyringRemove}
|
args := structs.KeyringRequest{Key: key, Operation: structs.KeyringRemove}
|
||||||
args.Token = token
|
parseKeyringRequest(&args, token, relayFactor)
|
||||||
return a.keyringProcess(&args)
|
return a.keyringProcess(&args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseKeyringRequest(req *structs.KeyringRequest, token string, relayFactor uint8) {
|
||||||
|
req.Token = token
|
||||||
|
req.RelayFactor = relayFactor
|
||||||
|
}
|
||||||
|
|
|
@ -132,49 +132,49 @@ func TestAgentKeyring_ACL(t *testing.T) {
|
||||||
testutil.WaitForLeader(t, agent.RPC, "dc1")
|
testutil.WaitForLeader(t, agent.RPC, "dc1")
|
||||||
|
|
||||||
// List keys without access fails
|
// List keys without access fails
|
||||||
_, err := agent.ListKeys("")
|
_, err := agent.ListKeys("", 0)
|
||||||
if err == nil || !strings.Contains(err.Error(), "denied") {
|
if err == nil || !strings.Contains(err.Error(), "denied") {
|
||||||
t.Fatalf("expected denied error, got: %#v", err)
|
t.Fatalf("expected denied error, got: %#v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List keys with access works
|
// List keys with access works
|
||||||
_, err = agent.ListKeys("root")
|
_, err = agent.ListKeys("root", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install without access fails
|
// Install without access fails
|
||||||
_, err = agent.InstallKey(key2, "")
|
_, err = agent.InstallKey(key2, "", 0)
|
||||||
if err == nil || !strings.Contains(err.Error(), "denied") {
|
if err == nil || !strings.Contains(err.Error(), "denied") {
|
||||||
t.Fatalf("expected denied error, got: %#v", err)
|
t.Fatalf("expected denied error, got: %#v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install with access works
|
// Install with access works
|
||||||
_, err = agent.InstallKey(key2, "root")
|
_, err = agent.InstallKey(key2, "root", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use without access fails
|
// Use without access fails
|
||||||
_, err = agent.UseKey(key2, "")
|
_, err = agent.UseKey(key2, "", 0)
|
||||||
if err == nil || !strings.Contains(err.Error(), "denied") {
|
if err == nil || !strings.Contains(err.Error(), "denied") {
|
||||||
t.Fatalf("expected denied error, got: %#v", err)
|
t.Fatalf("expected denied error, got: %#v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use with access works
|
// Use with access works
|
||||||
_, err = agent.UseKey(key2, "root")
|
_, err = agent.UseKey(key2, "root", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove without access fails
|
// Remove without access fails
|
||||||
_, err = agent.RemoveKey(key1, "")
|
_, err = agent.RemoveKey(key1, "", 0)
|
||||||
if err == nil || !strings.Contains(err.Error(), "denied") {
|
if err == nil || !strings.Contains(err.Error(), "denied") {
|
||||||
t.Fatalf("expected denied error, got: %#v", err)
|
t.Fatalf("expected denied error, got: %#v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove with access works
|
// Remove with access works
|
||||||
_, err = agent.RemoveKey(key1, "root")
|
_, err = agent.RemoveKey(key1, "root", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/hashicorp/consul/consul/structs"
|
"github.com/hashicorp/consul/consul/structs"
|
||||||
multierror "github.com/hashicorp/go-multierror"
|
multierror "github.com/hashicorp/go-multierror"
|
||||||
"github.com/hashicorp/raft"
|
"github.com/hashicorp/raft"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OperatorRaftConfiguration is used to inspect the current Raft configuration.
|
// OperatorRaftConfiguration is used to inspect the current Raft configuration.
|
||||||
|
@ -59,8 +60,9 @@ func (s *HTTPServer) OperatorRaftPeer(resp http.ResponseWriter, req *http.Reques
|
||||||
}
|
}
|
||||||
|
|
||||||
type keyringArgs struct {
|
type keyringArgs struct {
|
||||||
Key string
|
Key string
|
||||||
Token string
|
Token string
|
||||||
|
RelayFactor uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// OperatorKeyringEndpoint handles keyring operations (install, list, use, remove)
|
// OperatorKeyringEndpoint handles keyring operations (install, list, use, remove)
|
||||||
|
@ -75,6 +77,23 @@ func (s *HTTPServer) OperatorKeyringEndpoint(resp http.ResponseWriter, req *http
|
||||||
}
|
}
|
||||||
s.parseToken(req, &args.Token)
|
s.parseToken(req, &args.Token)
|
||||||
|
|
||||||
|
// Parse relay factor
|
||||||
|
if relayFactor := req.URL.Query().Get("relay-factor"); relayFactor != "" {
|
||||||
|
n, err := strconv.Atoi(relayFactor)
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeader(400)
|
||||||
|
resp.Write([]byte(fmt.Sprintf("Error parsing relay factor: %v", err)))
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
args.RelayFactor, err = ParseRelayFactor(n)
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeader(400)
|
||||||
|
resp.Write([]byte(fmt.Sprintf("Invalid relay factor: %v", err)))
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Switch on the method
|
// Switch on the method
|
||||||
switch req.Method {
|
switch req.Method {
|
||||||
case "GET":
|
case "GET":
|
||||||
|
@ -93,7 +112,7 @@ func (s *HTTPServer) OperatorKeyringEndpoint(resp http.ResponseWriter, req *http
|
||||||
|
|
||||||
// KeyringInstall is used to install a new gossip encryption key into the cluster
|
// KeyringInstall is used to install a new gossip encryption key into the cluster
|
||||||
func (s *HTTPServer) KeyringInstall(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
|
func (s *HTTPServer) KeyringInstall(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
|
||||||
responses, err := s.agent.InstallKey(args.Key, args.Token)
|
responses, err := s.agent.InstallKey(args.Key, args.Token, args.RelayFactor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -103,7 +122,7 @@ func (s *HTTPServer) KeyringInstall(resp http.ResponseWriter, req *http.Request,
|
||||||
|
|
||||||
// KeyringList is used to list the keys installed in the cluster
|
// KeyringList is used to list the keys installed in the cluster
|
||||||
func (s *HTTPServer) KeyringList(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
|
func (s *HTTPServer) KeyringList(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
|
||||||
responses, err := s.agent.ListKeys(args.Token)
|
responses, err := s.agent.ListKeys(args.Token, args.RelayFactor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -113,7 +132,7 @@ func (s *HTTPServer) KeyringList(resp http.ResponseWriter, req *http.Request, ar
|
||||||
|
|
||||||
// KeyringRemove is used to list the keys installed in the cluster
|
// KeyringRemove is used to list the keys installed in the cluster
|
||||||
func (s *HTTPServer) KeyringRemove(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
|
func (s *HTTPServer) KeyringRemove(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
|
||||||
responses, err := s.agent.RemoveKey(args.Key, args.Token)
|
responses, err := s.agent.RemoveKey(args.Key, args.Token, args.RelayFactor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -123,7 +142,7 @@ func (s *HTTPServer) KeyringRemove(resp http.ResponseWriter, req *http.Request,
|
||||||
|
|
||||||
// KeyringUse is used to change the primary gossip encryption key
|
// KeyringUse is used to change the primary gossip encryption key
|
||||||
func (s *HTTPServer) KeyringUse(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
|
func (s *HTTPServer) KeyringUse(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
|
||||||
responses, err := s.agent.UseKey(args.Key, args.Token)
|
responses, err := s.agent.UseKey(args.Key, args.Token, args.RelayFactor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ func TestOperator_KeyringInstall(t *testing.T) {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
listResponse, err := srv.agent.ListKeys("")
|
listResponse, err := srv.agent.ListKeys("", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -155,13 +155,13 @@ func TestOperator_KeyringRemove(t *testing.T) {
|
||||||
c.EncryptKey = key
|
c.EncryptKey = key
|
||||||
}
|
}
|
||||||
httpTestWithConfig(t, func(srv *HTTPServer) {
|
httpTestWithConfig(t, func(srv *HTTPServer) {
|
||||||
_, err := srv.agent.InstallKey(tempKey, "")
|
_, err := srv.agent.InstallKey(tempKey, "", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the temp key is installed
|
// Make sure the temp key is installed
|
||||||
list, err := srv.agent.ListKeys("")
|
list, err := srv.agent.ListKeys("", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ func TestOperator_KeyringRemove(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the temp key has been removed
|
// Make sure the temp key has been removed
|
||||||
list, err = srv.agent.ListKeys("")
|
list, err = srv.agent.ListKeys("", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ func TestOperator_KeyringUse(t *testing.T) {
|
||||||
c.EncryptKey = oldKey
|
c.EncryptKey = oldKey
|
||||||
}
|
}
|
||||||
httpTestWithConfig(t, func(srv *HTTPServer) {
|
httpTestWithConfig(t, func(srv *HTTPServer) {
|
||||||
if _, err := srv.agent.InstallKey(newKey, ""); err != nil {
|
if _, err := srv.agent.InstallKey(newKey, "", 0); err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,12 +233,12 @@ func TestOperator_KeyringUse(t *testing.T) {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := srv.agent.RemoveKey(oldKey, ""); err != nil {
|
if _, err := srv.agent.RemoveKey(oldKey, "", 0); err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure only the new key remains
|
// Make sure only the new key remains
|
||||||
list, err := srv.agent.ListKeys("")
|
list, err := srv.agent.ListKeys("", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -256,3 +256,32 @@ func TestOperator_KeyringUse(t *testing.T) {
|
||||||
}
|
}
|
||||||
}, configFunc)
|
}, configFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOperator_Keyring_InvalidRelayFactor(t *testing.T) {
|
||||||
|
key := "H3/9gBxcKKRf45CaI2DlRg=="
|
||||||
|
configFunc := func(c *Config) {
|
||||||
|
c.EncryptKey = key
|
||||||
|
}
|
||||||
|
httpTestWithConfig(t, func(srv *HTTPServer) {
|
||||||
|
cases := map[string]string{
|
||||||
|
"999": "Relay factor must be in range",
|
||||||
|
"asdf": "Error parsing relay factor",
|
||||||
|
}
|
||||||
|
for relayFactor, errString := range cases {
|
||||||
|
req, err := http.NewRequest("GET", "/v1/operator/keyring?relay-factor="+relayFactor, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
_, err = srv.OperatorKeyringEndpoint(resp, req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
body := resp.Body.String()
|
||||||
|
if !strings.Contains(body, errString) {
|
||||||
|
t.Fatalf("bad: %v", body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, configFunc)
|
||||||
|
}
|
||||||
|
|
|
@ -106,7 +106,8 @@ type joinResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type keyringRequest struct {
|
type keyringRequest struct {
|
||||||
Key string
|
Key string
|
||||||
|
RelayFactor uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyringEntry struct {
|
type KeyringEntry struct {
|
||||||
|
@ -604,21 +605,21 @@ func (i *AgentRPC) handleKeyring(client *rpcClient, seq uint64, cmd, token strin
|
||||||
var r keyringResponse
|
var r keyringResponse
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if cmd != listKeysCommand {
|
if err = client.dec.Decode(&req); err != nil {
|
||||||
if err = client.dec.Decode(&req); err != nil {
|
return fmt.Errorf("decode failed: %v", err)
|
||||||
return fmt.Errorf("decode failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i.agent.logger.Printf("[INFO] agent: Sending rpc command with relay factor %d", req.RelayFactor)
|
||||||
|
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case listKeysCommand:
|
case listKeysCommand:
|
||||||
queryResp, err = i.agent.ListKeys(token)
|
queryResp, err = i.agent.ListKeys(token, req.RelayFactor)
|
||||||
case installKeyCommand:
|
case installKeyCommand:
|
||||||
queryResp, err = i.agent.InstallKey(req.Key, token)
|
queryResp, err = i.agent.InstallKey(req.Key, token, req.RelayFactor)
|
||||||
case useKeyCommand:
|
case useKeyCommand:
|
||||||
queryResp, err = i.agent.UseKey(req.Key, token)
|
queryResp, err = i.agent.UseKey(req.Key, token, req.RelayFactor)
|
||||||
case removeKeyCommand:
|
case removeKeyCommand:
|
||||||
queryResp, err = i.agent.RemoveKey(req.Key, token)
|
queryResp, err = i.agent.RemoveKey(req.Key, token, req.RelayFactor)
|
||||||
default:
|
default:
|
||||||
respHeader := responseHeader{Seq: seq, Error: unsupportedCommand}
|
respHeader := responseHeader{Seq: seq, Error: unsupportedCommand}
|
||||||
client.Send(&respHeader, nil)
|
client.Send(&respHeader, nil)
|
||||||
|
|
|
@ -194,48 +194,49 @@ func (c *RPCClient) WANMembers() ([]Member, error) {
|
||||||
return resp.Members, err
|
return resp.Members, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RPCClient) ListKeys(token string) (keyringResponse, error) {
|
func (c *RPCClient) ListKeys(token string, relayFactor uint8) (keyringResponse, error) {
|
||||||
header := requestHeader{
|
header := requestHeader{
|
||||||
Command: listKeysCommand,
|
Command: listKeysCommand,
|
||||||
Seq: c.getSeq(),
|
Seq: c.getSeq(),
|
||||||
Token: token,
|
Token: token,
|
||||||
}
|
}
|
||||||
|
req := keyringRequest{RelayFactor: relayFactor}
|
||||||
var resp keyringResponse
|
var resp keyringResponse
|
||||||
err := c.genericRPC(&header, nil, &resp)
|
err := c.genericRPC(&header, req, &resp)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RPCClient) InstallKey(key, token string) (keyringResponse, error) {
|
func (c *RPCClient) InstallKey(key, token string, relayFactor uint8) (keyringResponse, error) {
|
||||||
header := requestHeader{
|
header := requestHeader{
|
||||||
Command: installKeyCommand,
|
Command: installKeyCommand,
|
||||||
Seq: c.getSeq(),
|
Seq: c.getSeq(),
|
||||||
Token: token,
|
Token: token,
|
||||||
}
|
}
|
||||||
req := keyringRequest{key}
|
req := keyringRequest{Key: key, RelayFactor: relayFactor}
|
||||||
var resp keyringResponse
|
var resp keyringResponse
|
||||||
err := c.genericRPC(&header, &req, &resp)
|
err := c.genericRPC(&header, &req, &resp)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RPCClient) UseKey(key, token string) (keyringResponse, error) {
|
func (c *RPCClient) UseKey(key, token string, relayFactor uint8) (keyringResponse, error) {
|
||||||
header := requestHeader{
|
header := requestHeader{
|
||||||
Command: useKeyCommand,
|
Command: useKeyCommand,
|
||||||
Seq: c.getSeq(),
|
Seq: c.getSeq(),
|
||||||
Token: token,
|
Token: token,
|
||||||
}
|
}
|
||||||
req := keyringRequest{key}
|
req := keyringRequest{Key: key, RelayFactor: relayFactor}
|
||||||
var resp keyringResponse
|
var resp keyringResponse
|
||||||
err := c.genericRPC(&header, &req, &resp)
|
err := c.genericRPC(&header, &req, &resp)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RPCClient) RemoveKey(key, token string) (keyringResponse, error) {
|
func (c *RPCClient) RemoveKey(key, token string, relayFactor uint8) (keyringResponse, error) {
|
||||||
header := requestHeader{
|
header := requestHeader{
|
||||||
Command: removeKeyCommand,
|
Command: removeKeyCommand,
|
||||||
Seq: c.getSeq(),
|
Seq: c.getSeq(),
|
||||||
Token: token,
|
Token: token,
|
||||||
}
|
}
|
||||||
req := keyringRequest{key}
|
req := keyringRequest{Key: key, RelayFactor: relayFactor}
|
||||||
var resp keyringResponse
|
var resp keyringResponse
|
||||||
err := c.genericRPC(&header, &req, &resp)
|
err := c.genericRPC(&header, &req, &resp)
|
||||||
return resp, err
|
return resp, err
|
||||||
|
|
|
@ -371,7 +371,7 @@ func TestRPCClientInstallKey(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// install key2
|
// install key2
|
||||||
r, err := p1.client.InstallKey(key2, "")
|
r, err := p1.client.InstallKey(key2, "", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -402,7 +402,7 @@ func TestRPCClientUseKey(t *testing.T) {
|
||||||
defer p1.Close()
|
defer p1.Close()
|
||||||
|
|
||||||
// add a second key to the ring
|
// add a second key to the ring
|
||||||
r, err := p1.client.InstallKey(key2, "")
|
r, err := p1.client.InstallKey(key2, "", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -423,21 +423,21 @@ func TestRPCClientUseKey(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// can't remove key1 yet
|
// can't remove key1 yet
|
||||||
r, err = p1.client.RemoveKey(key1, "")
|
r, err = p1.client.RemoveKey(key1, "", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
keyringError(t, r)
|
keyringError(t, r)
|
||||||
|
|
||||||
// change primary key
|
// change primary key
|
||||||
r, err = p1.client.UseKey(key2, "")
|
r, err = p1.client.UseKey(key2, "", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
keyringSuccess(t, r)
|
keyringSuccess(t, r)
|
||||||
|
|
||||||
// can remove key1 now
|
// can remove key1 now
|
||||||
r, err = p1.client.RemoveKey(key1, "")
|
r, err = p1.client.RemoveKey(key1, "", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -450,7 +450,7 @@ func TestRPCClientKeyOperation_encryptionDisabled(t *testing.T) {
|
||||||
})
|
})
|
||||||
defer p1.Close()
|
defer p1.Close()
|
||||||
|
|
||||||
r, err := p1.client.ListKeys("")
|
r, err := p1.client.ListKeys("", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -458,7 +458,7 @@ func TestRPCClientKeyOperation_encryptionDisabled(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func listKeys(t *testing.T, c *RPCClient) map[string]map[string]int {
|
func listKeys(t *testing.T, c *RPCClient) map[string]map[string]int {
|
||||||
resp, err := c.ListKeys("")
|
resp, err := c.ListKeys("", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ type KeyringCommand struct {
|
||||||
func (c *KeyringCommand) Run(args []string) int {
|
func (c *KeyringCommand) Run(args []string) int {
|
||||||
var installKey, useKey, removeKey, token string
|
var installKey, useKey, removeKey, token string
|
||||||
var listKeys bool
|
var listKeys bool
|
||||||
|
var relay int
|
||||||
|
|
||||||
cmdFlags := flag.NewFlagSet("keys", flag.ContinueOnError)
|
cmdFlags := flag.NewFlagSet("keys", flag.ContinueOnError)
|
||||||
cmdFlags.Usage = func() { c.Ui.Output(c.Help()) }
|
cmdFlags.Usage = func() { c.Ui.Output(c.Help()) }
|
||||||
|
@ -27,6 +28,7 @@ func (c *KeyringCommand) Run(args []string) int {
|
||||||
cmdFlags.StringVar(&removeKey, "remove", "", "remove key")
|
cmdFlags.StringVar(&removeKey, "remove", "", "remove key")
|
||||||
cmdFlags.BoolVar(&listKeys, "list", false, "list keys")
|
cmdFlags.BoolVar(&listKeys, "list", false, "list keys")
|
||||||
cmdFlags.StringVar(&token, "token", "", "acl token")
|
cmdFlags.StringVar(&token, "token", "", "acl token")
|
||||||
|
cmdFlags.IntVar(&relay, "relay-factor", 0, "relay factor")
|
||||||
|
|
||||||
rpcAddr := RPCAddrFlag(cmdFlags)
|
rpcAddr := RPCAddrFlag(cmdFlags)
|
||||||
if err := cmdFlags.Parse(args); err != nil {
|
if err := cmdFlags.Parse(args); err != nil {
|
||||||
|
@ -56,6 +58,13 @@ func (c *KeyringCommand) Run(args []string) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate the relay factor
|
||||||
|
relayFactor, err := agent.ParseRelayFactor(relay)
|
||||||
|
if err != nil {
|
||||||
|
c.Ui.Error(fmt.Sprintf("Error parsing relay factor: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
// All other operations will require a client connection
|
// All other operations will require a client connection
|
||||||
client, err := RPCClient(*rpcAddr)
|
client, err := RPCClient(*rpcAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -66,7 +75,7 @@ func (c *KeyringCommand) Run(args []string) int {
|
||||||
|
|
||||||
if listKeys {
|
if listKeys {
|
||||||
c.Ui.Info("Gathering installed encryption keys...")
|
c.Ui.Info("Gathering installed encryption keys...")
|
||||||
r, err := client.ListKeys(token)
|
r, err := client.ListKeys(token, relayFactor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("error: %s", err))
|
c.Ui.Error(fmt.Sprintf("error: %s", err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -80,7 +89,7 @@ func (c *KeyringCommand) Run(args []string) int {
|
||||||
|
|
||||||
if installKey != "" {
|
if installKey != "" {
|
||||||
c.Ui.Info("Installing new gossip encryption key...")
|
c.Ui.Info("Installing new gossip encryption key...")
|
||||||
r, err := client.InstallKey(installKey, token)
|
r, err := client.InstallKey(installKey, token, relayFactor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("error: %s", err))
|
c.Ui.Error(fmt.Sprintf("error: %s", err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -90,7 +99,7 @@ func (c *KeyringCommand) Run(args []string) int {
|
||||||
|
|
||||||
if useKey != "" {
|
if useKey != "" {
|
||||||
c.Ui.Info("Changing primary gossip encryption key...")
|
c.Ui.Info("Changing primary gossip encryption key...")
|
||||||
r, err := client.UseKey(useKey, token)
|
r, err := client.UseKey(useKey, token, relayFactor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("error: %s", err))
|
c.Ui.Error(fmt.Sprintf("error: %s", err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -100,7 +109,7 @@ func (c *KeyringCommand) Run(args []string) int {
|
||||||
|
|
||||||
if removeKey != "" {
|
if removeKey != "" {
|
||||||
c.Ui.Info("Removing gossip encryption key...")
|
c.Ui.Info("Removing gossip encryption key...")
|
||||||
r, err := client.RemoveKey(removeKey, token)
|
r, err := client.RemoveKey(removeKey, token, relayFactor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("error: %s", err))
|
c.Ui.Error(fmt.Sprintf("error: %s", err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -206,6 +215,11 @@ Options:
|
||||||
not currently the primary key.
|
not currently the primary key.
|
||||||
-token="" ACL token to use during requests. Defaults to that
|
-token="" ACL token to use during requests. Defaults to that
|
||||||
of the agent.
|
of the agent.
|
||||||
|
-relay-factor Added in Consul 0.7.4, setting this to a non-zero
|
||||||
|
value will cause nodes to relay their response to
|
||||||
|
the operation through this many randomly-chosen
|
||||||
|
other nodes in the cluster. The maximum allowed
|
||||||
|
value is 5.
|
||||||
-use=<key> Change the primary encryption key, which is used to
|
-use=<key> Change the primary encryption key, which is used to
|
||||||
encrypt messages. The key must already be installed
|
encrypt messages. The key must already be installed
|
||||||
before this operation can succeed.
|
before this operation can succeed.
|
||||||
|
|
|
@ -89,6 +89,17 @@ func TestKeyringCommandRun_failedConnection(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKeyringCommandRun_invalidRelayFactor(t *testing.T) {
|
||||||
|
ui := new(cli.MockUi)
|
||||||
|
c := &KeyringCommand{Ui: ui}
|
||||||
|
|
||||||
|
args := []string{"-list", "-relay-factor=6"}
|
||||||
|
code := c.Run(args)
|
||||||
|
if code != 1 {
|
||||||
|
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func listKeys(t *testing.T, addr string) string {
|
func listKeys(t *testing.T, addr string) string {
|
||||||
ui := new(cli.MockUi)
|
ui := new(cli.MockUi)
|
||||||
c := &KeyringCommand{Ui: ui}
|
c := &KeyringCommand{Ui: ui}
|
||||||
|
|
|
@ -147,15 +147,16 @@ func (m *Internal) executeKeyringOp(
|
||||||
mgr = m.srv.KeyManagerLAN()
|
mgr = m.srv.KeyManagerLAN()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opts := &serf.KeyRequestOptions{RelayFactor: args.RelayFactor}
|
||||||
switch args.Operation {
|
switch args.Operation {
|
||||||
case structs.KeyringList:
|
case structs.KeyringList:
|
||||||
serfResp, err = mgr.ListKeys()
|
serfResp, err = mgr.ListKeysWithOptions(opts)
|
||||||
case structs.KeyringInstall:
|
case structs.KeyringInstall:
|
||||||
serfResp, err = mgr.InstallKey(args.Key)
|
serfResp, err = mgr.InstallKeyWithOptions(args.Key, opts)
|
||||||
case structs.KeyringUse:
|
case structs.KeyringUse:
|
||||||
serfResp, err = mgr.UseKey(args.Key)
|
serfResp, err = mgr.UseKeyWithOptions(args.Key, opts)
|
||||||
case structs.KeyringRemove:
|
case structs.KeyringRemove:
|
||||||
serfResp, err = mgr.RemoveKey(args.Key)
|
serfResp, err = mgr.RemoveKeyWithOptions(args.Key, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
errStr := ""
|
errStr := ""
|
||||||
|
|
|
@ -1000,10 +1000,11 @@ const (
|
||||||
// KeyringRequest encapsulates a request to modify an encryption keyring.
|
// KeyringRequest encapsulates a request to modify an encryption keyring.
|
||||||
// It can be used for install, remove, or use key type operations.
|
// It can be used for install, remove, or use key type operations.
|
||||||
type KeyringRequest struct {
|
type KeyringRequest struct {
|
||||||
Operation KeyringOp
|
Operation KeyringOp
|
||||||
Key string
|
Key string
|
||||||
Datacenter string
|
Datacenter string
|
||||||
Forwarded bool
|
Forwarded bool
|
||||||
|
RelayFactor uint8
|
||||||
QueryOptions
|
QueryOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,9 @@ Available in Consul 0.7.2 and later, the keyring endpoint supports the
|
||||||
This endpoint supports the use of ACL tokens using either the `X-CONSUL-TOKEN`
|
This endpoint supports the use of ACL tokens using either the `X-CONSUL-TOKEN`
|
||||||
header or the `?token=` query parameter.
|
header or the `?token=` query parameter.
|
||||||
|
|
||||||
|
Added in Consul 0.7.4, this endpoint supports the `?relay-factor=` query parameter.
|
||||||
|
See the [Keyring Command](/docs/commands/keyring.html#_relay_factor) for more details.
|
||||||
|
|
||||||
#### GET Method
|
#### GET Method
|
||||||
|
|
||||||
Using the `GET` method, this endpoint will list the gossip encryption keys
|
Using the `GET` method, this endpoint will list the gossip encryption keys
|
||||||
|
|
|
@ -48,6 +48,10 @@ The list of available flags are:
|
||||||
|
|
||||||
* `-token=""` - ACL token to use during requests. Defaults to that of the agent.
|
* `-token=""` - ACL token to use during requests. Defaults to that of the agent.
|
||||||
|
|
||||||
|
* `-relay-factor` - Added in Consul 0.7.4, setting this to a non-zero value will
|
||||||
|
cause nodes to relay their response to the operation through this many
|
||||||
|
randomly-chosen other nodes in the cluster. The maximum allowed value is 5.
|
||||||
|
|
||||||
* `-rpc-addr` - Address to the RPC server of the agent you want to contact
|
* `-rpc-addr` - Address to the RPC server of the agent you want to contact
|
||||||
to send this command. If this isn't specified, the command will contact
|
to send this command. If this isn't specified, the command will contact
|
||||||
"127.0.0.1:8400" which is the default RPC address of a Consul agent.
|
"127.0.0.1:8400" which is the default RPC address of a Consul agent.
|
||||||
|
|
Loading…
Reference in New Issue