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  }