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  }