Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update the way that the certificate bundle is generated #1428

Merged
merged 2 commits into from
Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
## 3.5.0 (Unreleased)
## 3.6.0 (Unreleased)
BUGS:
* `resource/pki_secret_backend_root_sign_intermediate`: Ensure that the `certificate_bundle`, and `ca_chain`
do not contain duplicate certificates.
([#1428](https://github.com/hashicorp/terraform-provider-vault/pull/1428))

## 3.5.0 (April 20, 2022)
FEATURES:
* Add MFA support: new resources `vault_mfa_okta`, `vault_mfa_totp`, `vault_mfa_pingid` ([#1395](https://github.com/hashicorp/terraform-provider-vault/pull/1395))
* *New* `resource/database_secrets_mount`: Configures any number of database secrets engines under
Expand Down
86 changes: 62 additions & 24 deletions vault/resource_pki_secret_backend_root_sign_intermediate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package vault

import (
"context"
"encoding/pem"
"fmt"
"log"
"strings"
Expand Down Expand Up @@ -316,7 +317,7 @@ func setCAChain(d *schema.ResourceData, resp *api.Secret) error {
// provide the CAChain from the issuing_ca and the intermediate CA certificate
var err error
if len(caChain) == 0 {
caChain, err = getCAChain(resp.Data)
caChain, err = getCAChain(resp.Data, !isPEMFormat(d))
if err != nil {
return err
}
Expand All @@ -325,40 +326,76 @@ func setCAChain(d *schema.ResourceData, resp *api.Secret) error {
return d.Set(field, caChain)
}

func getCAChain(m map[string]interface{}) ([]string, error) {
var caChain []string

for _, k := range []string{"certificate", "issuing_ca"} {
if v, ok := m[k]; ok && v.(string) != "" {
value := v.(string)
if k == "issuing_ca" && strings.Contains(caChain[0], value) {
continue
}
caChain = append(caChain, value)
} else {
return nil, fmt.Errorf("required certificate for %q is missing or empty", k)
}
}

return caChain, nil
func getCAChain(m map[string]interface{}, literal bool) ([]string, error) {
return parseCertChain(m, true, literal)
}

func setCertificateBundle(d *schema.ResourceData, resp *api.Secret) error {
field := "certificate_bundle"
func isPEMFormat(d *schema.ResourceData) bool {
format := d.Get("format").(string)
switch format {
case "pem", "pem_bundle":
return true
default:
log.Printf("[WARN] Cannot set the %q for format %q", field, format)
return false
}
}

func setCertificateBundle(d *schema.ResourceData, resp *api.Secret) error {
field := "certificate_bundle"
if !isPEMFormat(d) {
log.Printf("[WARN] Cannot set the %q, not in PEM format", field)
return nil
}

caChain, err := getCAChain(resp.Data)
chain, err := parseCertChain(resp.Data, false, false)
if err != nil {
return err
}

return d.Set(field, strings.Join(caChain, "\n"))
return d.Set(field, strings.Join(chain, "\n"))
}

func parseCertChain(m map[string]interface{}, asCA, literal bool) ([]string, error) {
var chain []string
seen := make(map[string]bool)
parseCert := func(data string) error {
var b *pem.Block
rest := []byte(data)
for {
b, rest = pem.Decode(rest)
if b == nil {
break
}

cert := strings.Trim(string(pem.EncodeToMemory(b)), "\n")
if _, ok := seen[cert]; !ok {
chain = append(chain, cert)
seen[cert] = true
}
}

return nil
}

fields := []string{"issuing_ca", "certificate"}
if !asCA {
fields = []string{fields[1], fields[0]}
}

for _, k := range fields {
if v, ok := m[k]; ok && v.(string) != "" {
value := v.(string)
if literal {
chain = append(chain, value)
} else if err := parseCert(value); err != nil {
return nil, err
}
} else {
return nil, fmt.Errorf("required certificate for %q is missing or empty", k)
}
}

return chain, nil
}

func pkiSecretBackendRootSignIntermediateRead(d *schema.ResourceData, meta interface{}) error {
Expand Down Expand Up @@ -390,8 +427,9 @@ func pkiSecretRootSignIntermediateRV0() *schema.Resource {
}

func pkiSecretRootSignIntermediateRUpgradeV0(
_ context.Context, rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
caChain, err := getCAChain(rawState)
_ context.Context, rawState map[string]interface{}, _ interface{},
) (map[string]interface{}, error) {
caChain, err := getCAChain(rawState, false)
if err != nil {
return nil, err
}
Expand Down
Loading