github.com/outbrain/consul@v1.4.5/agent/keyring.go (about) 1 package agent 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 11 "github.com/hashicorp/consul/agent/consul" 12 "github.com/hashicorp/consul/agent/structs" 13 "github.com/hashicorp/memberlist" 14 "github.com/hashicorp/serf/serf" 15 ) 16 17 const ( 18 SerfLANKeyring = "serf/local.keyring" 19 SerfWANKeyring = "serf/remote.keyring" 20 ) 21 22 // initKeyring will create a keyring file at a given path. 23 func initKeyring(path, key string) error { 24 var keys []string 25 26 if keyBytes, err := base64.StdEncoding.DecodeString(key); err != nil { 27 return fmt.Errorf("Invalid key: %s", err) 28 } else if err := memberlist.ValidateKey(keyBytes); err != nil { 29 return fmt.Errorf("Invalid key: %s", err) 30 } 31 32 // Just exit if the file already exists. 33 if _, err := os.Stat(path); err == nil { 34 return nil 35 } 36 37 keys = append(keys, key) 38 keyringBytes, err := json.Marshal(keys) 39 if err != nil { 40 return err 41 } 42 43 if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { 44 return err 45 } 46 47 fh, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) 48 if err != nil { 49 return err 50 } 51 defer fh.Close() 52 53 if _, err := fh.Write(keyringBytes); err != nil { 54 os.Remove(path) 55 return err 56 } 57 58 return nil 59 } 60 61 // loadKeyringFile will load a gossip encryption keyring out of a file. The file 62 // must be in JSON format and contain a list of encryption key strings. 63 func loadKeyringFile(c *serf.Config) error { 64 if c.KeyringFile == "" { 65 return nil 66 } 67 68 if _, err := os.Stat(c.KeyringFile); err != nil { 69 return err 70 } 71 72 keyringData, err := ioutil.ReadFile(c.KeyringFile) 73 if err != nil { 74 return err 75 } 76 77 keys := make([]string, 0) 78 if err := json.Unmarshal(keyringData, &keys); err != nil { 79 return err 80 } 81 82 return loadKeyring(c, keys) 83 } 84 85 // loadKeyring takes a list of base64-encoded strings and installs them in the 86 // given Serf's keyring. 87 func loadKeyring(c *serf.Config, keys []string) error { 88 keysDecoded := make([][]byte, len(keys)) 89 for i, key := range keys { 90 keyBytes, err := base64.StdEncoding.DecodeString(key) 91 if err != nil { 92 return err 93 } 94 keysDecoded[i] = keyBytes 95 } 96 97 if len(keysDecoded) == 0 { 98 return fmt.Errorf("no keys present in keyring: %s", c.KeyringFile) 99 } 100 101 keyring, err := memberlist.NewKeyring(keysDecoded, keysDecoded[0]) 102 if err != nil { 103 return err 104 } 105 106 c.MemberlistConfig.Keyring = keyring 107 return nil 108 } 109 110 // keyringProcess is used to abstract away the semantic similarities in 111 // performing various operations on the encryption keyring. 112 func (a *Agent) keyringProcess(args *structs.KeyringRequest) (*structs.KeyringResponses, error) { 113 var reply structs.KeyringResponses 114 115 if _, ok := a.delegate.(*consul.Server); !ok { 116 return nil, fmt.Errorf("keyring operations must run against a server node") 117 } 118 if err := a.RPC("Internal.KeyringOperation", args, &reply); err != nil { 119 return &reply, err 120 } 121 122 return &reply, nil 123 } 124 125 // ParseRelayFactor validates and converts the given relay factor to uint8 126 func ParseRelayFactor(n int) (uint8, error) { 127 if n < 0 || n > 5 { 128 return 0, fmt.Errorf("Relay factor must be in range: [0, 5]") 129 } 130 return uint8(n), nil 131 } 132 133 // ListKeys lists out all keys installed on the collective Consul cluster. This 134 // includes both servers and clients in all DC's. 135 func (a *Agent) ListKeys(token string, relayFactor uint8) (*structs.KeyringResponses, error) { 136 args := structs.KeyringRequest{Operation: structs.KeyringList} 137 parseKeyringRequest(&args, token, relayFactor) 138 return a.keyringProcess(&args) 139 } 140 141 // InstallKey installs a new gossip encryption key 142 func (a *Agent) InstallKey(key, token string, relayFactor uint8) (*structs.KeyringResponses, error) { 143 args := structs.KeyringRequest{Key: key, Operation: structs.KeyringInstall} 144 parseKeyringRequest(&args, token, relayFactor) 145 return a.keyringProcess(&args) 146 } 147 148 // UseKey changes the primary encryption key used to encrypt messages 149 func (a *Agent) UseKey(key, token string, relayFactor uint8) (*structs.KeyringResponses, error) { 150 args := structs.KeyringRequest{Key: key, Operation: structs.KeyringUse} 151 parseKeyringRequest(&args, token, relayFactor) 152 return a.keyringProcess(&args) 153 } 154 155 // RemoveKey will remove a gossip encryption key from the keyring 156 func (a *Agent) RemoveKey(key, token string, relayFactor uint8) (*structs.KeyringResponses, error) { 157 args := structs.KeyringRequest{Key: key, Operation: structs.KeyringRemove} 158 parseKeyringRequest(&args, token, relayFactor) 159 return a.keyringProcess(&args) 160 } 161 162 func parseKeyringRequest(req *structs.KeyringRequest, token string, relayFactor uint8) { 163 req.Token = token 164 req.RelayFactor = relayFactor 165 }