@@ -2,7 +2,10 @@ package hashicorpvault
22
33import (
44 "bytes"
5+ "context"
56 "fmt"
7+ "github.com/hashicorp/vault/sdk/helper/consts"
8+ "github.com/spiffe/spire/pkg/server/plugin/keymanager"
69 "github.com/stretchr/testify/require"
710 "google.golang.org/grpc/codes"
811 "testing"
@@ -251,6 +254,283 @@ func TestConfigure(t *testing.T) {
251254 }
252255}
253256
257+ func TestGenerateKey (t * testing.T ) {
258+ successfulConfig := & Config {
259+ TransitEnginePath : "test-transit" ,
260+ CACertPath : "testdata/root-cert.pem" ,
261+ TokenAuth : & TokenAuthConfig {
262+ Token : "test-token" ,
263+ },
264+ }
265+
266+ for _ , tt := range []struct {
267+ name string
268+ csr []byte
269+ config * Config
270+ authMethod AuthMethod
271+ expectCode codes.Code
272+ expectMsgPrefix string
273+ id string
274+ keyType keymanager.KeyType
275+
276+ fakeServer func () * FakeVaultServerConfig
277+ }{
278+ {
279+ name : "Generate EC P-256 key with token auth" ,
280+ id : "x509-CA-A" ,
281+ keyType : keymanager .ECP256 ,
282+ config : successfulConfig ,
283+ authMethod : TOKEN ,
284+ fakeServer : func () * FakeVaultServerConfig {
285+ fakeServer := setupSuccessFakeVaultServer ()
286+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
287+ fakeServer .CertAuthResponse = []byte {}
288+ fakeServer .AppRoleAuthResponse = []byte {}
289+
290+ return fakeServer
291+ },
292+ },
293+ {
294+ name : "Generate P-384 key with token auth" ,
295+ id : "x509-CA-A" ,
296+ keyType : keymanager .ECP384 ,
297+ config : successfulConfig ,
298+ authMethod : TOKEN ,
299+ fakeServer : func () * FakeVaultServerConfig {
300+ fakeServer := setupSuccessFakeVaultServer ()
301+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
302+ fakeServer .CertAuthResponse = []byte {}
303+ fakeServer .AppRoleAuthResponse = []byte {}
304+ fakeServer .GetKeyResponse = []byte (testGetKeyResponseP384 )
305+
306+ return fakeServer
307+ },
308+ },
309+ {
310+ name : "Generate RSA 2048 key with token auth" ,
311+ id : "x509-CA-A" ,
312+ keyType : keymanager .RSA2048 ,
313+ config : successfulConfig ,
314+ authMethod : TOKEN ,
315+ fakeServer : func () * FakeVaultServerConfig {
316+ fakeServer := setupSuccessFakeVaultServer ()
317+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
318+ fakeServer .CertAuthResponse = []byte {}
319+ fakeServer .AppRoleAuthResponse = []byte {}
320+ fakeServer .GetKeyResponse = []byte (testGetKeyResponseRSA2048 )
321+
322+ return fakeServer
323+ },
324+ },
325+ {
326+ name : "Generate RSA 4096 key with token auth" ,
327+ id : "x509-CA-A" ,
328+ keyType : keymanager .RSA4096 ,
329+ config : successfulConfig ,
330+ authMethod : TOKEN ,
331+ fakeServer : func () * FakeVaultServerConfig {
332+ fakeServer := setupSuccessFakeVaultServer ()
333+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
334+ fakeServer .CertAuthResponse = []byte {}
335+ fakeServer .AppRoleAuthResponse = []byte {}
336+ fakeServer .GetKeyResponse = []byte (testGetKeyResponseRSA4096 )
337+
338+ return fakeServer
339+ },
340+ },
341+ {
342+ name : "Generate key with missing id" ,
343+ keyType : keymanager .RSA2048 ,
344+ config : successfulConfig ,
345+ authMethod : TOKEN ,
346+ fakeServer : func () * FakeVaultServerConfig {
347+ fakeServer := setupSuccessFakeVaultServer ()
348+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
349+ fakeServer .CertAuthResponse = []byte {}
350+ fakeServer .AppRoleAuthResponse = []byte {}
351+ fakeServer .GetKeyResponse = []byte (testGetKeyResponseRSA2048 )
352+
353+ return fakeServer
354+ },
355+ expectCode : codes .InvalidArgument ,
356+ expectMsgPrefix : "keymanager(hashicorp_vault): key id is required" ,
357+ },
358+ {
359+ name : "Generate key with missing key type" ,
360+ id : "x509-CA-A" ,
361+ config : successfulConfig ,
362+ authMethod : TOKEN ,
363+ fakeServer : func () * FakeVaultServerConfig {
364+ fakeServer := setupSuccessFakeVaultServer ()
365+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
366+ fakeServer .CertAuthResponse = []byte {}
367+ fakeServer .AppRoleAuthResponse = []byte {}
368+ fakeServer .GetKeyResponse = []byte (testGetKeyResponseRSA2048 )
369+
370+ return fakeServer
371+ },
372+ expectCode : codes .InvalidArgument ,
373+ expectMsgPrefix : "keymanager(hashicorp_vault): key type is required" ,
374+ },
375+ {
376+ name : "Generate key with unsupported key type" ,
377+ id : "x509-CA-A" ,
378+ keyType : 100 ,
379+ config : successfulConfig ,
380+ authMethod : TOKEN ,
381+ fakeServer : func () * FakeVaultServerConfig {
382+ fakeServer := setupSuccessFakeVaultServer ()
383+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
384+ fakeServer .CertAuthResponse = []byte {}
385+ fakeServer .AppRoleAuthResponse = []byte {}
386+ fakeServer .GetKeyResponse = []byte (testGetKeyResponseRSA2048 )
387+
388+ return fakeServer
389+ },
390+ expectCode : codes .Internal ,
391+ expectMsgPrefix : "keymanager(hashicorp_vault): facade does not support key type \" UNKNOWN(100)\" " ,
392+ },
393+ {
394+ name : "Malformed get key response" ,
395+ id : "x509-CA-A" ,
396+ keyType : keymanager .RSA2048 ,
397+ config : successfulConfig ,
398+ authMethod : TOKEN ,
399+ fakeServer : func () * FakeVaultServerConfig {
400+ fakeServer := setupSuccessFakeVaultServer ()
401+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
402+ fakeServer .CertAuthResponse = []byte {}
403+ fakeServer .AppRoleAuthResponse = []byte {}
404+ fakeServer .GetKeyResponse = []byte ("error" )
405+
406+ return fakeServer
407+ },
408+ expectCode : codes .Internal ,
409+ expectMsgPrefix : "keymanager(hashicorp_vault): failed to get transit engine key: invalid character" ,
410+ },
411+ {
412+ name : "Malformed create key response" ,
413+ id : "x509-CA-A" ,
414+ keyType : keymanager .RSA2048 ,
415+ config : successfulConfig ,
416+ authMethod : TOKEN ,
417+ fakeServer : func () * FakeVaultServerConfig {
418+ fakeServer := setupSuccessFakeVaultServer ()
419+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
420+ fakeServer .CertAuthResponse = []byte {}
421+ fakeServer .AppRoleAuthResponse = []byte {}
422+ fakeServer .CreateKeyResponse = []byte ("error" )
423+
424+ return fakeServer
425+ },
426+ expectCode : codes .Internal ,
427+ expectMsgPrefix : "keymanager(hashicorp_vault): failed to create transit engine key: invalid character" ,
428+ },
429+ {
430+ name : "Bad get key response code" ,
431+ id : "x509-CA-A" ,
432+ keyType : keymanager .RSA2048 ,
433+ config : successfulConfig ,
434+ authMethod : TOKEN ,
435+ fakeServer : func () * FakeVaultServerConfig {
436+ fakeServer := setupSuccessFakeVaultServer ()
437+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
438+ fakeServer .CertAuthResponse = []byte {}
439+ fakeServer .AppRoleAuthResponse = []byte {}
440+ fakeServer .GetKeyResponseCode = 500
441+
442+ return fakeServer
443+ },
444+ expectCode : codes .Internal ,
445+ expectMsgPrefix : "keymanager(hashicorp_vault): failed to get transit engine key: Error making API request." ,
446+ },
447+ {
448+ name : "Bad create key response code" ,
449+ id : "x509-CA-A" ,
450+ keyType : keymanager .RSA2048 ,
451+ config : successfulConfig ,
452+ authMethod : TOKEN ,
453+ fakeServer : func () * FakeVaultServerConfig {
454+ fakeServer := setupSuccessFakeVaultServer ()
455+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
456+ fakeServer .CertAuthResponse = []byte {}
457+ fakeServer .AppRoleAuthResponse = []byte {}
458+ fakeServer .CreateKeyResponseCode = 500
459+
460+ return fakeServer
461+ },
462+ expectCode : codes .Internal ,
463+ expectMsgPrefix : "keymanager(hashicorp_vault): failed to create transit engine key: Error making API request." ,
464+ },
465+ {
466+ name : "Malformed key" ,
467+ id : "x509-CA-A" ,
468+ keyType : keymanager .RSA2048 ,
469+ config : successfulConfig ,
470+ authMethod : TOKEN ,
471+ fakeServer : func () * FakeVaultServerConfig {
472+ fakeServer := setupSuccessFakeVaultServer ()
473+ fakeServer .LookupSelfResponse = []byte (testLookupSelfResponse )
474+ fakeServer .CertAuthResponse = []byte {}
475+ fakeServer .AppRoleAuthResponse = []byte {}
476+ fakeServer .GetKeyResponse = []byte (testGetKeyResponseMalformed )
477+
478+ return fakeServer
479+ },
480+ expectCode : codes .Internal ,
481+ expectMsgPrefix : "keymanager(hashicorp_vault): unable to decode PEM key" ,
482+ },
483+ } {
484+ tt := tt
485+ t .Run (tt .name , func (t * testing.T ) {
486+ fakeVaultServer := tt .fakeServer ()
487+
488+ s , addr , err := fakeVaultServer .NewTLSServer ()
489+ require .NoError (t , err )
490+
491+ s .Start ()
492+ defer s .Close ()
493+
494+ p := New ()
495+ options := []plugintest.Option {
496+ plugintest .CaptureConfigureError (& err ),
497+ plugintest .CoreConfig (catalog.CoreConfig {TrustDomain : spiffeid .RequireTrustDomainFromString ("example.org" )}),
498+ }
499+ if tt .config != nil {
500+ tt .config .VaultAddr = fmt .Sprintf ("https://%s" , addr )
501+ cp , err := p .genClientParams (tt .authMethod , tt .config )
502+ require .NoError (t , err )
503+ cc , err := NewClientConfig (cp , p .logger )
504+ require .NoError (t , err )
505+ p .cc = cc
506+ options = append (options , plugintest .ConfigureJSON (tt .config ))
507+ }
508+ p .authMethod = tt .authMethod
509+
510+ v1 := new (keymanager.V1 )
511+ plugintest .Load (t , builtin (p ), v1 ,
512+ options ... ,
513+ )
514+
515+ key , err := v1 .GenerateKey (context .Background (), tt .id , tt .keyType )
516+
517+ spiretest .RequireGRPCStatusHasPrefix (t , err , tt .expectCode , tt .expectMsgPrefix )
518+ if tt .expectCode != codes .OK {
519+ require .Nil (t , key )
520+ return
521+ }
522+
523+ require .NotNil (t , key )
524+ require .Equal (t , tt .id , key .ID ())
525+
526+ if p .cc .clientParams .Namespace != "" {
527+ headers := p .vc .vaultClient .Headers ()
528+ require .Equal (t , p .cc .clientParams .Namespace , headers .Get (consts .NamespaceHeaderName ))
529+ }
530+ })
531+ }
532+ }
533+
254534func getTestConfigureRequest (t * testing.T , addr string , tpl string ) string {
255535 templ , err := template .New ("plugin config" ).Parse (tpl )
256536 require .NoError (t , err )
@@ -264,6 +544,35 @@ func getTestConfigureRequest(t *testing.T, addr string, tpl string) string {
264544 return c .String ()
265545}
266546
547+ func setupSuccessFakeVaultServer () * FakeVaultServerConfig {
548+ fakeVaultServer := setupFakeVaultServer ()
549+
550+ fakeVaultServer .CertAuthResponseCode = 200
551+ fakeVaultServer .CertAuthResponse = []byte (testCertAuthResponse )
552+ fakeVaultServer .CertAuthReqEndpoint = "/v1/auth/test-cert-auth/login"
553+
554+ fakeVaultServer .AppRoleAuthResponseCode = 200
555+ fakeVaultServer .AppRoleAuthResponse = []byte (testAppRoleAuthResponse )
556+ fakeVaultServer .AppRoleAuthReqEndpoint = "/v1/auth/test-approle-auth/login"
557+
558+ fakeVaultServer .K8sAuthResponseCode = 200
559+ fakeVaultServer .K8sAuthReqEndpoint = "/v1/auth/test-k8s-auth/login"
560+ fakeVaultServer .K8sAuthResponse = []byte (testK8sAuthResponse )
561+
562+ fakeVaultServer .LookupSelfResponse = []byte (testLookupSelfResponse )
563+ fakeVaultServer .LookupSelfReqEndpoint = "GET /v1/auth/token/lookup-self"
564+ fakeVaultServer .LookupSelfResponseCode = 200
565+
566+ fakeVaultServer .CreateKeyResponseCode = 200
567+ fakeVaultServer .CreateKeyReqEndpoint = "PUT /v1/test-transit/keys/{id}"
568+
569+ fakeVaultServer .GetKeyResponseCode = 200
570+ fakeVaultServer .GetKeyReqEndpoint = "GET /v1/test-transit/keys/{id}"
571+ fakeVaultServer .GetKeyResponse = []byte (testGetKeyResponseP256 )
572+
573+ return fakeVaultServer
574+ }
575+
267576func setupFakeVaultServer () * FakeVaultServerConfig {
268577 fakeVaultServer := NewFakeVaultServerConfig ()
269578 fakeVaultServer .ServerCertificatePemPath = testServerCert
0 commit comments