Skip to content

Commit 56df5fe

Browse files
authored
kms: add support for multiple HSMs (#32)
This commit adds support for adding, removing and listing HSMs. Now, a KMS cluster can protect its on-disk state with multiple HSMs. This commit adds functions for managing them. Signed-off-by: Andreas Auernhammer <github@aead.dev>
1 parent 240efef commit 56df5fe

File tree

8 files changed

+796
-390
lines changed

8 files changed

+796
-390
lines changed

kms/client.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,28 @@ func (c *Client) EditCluster(ctx context.Context, req *EditClusterRequest) error
615615
return resp.Body.Close()
616616
}
617617

618+
// ResealCluster re-seals the cluster's on-disk state with the active HSMs.
619+
// It returns an error if an active HSM fails to re-seal the cluster's root
620+
// encryption key. For example, when the HSM is currently not available.
621+
//
622+
// It requires SysAdmin privileges.
623+
//
624+
// The returned error is of type *HostError.
625+
func (c *Client) ResealCluster(ctx context.Context, req *ResealClusterRequest) error {
626+
body, err := cmds.Encode(nil, cmds.ClusterReseal, req)
627+
if err != nil {
628+
return err
629+
}
630+
631+
resp, err := c.Send(ctx, &Request{
632+
Body: body,
633+
})
634+
if err != nil {
635+
return err
636+
}
637+
return resp.Body.Close()
638+
}
639+
618640
// AddNode adds the KMS server at req.Host to the current KMS cluster.
619641
// It returns an error if the server is already part of the cluster.
620642
//
@@ -851,6 +873,53 @@ func (c *Client) Logs(ctx context.Context, req *LogRequest) (*LogResponse, error
851873
}, nil
852874
}
853875

876+
// AddHSM seals the cluster's on-disk state with the HSM referenced by req.Name.
877+
//
878+
// The cluster must already be configured with the HSM. Hence, AddHSM can only
879+
// add HSMs that have been removed using RemoveHSM.
880+
//
881+
// It requires SysAdmin privileges.
882+
//
883+
// The returned error is of type *HostError.
884+
func (c *Client) AddHSM(ctx context.Context, req *AddHSMRequest) error {
885+
body, err := cmds.Encode(nil, cmds.ClusterAddHSM, req)
886+
if err != nil {
887+
return err
888+
}
889+
890+
resp, err := c.Send(ctx, &Request{
891+
Body: body,
892+
})
893+
if err != nil {
894+
return err
895+
}
896+
return resp.Body.Close()
897+
}
898+
899+
// RemoveHSM removes any sealed root encryption key associated with the HSM
900+
// referenced by req.Name. It does not remove the HSM configuration from the
901+
// cluster. Once removed, the specified HSM can no longer be used to unseal
902+
// the on-disk state. However, the HSM can added again via AddHSM as long as
903+
// the HSM configuration is present on the cluster.
904+
//
905+
// It requires SysAdmin privileges.
906+
//
907+
// The returned error is of type *HostError.
908+
func (c *Client) RemoveHSM(ctx context.Context, req *RemoveHSMRequest) error {
909+
body, err := cmds.Encode(nil, cmds.ClusterRemoveHSM, req)
910+
if err != nil {
911+
return err
912+
}
913+
914+
resp, err := c.Send(ctx, &Request{
915+
Body: body,
916+
})
917+
if err != nil {
918+
return err
919+
}
920+
return resp.Body.Close()
921+
}
922+
854923
// CreateEnclave creates a new enclave with the name req.Name.
855924
//
856925
// It returns ErrEnclaveExists if such an enclave already exists

kms/cmds/command.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ const (
1515
ClusterRemoveNode Command = 2
1616
ClusterStatus Command = 3
1717
ClusterEdit Command = 4
18+
ClusterAddHSM Command = 5
19+
ClusterRemoveHSM Command = 6
20+
ClusterReseal Command = 7
1821

1922
EnclaveCreate Command = 101
2023
EnclaveDelete Command = 102
@@ -45,6 +48,7 @@ const (
4548
IdentityList Command = 404
4649
)
4750

51+
// Parse parses s as a string representation of a Command.
4852
func Parse(s string) (Command, error) {
4953
c, ok := textCmds[strings.ToUpper(s)]
5054
if !ok {
@@ -66,6 +70,16 @@ func (c Command) IsWrite() bool {
6670
return ok
6771
}
6872

73+
// IsCluster reports whether c operates on a cluster-level
74+
// instead of within a specific enclave.
75+
//
76+
// Cluster-level commands usually require SysAdmin privileges
77+
// and cannot be performed by enclave admins or regular users.
78+
func (c Command) IsCluster() bool {
79+
_, ok := isCluster[c]
80+
return ok
81+
}
82+
6983
func (c Command) String() string {
7084
s, ok := cmdTexts[c]
7185
if !ok {
@@ -104,6 +118,9 @@ var isWrite = map[Command]struct{}{ // Commands that change state on a KMS serve
104118
ClusterAddNode: {},
105119
ClusterRemoveNode: {},
106120
ClusterEdit: {},
121+
ClusterAddHSM: {},
122+
ClusterRemoveHSM: {},
123+
ClusterReseal: {},
107124

108125
EnclaveCreate: {},
109126
EnclaveDelete: {},
@@ -120,11 +137,29 @@ var isWrite = map[Command]struct{}{ // Commands that change state on a KMS serve
120137
IdentityDelete: {},
121138
}
122139

140+
var isCluster = map[Command]struct{}{ // Commands that operate on a cluster-level and require sysadmin privileges
141+
ClusterAddNode: {},
142+
ClusterRemoveNode: {},
143+
ClusterStatus: {},
144+
ClusterEdit: {},
145+
ClusterAddHSM: {},
146+
ClusterRemoveHSM: {},
147+
ClusterReseal: {},
148+
149+
EnclaveCreate: {},
150+
EnclaveDelete: {},
151+
EnclaveStatus: {},
152+
EnclaveList: {},
153+
}
154+
123155
var cmdTexts = map[Command]string{
124156
ClusterAddNode: "CLUSTER:ADDNODE",
125157
ClusterRemoveNode: "CLUSTER:REMOVENODE",
126158
ClusterStatus: "CLUSTER:STATUS",
127159
ClusterEdit: "CLUSTER:EDIT",
160+
ClusterAddHSM: "CLUSTER:ADDHSM",
161+
ClusterRemoveHSM: "CLUSTER:REMOVEHSM",
162+
ClusterReseal: "CLUSTER:RESEAL",
128163

129164
EnclaveCreate: "ENCLAVE:CREATE",
130165
EnclaveDelete: "ENCLAVE:DELETE",
@@ -159,6 +194,9 @@ var textCmds = map[string]Command{
159194
"CLUSTER:REMOVENODE": ClusterRemoveNode,
160195
"CLUSTER:STATUS": ClusterStatus,
161196
"CLUSTER:EDIT": ClusterEdit,
197+
"CLUSTER:ADDHSM": ClusterAddHSM,
198+
"CLUSTER:REMOVEHSM": ClusterRemoveHSM,
199+
"CLUSTER:RESEAL": ClusterReseal,
162200

163201
"ENCLAVE:CREATE": EnclaveCreate,
164202
"ENCLAVE:DELETE": EnclaveDelete,

0 commit comments

Comments
 (0)