Skip to content

Commit 8d8398e

Browse files
InverseIntegralMarcosDY
authored andcommitted
Make key names unique by adding a UUID (spiffe#5058)
Signed-off-by: Matteo Kamm <[email protected]>
1 parent 67924a4 commit 8d8398e

File tree

4 files changed

+77
-31
lines changed

4 files changed

+77
-31
lines changed

Diff for: pkg/server/plugin/keymanager/hashicorpvault/hashicorp_vault.go

+34-8
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ func builtin(p *Plugin) catalog.BuiltIn {
3636
}
3737

3838
type keyEntry struct {
39+
KeyName string
3940
PublicKey *keymanagerv1.PublicKey
4041
}
4142

@@ -123,10 +124,11 @@ type Plugin struct {
123124
keymanagerv1.UnsafeKeyManagerServer
124125
configv1.UnsafeConfigServer
125126

126-
logger hclog.Logger
127-
serverID string
128-
mu sync.RWMutex
129-
entries map[string]keyEntry
127+
logger hclog.Logger
128+
serverID string
129+
mu sync.RWMutex
130+
entries map[string]keyEntry
131+
entriesMtx sync.RWMutex
130132

131133
authMethod AuthMethod
132134
cc *ClientConfig
@@ -316,7 +318,7 @@ func (p *Plugin) GenerateKey(ctx context.Context, req *keymanagerv1.GenerateKeyR
316318
return nil, err
317319
}
318320

319-
p.entries[spireKeyID] = *newKeyEntry
321+
p.setKeyEntry(spireKeyID, *newKeyEntry)
320322

321323
return &keymanagerv1.GenerateKeyResponse{
322324
PublicKey: newKeyEntry.PublicKey,
@@ -351,7 +353,7 @@ func (p *Plugin) SignData(ctx context.Context, req *keymanagerv1.SignDataRequest
351353
}
352354
}
353355

354-
signature, err := p.vc.SignData(ctx, req.KeyId, req.Data, hashAlgo, signingAlgo)
356+
signature, err := p.vc.SignData(ctx, keyEntry.KeyName, req.Data, hashAlgo, signingAlgo)
355357
if err != nil {
356358
return nil, err
357359
}
@@ -451,12 +453,17 @@ func (p *Plugin) createKey(ctx context.Context, spireKeyID string, keyType keyma
451453
return nil, err
452454
}
453455

454-
err = p.vc.CreateKey(ctx, spireKeyID, *kt)
456+
keyName, err := p.generateKeyName(spireKeyID)
455457
if err != nil {
456458
return nil, err
457459
}
458460

459-
return p.vc.getKeyEntry(ctx, spireKeyID)
461+
err = p.vc.CreateKey(ctx, keyName, *kt)
462+
if err != nil {
463+
return nil, err
464+
}
465+
466+
return p.vc.getKeyEntry(ctx, keyName)
460467
}
461468

462469
func convertToTransitKeyType(keyType keymanagerv1.KeyType) (*TransitKeyType, error) {
@@ -502,6 +509,8 @@ func makeFingerprint(pkixData []byte) string {
502509

503510
func (p *Plugin) setCache(keyEntries []*keyEntry) {
504511
// clean previous cache
512+
p.entriesMtx.Lock()
513+
defer p.entriesMtx.Unlock()
505514
p.entries = make(map[string]keyEntry)
506515

507516
// add results to cache
@@ -511,6 +520,23 @@ func (p *Plugin) setCache(keyEntries []*keyEntry) {
511520
}
512521
}
513522

523+
// setKeyEntry adds the entry to the cache that matches the provided SPIRE Key ID
524+
func (p *Plugin) setKeyEntry(keyID string, ke keyEntry) {
525+
p.entriesMtx.Lock()
526+
defer p.entriesMtx.Unlock()
527+
528+
p.entries[keyID] = ke
529+
}
530+
531+
// getKeyEntry gets the entry from the cache that matches the provided SPIRE Key ID
532+
func (p *Plugin) getKeyEntry(keyID string) (ke keyEntry, ok bool) {
533+
p.entriesMtx.RLock()
534+
defer p.entriesMtx.RUnlock()
535+
536+
ke, ok = p.entries[keyID]
537+
return ke, ok
538+
}
539+
514540
// generateKeyName returns a new identifier to be used as a key name.
515541
// The returned name has the form: <UUID>-<SPIRE-KEY-ID>
516542
// where UUID is a new randomly generated UUID and SPIRE-KEY-ID is provided

Diff for: pkg/server/plugin/keymanager/hashicorpvault/vault_client.go

+35-15
Original file line numberDiff line numberDiff line change
@@ -375,13 +375,13 @@ const (
375375

376376
// CreateKey creates a new key in the specified transit secret engine
377377
// See: https://developer.hashicorp.com/vault/api-docs/secret/transit#create-key
378-
func (c *Client) CreateKey(ctx context.Context, spireKeyID string, keyType TransitKeyType) error {
378+
func (c *Client) CreateKey(ctx context.Context, keyName string, keyType TransitKeyType) error {
379379
arguments := map[string]interface{}{
380380
"type": keyType,
381381
"exportable": "false", // SPIRE keys are never exportable
382382
}
383383

384-
_, err := c.vaultClient.Logical().WriteWithContext(ctx, fmt.Sprintf("/%s/keys/%s", c.clientParams.TransitEnginePath, spireKeyID), arguments)
384+
_, err := c.vaultClient.Logical().WriteWithContext(ctx, fmt.Sprintf("/%s/keys/%s", c.clientParams.TransitEnginePath, keyName), arguments)
385385
if err != nil {
386386
return status.Errorf(codes.Internal, "failed to create transit engine key: %v", err)
387387
}
@@ -391,7 +391,7 @@ func (c *Client) CreateKey(ctx context.Context, spireKeyID string, keyType Trans
391391

392392
// SignData signs the data using the transit engine key with the provided spire key id.
393393
// See: https://developer.hashicorp.com/vault/api-docs/secret/transit#sign-data
394-
func (c *Client) SignData(ctx context.Context, spireKeyID string, data []byte, hashAlgo TransitHashAlgorithm, signatureAlgo TransitSignatureAlgorithm) ([]byte, error) {
394+
func (c *Client) SignData(ctx context.Context, keyName string, data []byte, hashAlgo TransitHashAlgorithm, signatureAlgo TransitSignatureAlgorithm) ([]byte, error) {
395395
encodedData := base64.StdEncoding.EncodeToString(data)
396396

397397
body := map[string]interface{}{
@@ -401,7 +401,7 @@ func (c *Client) SignData(ctx context.Context, spireKeyID string, data []byte, h
401401
"prehashed": "true",
402402
}
403403

404-
sigResp, err := c.vaultClient.Logical().WriteWithContext(ctx, fmt.Sprintf("/%s/sign/%s/%s", c.clientParams.TransitEnginePath, spireKeyID, hashAlgo), body)
404+
sigResp, err := c.vaultClient.Logical().WriteWithContext(ctx, fmt.Sprintf("/%s/sign/%s/%s", c.clientParams.TransitEnginePath, keyName, hashAlgo), body)
405405
if err != nil {
406406
return nil, status.Errorf(codes.Internal, "transit engine sign call failed: %v", err)
407407
}
@@ -449,18 +449,18 @@ func (c *Client) GetKeys(ctx context.Context) ([]*keyEntry, error) {
449449
return nil, status.Errorf(codes.Internal, "transit engine list keys call was successful but keys are missing")
450450
}
451451

452-
keyIds, ok := keys.([]interface{})
452+
keyNames, ok := keys.([]interface{})
453453
if !ok {
454-
return nil, status.Errorf(codes.Internal, "expected keys data type %T but got %T", keyIds, keys)
454+
return nil, status.Errorf(codes.Internal, "expected keys data type %T but got %T", keyNames, keys)
455455
}
456456

457-
for _, keyId := range keyIds {
458-
keyIdStr, ok := keyId.(string)
457+
for _, keyName := range keyNames {
458+
keyNameStr, ok := keyName.(string)
459459
if !ok {
460-
return nil, status.Errorf(codes.Internal, "expected key id data type %T but got %T", keyIdStr, keyId)
460+
return nil, status.Errorf(codes.Internal, "expected key id data type %T but got %T", keyNameStr, keyName)
461461
}
462462

463-
keyEntry, err := c.getKeyEntry(ctx, keyIdStr)
463+
keyEntry, err := c.getKeyEntry(ctx, keyNameStr)
464464
if err != nil {
465465
return nil, err
466466
}
@@ -471,9 +471,14 @@ func (c *Client) GetKeys(ctx context.Context) ([]*keyEntry, error) {
471471
return keyEntries, nil
472472
}
473473

474-
// getKeyEntry gets the transit engine key with the specified spire key id and converts it into a key entry.
475-
func (c *Client) getKeyEntry(ctx context.Context, spireKeyID string) (*keyEntry, error) {
476-
keyData, err := c.getKey(ctx, spireKeyID)
474+
// getKeyEntry gets the transit engine key with the specified key name and converts it into a key entry.
475+
func (c *Client) getKeyEntry(ctx context.Context, keyName string) (*keyEntry, error) {
476+
spireKeyID, ok := spireKeyIDFromKeyName(keyName)
477+
if !ok {
478+
return nil, status.Errorf(codes.Internal, "unable to get SPIRE key ID from key %s", keyName)
479+
}
480+
481+
keyData, err := c.getKey(ctx, keyName)
477482
if err != nil {
478483
return nil, err
479484
}
@@ -519,6 +524,7 @@ func (c *Client) getKeyEntry(ctx context.Context, spireKeyID string) (*keyEntry,
519524
}
520525

521526
return &keyEntry{
527+
KeyName: keyName,
522528
PublicKey: &keymanagerv1.PublicKey{
523529
Id: spireKeyID,
524530
Type: keyType,
@@ -530,8 +536,8 @@ func (c *Client) getKeyEntry(ctx context.Context, spireKeyID string) (*keyEntry,
530536

531537
// getKey returns a specific key from the transit engine.
532538
// See: https://developer.hashicorp.com/vault/api-docs/secret/transit#read-key
533-
func (c *Client) getKey(ctx context.Context, spireKeyID string) (map[string]interface{}, error) {
534-
res, err := c.vaultClient.Logical().ReadWithContext(ctx, fmt.Sprintf("/%s/keys/%s", c.clientParams.TransitEnginePath, spireKeyID))
539+
func (c *Client) getKey(ctx context.Context, keyName string) (map[string]interface{}, error) {
540+
res, err := c.vaultClient.Logical().ReadWithContext(ctx, fmt.Sprintf("/%s/keys/%s", c.clientParams.TransitEnginePath, keyName))
535541
if err != nil {
536542
return nil, status.Errorf(codes.Internal, "failed to get transit engine key: %v", err)
537543
}
@@ -558,3 +564,17 @@ func (c *Client) getKey(ctx context.Context, spireKeyID string) (map[string]inte
558564

559565
return currentKeyMap, nil
560566
}
567+
568+
// spireKeyIDFromKeyName parses a Key Vault key name to get the
569+
// SPIRE Key ID. This Key ID is used in the Server KeyManager interface.
570+
func spireKeyIDFromKeyName(keyName string) (string, bool) {
571+
// A key name would have the format <UUID>-<SPIRE-KEY-ID>.
572+
// first we find the position where the SPIRE Key ID starts.
573+
spireKeyIDIndex := 37 // 36 is the UUID length plus one '-' separator
574+
if spireKeyIDIndex >= len(keyName) {
575+
// The index is out of range.
576+
return "", false
577+
}
578+
spireKeyID := keyName[spireKeyIDIndex:]
579+
return spireKeyID, true
580+
}

Diff for: pkg/server/plugin/keymanager/hashicorpvault/vault_client_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ func TestGetKeyEntry(t *testing.T) {
913913
client, err := cc.NewAuthenticatedClient(CERT, renewCh)
914914
require.NoError(t, err)
915915

916-
resp, err := client.getKeyEntry(context.Background(), "x509-CA-A")
916+
resp, err := client.getKeyEntry(context.Background(), "ab748227-3a10-40cc-87fd-2a5321aa638d-x509-CA-A")
917917
require.NoError(t, err)
918918

919919
block, _ := pem.Decode([]byte("-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEV57LFbIQZzyZ2YcKZfB9mGWkUhJv\niRzIZOqV4wRHoUOZjMuhBMR2WviEsy65TYpcBjreAc6pbneiyhlTwPvgmw==\n-----END PUBLIC KEY-----\n"))
@@ -951,7 +951,7 @@ func TestGetKeyEntryErrorFromEndpoint(t *testing.T) {
951951
client, err := cc.NewAuthenticatedClient(CERT, renewCh)
952952
require.NoError(t, err)
953953

954-
resp, err := client.getKeyEntry(context.Background(), "x509-CA-A")
954+
resp, err := client.getKeyEntry(context.Background(), "ab748227-3a10-40cc-87fd-2a5321aa638d-x509-CA-A")
955955
spiretest.RequireGRPCStatusHasPrefix(t, err, codes.Internal, "failed to get transit engine key: Error making API request.")
956956
require.Empty(t, resp)
957957
}

Diff for: pkg/server/plugin/keymanager/hashicorpvault/vault_fake_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ k8s_auth {
403403
"lease_duration": 0,
404404
"data": {
405405
"keys": [
406-
"x509-CA-A"
406+
"ab748227-3a10-40cc-87fd-2a5321aa638d-x509-CA-A"
407407
]
408408
},
409409
"wrap_info": null,
@@ -447,7 +447,7 @@ k8s_auth {
447447
"min_available_version": 0,
448448
"min_decryption_version": 1,
449449
"min_encryption_version": 0,
450-
"name": "x509-CA-A",
450+
"name": "ab748227-3a10-40cc-87fd-2a5321aa638d-x509-CA-A",
451451
"supports_decryption": false,
452452
"supports_derivation": false,
453453
"supports_encryption": false,
@@ -482,7 +482,7 @@ k8s_auth {
482482
"min_available_version": 0,
483483
"min_decryption_version": 1,
484484
"min_encryption_version": 0,
485-
"name": "x509-CA-A",
485+
"name": "ab748227-3a10-40cc-87fd-2a5321aa638d-x509-CA-A",
486486
"supports_decryption": false,
487487
"supports_derivation": false,
488488
"supports_encryption": false,
@@ -517,7 +517,7 @@ k8s_auth {
517517
"min_available_version": 0,
518518
"min_decryption_version": 1,
519519
"min_encryption_version": 0,
520-
"name": "x509-CA-A",
520+
"name": "ab748227-3a10-40cc-87fd-2a5321aa638d-x509-CA-A",
521521
"supports_decryption": true,
522522
"supports_derivation": false,
523523
"supports_encryption": true,
@@ -552,7 +552,7 @@ k8s_auth {
552552
"min_available_version": 0,
553553
"min_decryption_version": 1,
554554
"min_encryption_version": 0,
555-
"name": "x509-CA-A",
555+
"name": "ab748227-3a10-40cc-87fd-2a5321aa638d-x509-CA-A",
556556
"supports_decryption": true,
557557
"supports_derivation": false,
558558
"supports_encryption": true,
@@ -587,7 +587,7 @@ k8s_auth {
587587
"min_available_version": 0,
588588
"min_decryption_version": 1,
589589
"min_encryption_version": 0,
590-
"name": "x509-CA-A",
590+
"name": "ab748227-3a10-40cc-87fd-2a5321aa638d-x509-CA-A",
591591
"supports_decryption": true,
592592
"supports_derivation": false,
593593
"supports_encryption": true,

0 commit comments

Comments
 (0)