@@ -17,6 +17,7 @@ import (
17
17
"io"
18
18
19
19
multierror "github.com/hashicorp/go-multierror"
20
+ "github.com/hashicorp/vault/builtin/logical/ssh/managed_key"
20
21
"github.com/hashicorp/vault/sdk/framework"
21
22
"github.com/hashicorp/vault/sdk/helper/cryptoutil"
22
23
"github.com/hashicorp/vault/sdk/logical"
@@ -31,12 +32,19 @@ const (
31
32
caPublicKeyStoragePathDeprecated = "public_key"
32
33
caPrivateKeyStoragePath = "config/ca_private_key"
33
34
caPrivateKeyStoragePathDeprecated = "config/ca_bundle"
35
+ caManagedKeyStoragePath = "config/ca_managed_key"
34
36
)
35
37
36
38
type keyStorageEntry struct {
37
39
Key string `json:"key" structs:"key" mapstructure:"key"`
38
40
}
39
41
42
+ type managedKeyStorageEntry struct {
43
+ KeyId managed_key.UUIDKey `json:"key_id" structs:"key_id" mapstructure:"key_id"`
44
+ KeyName managed_key.NameKey `json:"key_name" structs:"key_name" mapstructure:"key_name"`
45
+ PublicKey string `json:"public_key" structs:"public_key" mapstructure:"public_key"`
46
+ }
47
+
40
48
func pathConfigCA (b * backend ) * framework.Path {
41
49
return & framework.Path {
42
50
Pattern : "config/ca" ,
@@ -56,7 +64,7 @@ func pathConfigCA(b *backend) *framework.Path {
56
64
},
57
65
"generate_signing_key" : {
58
66
Type : framework .TypeBool ,
59
- Description : `Generate SSH key pair internally rather than use the private_key and public_key fields.` ,
67
+ Description : `Generate SSH key pair internally rather than use the private_key and public_key fields. If managed key config is provided, this field is ignored. ` ,
60
68
Default : true ,
61
69
},
62
70
"key_type" : {
@@ -69,6 +77,14 @@ func pathConfigCA(b *backend) *framework.Path {
69
77
Description : `Specifies the desired key bits when generating variable-length keys (such as when key_type="ssh-rsa") or which NIST P-curve to use when key_type="ec" (256, 384, or 521).` ,
70
78
Default : 0 ,
71
79
},
80
+ "managed_key_name" : {
81
+ Type : framework .TypeString ,
82
+ Description : `The name of the managed key to use. When using a managed key, this field or managed_key_id is required.` ,
83
+ },
84
+ "managed_key_id" : {
85
+ Type : framework .TypeString ,
86
+ Description : `The id of the managed key to use. When using a managed key, this field or managed_key_name is required.` ,
87
+ },
72
88
},
73
89
74
90
Operations : map [logical.Operation ]framework.OperationHandler {
@@ -189,67 +205,75 @@ func (b *backend) pathConfigCAUpdate(ctx context.Context, req *logical.Request,
189
205
publicKey := data .Get ("public_key" ).(string )
190
206
privateKey := data .Get ("private_key" ).(string )
191
207
192
- var generateSigningKey bool
208
+ managedKeyName := data .Get ("managed_key_name" ).(string )
209
+ managedKeyID := data .Get ("managed_key_id" ).(string )
193
210
194
- generateSigningKeyRaw , ok := data .GetOk ("generate_signing_key" )
195
- switch {
196
- // explicitly set true
197
- case ok && generateSigningKeyRaw .(bool ):
198
- if publicKey != "" || privateKey != "" {
199
- return logical .ErrorResponse ("public_key and private_key must not be set when generate_signing_key is set to true" ), nil
200
- }
211
+ useManagedKey := managedKeyName != "" || managedKeyID != ""
201
212
202
- generateSigningKey = true
213
+ generateSigningKey := data . Get ( "generate_signing_key" ).( bool )
203
214
204
- // explicitly set to false, or not set and we have both a public and private key
205
- case ok , publicKey != "" && privateKey != "" :
206
- if publicKey == "" {
207
- return logical .ErrorResponse ("missing public_key" ), nil
215
+ if useManagedKey {
216
+ generateSigningKey = false
217
+ err = b .createManagedKey (ctx , req .Storage , managedKeyName , managedKeyID )
218
+ if err != nil {
219
+ return nil , err
208
220
}
221
+ } else {
222
+ if publicKey != "" && privateKey != "" {
223
+ _ , err := ssh .ParsePrivateKey ([]byte (privateKey ))
224
+ if err != nil {
225
+ return logical .ErrorResponse (fmt .Sprintf ("Unable to parse private_key as an SSH private key: %v" , err )), nil
226
+ }
209
227
210
- if privateKey == "" {
211
- return logical .ErrorResponse ("missing private_key" ), nil
212
- }
228
+ _ , err = parsePublicSSHKey (publicKey )
229
+ if err != nil {
230
+ return logical .ErrorResponse (fmt .Sprintf ("Unable to parse public_key as an SSH public key: %v" , err )), nil
231
+ }
232
+ } else if generateSigningKey {
233
+ keyType := data .Get ("key_type" ).(string )
234
+ keyBits := data .Get ("key_bits" ).(int )
213
235
214
- _ , err := ssh .ParsePrivateKey ([]byte (privateKey ))
215
- if err != nil {
216
- return logical .ErrorResponse (fmt .Sprintf ("Unable to parse private_key as an SSH private key: %v" , err )), nil
236
+ publicKey , privateKey , err = generateSSHKeyPair (b .Backend .GetRandomReader (), keyType , keyBits )
237
+ if err != nil {
238
+ return nil , err
239
+ }
240
+ } else {
241
+ return logical .ErrorResponse ("if generate_signing_key is false, either both public_key and private_key or a managed key must be provided" ), nil
217
242
}
218
243
219
- _ , err = parsePublicSSHKey ( publicKey )
244
+ errResp , err := createStoredKey ( ctx , req . Storage , publicKey , privateKey )
220
245
if err != nil {
221
- return logical .ErrorResponse (fmt .Sprintf ("Unable to parse public_key as an SSH public key: %v" , err )), nil
246
+ return nil , err
247
+ }
248
+ if errResp != nil {
249
+ return errResp , nil
222
250
}
223
-
224
- // not set and no public/private key provided so generate
225
- case publicKey == "" && privateKey == "" :
226
- generateSigningKey = true
227
-
228
- // not set, but one or the other supplied
229
- default :
230
- return logical .ErrorResponse ("only one of public_key and private_key set; both must be set to use, or both must be blank to auto-generate" ), nil
231
251
}
232
252
233
253
if generateSigningKey {
234
- keyType := data .Get ("key_type" ).(string )
235
- keyBits := data .Get ("key_bits" ).(int )
236
-
237
- publicKey , privateKey , err = generateSSHKeyPair (b .Backend .GetRandomReader (), keyType , keyBits )
238
- if err != nil {
239
- return nil , err
254
+ response := & logical.Response {
255
+ Data : map [string ]interface {}{
256
+ "public_key" : publicKey ,
257
+ },
240
258
}
259
+
260
+ return response , nil
241
261
}
242
262
263
+ return nil , nil
264
+ }
265
+
266
+ func createStoredKey (ctx context.Context , s logical.Storage , publicKey , privateKey string ) (* logical.Response , error ) {
243
267
if publicKey == "" || privateKey == "" {
244
268
return nil , fmt .Errorf ("failed to generate or parse the keys" )
245
269
}
246
270
247
- publicKeyEntry , err := caKey (ctx , req . Storage , caPublicKey )
271
+ publicKeyEntry , err := caKey (ctx , s , caPublicKey )
248
272
if err != nil {
249
273
return nil , fmt .Errorf ("failed to read CA public key: %w" , err )
250
274
}
251
275
252
- privateKeyEntry , err := caKey (ctx , req . Storage , caPrivateKey )
276
+ privateKeyEntry , err := caKey (ctx , s , caPrivateKey )
253
277
if err != nil {
254
278
return nil , fmt .Errorf ("failed to read CA private key: %w" , err )
255
279
}
@@ -266,7 +290,7 @@ func (b *backend) pathConfigCAUpdate(ctx context.Context, req *logical.Request,
266
290
}
267
291
268
292
// Save the public key
269
- err = req . Storage .Put (ctx , entry )
293
+ err = s .Put (ctx , entry )
270
294
if err != nil {
271
295
return nil , err
272
296
}
@@ -279,32 +303,22 @@ func (b *backend) pathConfigCAUpdate(ctx context.Context, req *logical.Request,
279
303
}
280
304
281
305
// Save the private key
282
- err = req . Storage .Put (ctx , entry )
306
+ err = s .Put (ctx , entry )
283
307
if err != nil {
284
308
var mErr * multierror.Error
285
309
286
310
mErr = multierror .Append (mErr , fmt .Errorf ("failed to store CA private key: %w" , err ))
287
311
288
312
// If storing private key fails, the corresponding public key should be
289
313
// removed
290
- if delErr := req . Storage .Delete (ctx , caPublicKeyStoragePath ); delErr != nil {
314
+ if delErr := s .Delete (ctx , caPublicKeyStoragePath ); delErr != nil {
291
315
mErr = multierror .Append (mErr , fmt .Errorf ("failed to cleanup CA public key: %w" , delErr ))
292
316
return nil , mErr
293
317
}
294
318
295
319
return nil , err
296
320
}
297
321
298
- if generateSigningKey {
299
- response := & logical.Response {
300
- Data : map [string ]interface {}{
301
- "public_key" : publicKey ,
302
- },
303
- }
304
-
305
- return response , nil
306
- }
307
-
308
322
return nil , nil
309
323
}
310
324
@@ -406,3 +420,39 @@ func generateSSHKeyPair(randomSource io.Reader, keyType string, keyBits int) (st
406
420
407
421
return string (ssh .MarshalAuthorizedKey (public )), string (pem .EncodeToMemory (privateBlock )), nil
408
422
}
423
+
424
+ func (b * backend ) createManagedKey (ctx context.Context , s logical.Storage , managedKeyName , managedKeyId string ) error {
425
+ var keyId managed_key.UUIDKey
426
+ var keyName managed_key.NameKey
427
+ var keyInfo * managed_key.ManagedKeyInfo
428
+ var err error
429
+
430
+ if managedKeyId != "" {
431
+ keyId = managed_key .UUIDKey (managedKeyId )
432
+ keyInfo , err = managed_key .GetManagedKeyInfo (ctx , b , keyId )
433
+ } else if managedKeyName != "" {
434
+ keyName = managed_key .NameKey (managedKeyName )
435
+ keyInfo , err = managed_key .GetManagedKeyInfo (ctx , b , keyName )
436
+ }
437
+
438
+ if err != nil {
439
+ return fmt .Errorf ("error retrieving public key: %s" , err )
440
+ }
441
+
442
+ entry , err := logical .StorageEntryJSON (caManagedKeyStoragePath , & managedKeyStorageEntry {
443
+ PublicKey : string (keyInfo .PublicKey ().Marshal ()),
444
+ KeyName : keyInfo .Name ,
445
+ KeyId : keyInfo .Uuid ,
446
+ })
447
+ if err != nil {
448
+ return fmt .Errorf ("error creating storage entry: %s" , err )
449
+ }
450
+
451
+ // Save the public key
452
+ err = s .Put (ctx , entry )
453
+ if err != nil {
454
+ return fmt .Errorf ("error writing key entry to storage: %s" , err )
455
+ }
456
+
457
+ return nil
458
+ }
0 commit comments