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