Skip to content

Commit 3d870ea

Browse files
Merge branch 'include_metadata_56051' of https://github.com/Keyfactor/hashicorp-vault-secretsengine into OauthAndParametersForTemplateAndCA
2 parents 5932154 + 2c5db31 commit 3d870ea

File tree

6 files changed

+61
-4
lines changed

6 files changed

+61
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
- 1.4.0
22
- Added support for oAuth2 authentication to Keyfactor Command.
33
- Included the ability to specify CA and Template via command parameters
4+
- Included the ability to pass metadata along with the request
45

56
- 1.3.1
67
- Fix for issue where plugin was not enforcing plugin-side role limitations for AllowedDomains and AllowSubDomains, and was relying exclusively on the certificate template for these values.

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,11 @@ the Vault secrets store.
479479
> [!NOTE]
480480
> The Certificate Authority and Template values can be passed via command parameters. If they are omitted, the values set in the configuration are used.
481481
482+
> [!NOTE]
483+
> As of v1.4, certificate Metadata is able to be provided in the command line and submitted along with the signing request.
484+
> example: `vault write keyfactor/issue/hashiIssuer common_name="test.com" dns_sans="test.com" metadata='{ \"testMetadata\": \"arbitrary string value\" }' ca="myCA"`
485+
> **Make sure that the quotation marks as escaped, as above, or an error will be returned.**
486+
482487
### Viewing Certificates
483488

484489
After certificates are stored in the secrets store, you can then retrieve those certificates at a later time if

backend.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func (b *keyfactorBackend) getClient(ctx context.Context, s logical.Storage) (*k
130130
}
131131

132132
// Handle interface with Keyfactor API to enroll a certificate with given content
133-
func (b *keyfactorBackend) submitCSR(ctx context.Context, req *logical.Request, csr string, caName string, templateName string) ([]string, string, error) {
133+
func (b *keyfactorBackend) submitCSR(ctx context.Context, req *logical.Request, csr string, caName string, templateName string, metaDataJson string) ([]string, string, error) {
134134
config, err := b.fetchConfig(ctx, req.Storage)
135135
if err != nil {
136136
return nil, "", err
@@ -156,7 +156,7 @@ func (b *keyfactorBackend) submitCSR(ctx context.Context, req *logical.Request,
156156

157157
url := config.KeyfactorUrl + "/" + config.CommandAPIPath + "/Enrollment/CSR"
158158
b.Logger().Debug("url: " + url)
159-
bodyContent := "{\"CSR\": \"" + csr + "\",\"CertificateAuthority\":\"" + caName + "\",\"IncludeChain\": true, \"Metadata\": {}, \"Timestamp\": \"" + time + "\",\"Template\": \"" + templateName + "\",\"SANs\": {}}"
159+
bodyContent := "{\"CSR\": \"" + csr + "\",\"CertificateAuthority\":\"" + caName + "\",\"IncludeChain\": true, \"Metadata\": " + metaDataJson + ", \"Timestamp\": \"" + time + "\",\"Template\": \"" + templateName + "\",\"SANs\": {}}"
160160
payload := strings.NewReader(bodyContent)
161161
b.Logger().Debug("body: " + bodyContent)
162162
httpReq, err := http.NewRequest("POST", url, payload)
@@ -255,3 +255,15 @@ func (b *keyfactorBackend) submitCSR(ctx context.Context, req *logical.Request,
255255
const keyfactorHelp = `
256256
The Keyfactor backend is a pki service that issues and manages certificates.
257257
`
258+
259+
func (b *keyfactorBackend) isValidJSON(str string) bool {
260+
var js json.RawMessage
261+
err := json.Unmarshal([]byte(str), &js)
262+
if err != nil {
263+
b.Logger().Debug(err.Error())
264+
return false
265+
} else {
266+
b.Logger().Debug("the metadata was able to be parsed as valid JSON")
267+
return true
268+
}
269+
}

fields.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ be larger than the role max TTL.`,
7676
},
7777
}
7878

79+
fields["metadata"] = &framework.FieldSchema{
80+
Type: framework.TypeString,
81+
Description: `Metadata in JSON format to be passed along with the signing request and associated with the certificate in Command.
82+
Quotation marks should be escaped.
83+
Example: ... metadata='{ \"testMetadata\": \"arbitrary string value\" }`,
84+
}
85+
7986
return fields
8087
}
8188

path_certs.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,21 @@ func (b *keyfactorBackend) pathSign(ctx context.Context, req *logical.Request, d
262262
b.Logger().Debug("CA Name parameter = " + caName)
263263
b.Logger().Debug("Template name parameter = " + templateName)
264264

265-
certs, serial, errr := b.submitCSR(ctx, req, csr, caName, templateName)
265+
metadata := data.Get("metadata").(string)
266+
267+
if metadata == "" {
268+
metadata = "{}"
269+
}
270+
271+
// verify that any passed metadata string is valid JSON
272+
273+
if !b.isValidJSON(metadata) {
274+
err := fmt.Errorf("'%s' is not a valid JSON string", metadata)
275+
b.Logger().Error(err.Error())
276+
return nil, err
277+
}
278+
279+
certs, serial, errr := b.submitCSR(ctx, req, csr, caName, templateName, metadata)
266280

267281
if errr != nil {
268282
return nil, fmt.Errorf("could not sign csr: %s", errr)
@@ -411,14 +425,27 @@ func (b *keyfactorBackend) pathIssueSignCert(ctx context.Context, req *logical.R
411425
err_resp = fmt.Errorf("at least one DNS SAN is required to match the supplied Common Name for RFC 2818 compliance")
412426
}
413427

428+
metadata := data.Get("metadata").(string)
429+
430+
if metadata == "" {
431+
metadata = "{}"
432+
}
433+
434+
// verify that any passed metadata string is valid JSON
435+
436+
if !b.isValidJSON(metadata) {
437+
err_resp := fmt.Errorf("'%s' is not a valid JSON string", metadata)
438+
b.Logger().Error(err_resp.Error())
439+
}
440+
414441
if err_resp != nil {
415442
return nil, err_resp
416443
}
417444

418445
//generate and submit CSR
419446
b.Logger().Debug("generating the CSR...")
420447
csr, key := b.generateCSR(cn.(string), ip_sans, dns_sans)
421-
certs, serial, errr := b.submitCSR(ctx, req, csr, caName, templateName)
448+
certs, serial, errr := b.submitCSR(ctx, req, csr, caName, templateName, metadata)
422449

423450
if errr != nil {
424451
return nil, fmt.Errorf("could not enroll certificate: %s", errr)

readme_source.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,11 @@ the Vault secrets store.
455455
> [!NOTE]
456456
> The Certificate Authority and Template values can be passed via command parameters. If they are omitted, the values set in the configuration are used.
457457
458+
> [!NOTE]
459+
> As of v1.4, certificate Metadata is able to be provided in the command line and submitted along with the signing request.
460+
> example: `vault write keyfactor/issue/hashiIssuer common_name="test.com" dns_sans="test.com" metadata='{ \"testMetadata\": \"arbitrary string value\" }' ca="myCA"`
461+
> **Make sure that the quotation marks as escaped, as above, or an error will be returned.**
462+
458463
### Viewing Certificates
459464

460465
After certificates are stored in the secrets store, you can then retrieve those certificates at a later time if

0 commit comments

Comments
 (0)