github.com/hernad/nomad@v1.6.112/nomad/structs/keyring.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package structs 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/hernad/nomad/helper" 11 "github.com/hernad/nomad/helper/crypto" 12 "github.com/hernad/nomad/helper/uuid" 13 ) 14 15 // RootKey is used to encrypt and decrypt variables. It is never stored in raft. 16 type RootKey struct { 17 Meta *RootKeyMeta 18 Key []byte // serialized to keystore as base64 blob 19 } 20 21 // NewRootKey returns a new root key and its metadata. 22 func NewRootKey(algorithm EncryptionAlgorithm) (*RootKey, error) { 23 meta := NewRootKeyMeta() 24 meta.Algorithm = algorithm 25 26 rootKey := &RootKey{ 27 Meta: meta, 28 } 29 30 switch algorithm { 31 case EncryptionAlgorithmAES256GCM: 32 key, err := crypto.Bytes(32) 33 if err != nil { 34 return nil, fmt.Errorf("failed to generate key: %v", err) 35 } 36 rootKey.Key = key 37 } 38 39 return rootKey, nil 40 } 41 42 // RootKeyMeta is the metadata used to refer to a RootKey. It is 43 // stored in raft. 44 type RootKeyMeta struct { 45 KeyID string // UUID 46 Algorithm EncryptionAlgorithm 47 CreateTime int64 48 CreateIndex uint64 49 ModifyIndex uint64 50 State RootKeyState 51 } 52 53 // RootKeyState enum describes the lifecycle of a root key. 54 type RootKeyState string 55 56 const ( 57 RootKeyStateInactive RootKeyState = "inactive" 58 RootKeyStateActive = "active" 59 RootKeyStateRekeying = "rekeying" 60 61 // RootKeyStateDeprecated is, itself, deprecated and is no longer in 62 // use. For backwards compatibility, any existing keys with this state will 63 // be treated as RootKeyStateInactive 64 RootKeyStateDeprecated = "deprecated" 65 ) 66 67 // NewRootKeyMeta returns a new RootKeyMeta with default values 68 func NewRootKeyMeta() *RootKeyMeta { 69 now := time.Now().UTC().UnixNano() 70 return &RootKeyMeta{ 71 KeyID: uuid.Generate(), 72 Algorithm: EncryptionAlgorithmAES256GCM, 73 State: RootKeyStateInactive, 74 CreateTime: now, 75 } 76 } 77 78 // RootKeyMetaStub is for serializing root key metadata to the 79 // keystore, not for the List API. It excludes frequently-changing 80 // fields such as ModifyIndex so we don't have to sync them to the 81 // on-disk keystore when the fields are already in raft. 82 type RootKeyMetaStub struct { 83 KeyID string 84 Algorithm EncryptionAlgorithm 85 CreateTime int64 86 State RootKeyState 87 } 88 89 // Active indicates his key is the one currently being used for 90 // crypto operations (at most one key can be Active) 91 func (rkm *RootKeyMeta) Active() bool { 92 return rkm.State == RootKeyStateActive 93 } 94 95 func (rkm *RootKeyMeta) SetActive() { 96 rkm.State = RootKeyStateActive 97 } 98 99 // Rekeying indicates that variables encrypted with this key should be 100 // rekeyed 101 func (rkm *RootKeyMeta) Rekeying() bool { 102 return rkm.State == RootKeyStateRekeying 103 } 104 105 func (rkm *RootKeyMeta) SetRekeying() { 106 rkm.State = RootKeyStateRekeying 107 } 108 109 func (rkm *RootKeyMeta) SetInactive() { 110 rkm.State = RootKeyStateInactive 111 } 112 113 // Inactive indicates that this key is no longer being used to encrypt new 114 // variables or workload identities. 115 func (rkm *RootKeyMeta) Inactive() bool { 116 return rkm.State == RootKeyStateInactive || rkm.State == RootKeyStateDeprecated 117 } 118 119 func (rkm *RootKeyMeta) Stub() *RootKeyMetaStub { 120 if rkm == nil { 121 return nil 122 } 123 return &RootKeyMetaStub{ 124 KeyID: rkm.KeyID, 125 Algorithm: rkm.Algorithm, 126 CreateTime: rkm.CreateTime, 127 State: rkm.State, 128 } 129 130 } 131 func (rkm *RootKeyMeta) Copy() *RootKeyMeta { 132 if rkm == nil { 133 return nil 134 } 135 out := *rkm 136 return &out 137 } 138 139 func (rkm *RootKeyMeta) Validate() error { 140 if rkm == nil { 141 return fmt.Errorf("root key metadata is required") 142 } 143 if rkm.KeyID == "" || !helper.IsUUID(rkm.KeyID) { 144 return fmt.Errorf("root key UUID is required") 145 } 146 if rkm.Algorithm == "" { 147 return fmt.Errorf("root key algorithm is required") 148 } 149 switch rkm.State { 150 case RootKeyStateInactive, RootKeyStateActive, 151 RootKeyStateRekeying, RootKeyStateDeprecated: 152 default: 153 return fmt.Errorf("root key state %q is invalid", rkm.State) 154 } 155 return nil 156 } 157 158 // KeyEncryptionKeyWrapper is the struct that gets serialized for the on-disk 159 // KMS wrapper. This struct includes the server-specific key-wrapping key and 160 // should never be sent over RPC. 161 type KeyEncryptionKeyWrapper struct { 162 Meta *RootKeyMeta 163 EncryptedDataEncryptionKey []byte `json:"DEK"` 164 KeyEncryptionKey []byte `json:"KEK"` 165 } 166 167 // EncryptionAlgorithm chooses which algorithm is used for 168 // encrypting / decrypting entries with this key 169 type EncryptionAlgorithm string 170 171 const ( 172 EncryptionAlgorithmAES256GCM EncryptionAlgorithm = "aes256-gcm" 173 ) 174 175 // KeyringRotateRootKeyRequest is the argument to the Keyring.Rotate RPC 176 type KeyringRotateRootKeyRequest struct { 177 Algorithm EncryptionAlgorithm 178 Full bool 179 WriteRequest 180 } 181 182 // KeyringRotateRootKeyResponse returns the full key metadata 183 type KeyringRotateRootKeyResponse struct { 184 Key *RootKeyMeta 185 WriteMeta 186 } 187 188 // KeyringListRootKeyMetaRequest is the argument to the Keyring.List RPC 189 type KeyringListRootKeyMetaRequest struct { 190 QueryOptions 191 } 192 193 // KeyringListRootKeyMetaRequest is the response value of the List RPC 194 type KeyringListRootKeyMetaResponse struct { 195 Keys []*RootKeyMeta 196 QueryMeta 197 } 198 199 // KeyringUpdateRootKeyRequest is used internally for key replication 200 // only and for keyring restores. The RootKeyMeta will be extracted 201 // for applying to the FSM with the KeyringUpdateRootKeyMetaRequest 202 // (see below) 203 type KeyringUpdateRootKeyRequest struct { 204 RootKey *RootKey 205 Rekey bool 206 WriteRequest 207 } 208 209 type KeyringUpdateRootKeyResponse struct { 210 WriteMeta 211 } 212 213 // KeyringGetRootKeyRequest is used internally for key replication 214 // only and for keyring restores. 215 type KeyringGetRootKeyRequest struct { 216 KeyID string 217 QueryOptions 218 } 219 220 type KeyringGetRootKeyResponse struct { 221 Key *RootKey 222 QueryMeta 223 } 224 225 // KeyringUpdateRootKeyMetaRequest is used internally for key 226 // replication so that we have a request wrapper for writing the 227 // metadata to the FSM without including the key material 228 type KeyringUpdateRootKeyMetaRequest struct { 229 RootKeyMeta *RootKeyMeta 230 Rekey bool 231 WriteRequest 232 } 233 234 type KeyringUpdateRootKeyMetaResponse struct { 235 WriteMeta 236 } 237 238 type KeyringDeleteRootKeyRequest struct { 239 KeyID string 240 WriteRequest 241 } 242 243 type KeyringDeleteRootKeyResponse struct { 244 WriteMeta 245 }