From 2fd24b178220bc014d084998956652ece68ed42d Mon Sep 17 00:00:00 2001 From: hc-github-team-secure-vault-core <82990506+hc-github-team-secure-vault-core@users.noreply.github.com> Date: Thu, 15 Jun 2023 17:15:01 -0400 Subject: [PATCH] backport of commit 8cc7be234ac34ff0f703ab092a7314ba9e65b277 (#21293) Co-authored-by: Matt Schultz <975680+schultz-is@users.noreply.github.com> --- builtin/logical/pki/acme_challenges.go | 39 +++- builtin/logical/pki/acme_challenges_test.go | 43 +++-- .../logical/pkiext/pkiext_binary/acme_test.go | 166 ++++++++++++++++++ .../pkiext/pkiext_binary/pki_cluster.go | 5 + .../logical/pkiext/pkiext_binary/pki_mount.go | 10 ++ .../pkiext_binary/testdata/caddy_http.json | 66 +++++++ .../testdata/caddy_http_eab.json | 70 ++++++++ .../testdata/caddy_tls_alpn.json | 66 +++++++ 8 files changed, 442 insertions(+), 23 deletions(-) create mode 100644 builtin/logical/pkiext/pkiext_binary/testdata/caddy_http.json create mode 100644 builtin/logical/pkiext/pkiext_binary/testdata/caddy_http_eab.json create mode 100644 builtin/logical/pkiext/pkiext_binary/testdata/caddy_tls_alpn.json diff --git a/builtin/logical/pki/acme_challenges.go b/builtin/logical/pki/acme_challenges.go index 855035729e97..d840940fa718 100644 --- a/builtin/logical/pki/acme_challenges.go +++ b/builtin/logical/pki/acme_challenges.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/sha256" + "crypto/subtle" "crypto/tls" "crypto/x509" "encoding/asn1" @@ -55,7 +56,7 @@ func ValidateKeyAuthorization(keyAuthz string, token string, thumbprint string) // challenge matches our expectation, returning (true, nil) if so, or // (false, err) if not. // -// This is for use with DNS challenges, which require +// This is for use with DNS challenges, which require base64 encoding. func ValidateSHA256KeyAuthorization(keyAuthz string, token string, thumbprint string) (bool, error) { authzContents := token + "." + thumbprint checksum := sha256.Sum256([]byte(authzContents)) @@ -68,6 +69,22 @@ func ValidateSHA256KeyAuthorization(keyAuthz string, token string, thumbprint st return true, nil } +// ValidateRawSHA256KeyAuthorization validates that the given keyAuthz from a +// challenge matches our expectation, returning (true, nil) if so, or +// (false, err) if not. +// +// This is for use with TLS challenges, which require the raw hash output. +func ValidateRawSHA256KeyAuthorization(keyAuthz []byte, token string, thumbprint string) (bool, error) { + authzContents := token + "." + thumbprint + expectedAuthz := sha256.Sum256([]byte(authzContents)) + + if len(keyAuthz) != len(expectedAuthz) || subtle.ConstantTimeCompare(expectedAuthz[:], keyAuthz) != 1 { + return false, fmt.Errorf("sha256 key authorization was invalid") + } + + return true, nil +} + func buildResolver(config *acmeConfigEntry) (*net.Resolver, error) { if len(config.DNSResolver) == 0 { return net.DefaultResolver, nil @@ -286,9 +303,13 @@ func ValidateTLSALPN01Challenge(domain string, token string, thumbprint string, // Verify that this is a self-signed certificate that isn't signed // by another certificate (i.e., with the same key material but // different issuer). - if err := cert.CheckSignatureFrom(cert); err != nil { - return fmt.Errorf("server under test returned a non-self-signed certificate: %w", err) + // NOTE: Do not use cert.CheckSignatureFrom(cert) as we need to bypass the + // checks for the parent certificate having the IsCA basic constraint set. + err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature) + if err != nil { + return fmt.Errorf("server under test returned a non-self-signed certificate: %v", err) } + if !bytes.Equal(cert.RawSubject, cert.RawIssuer) { return fmt.Errorf("server under test returned a non-self-signed certificate: invalid subject (%v) <-> issuer (%v) match", cert.Subject.String(), cert.Issuer.String()) } @@ -339,8 +360,16 @@ func ValidateTLSALPN01Challenge(domain string, token string, thumbprint string, return fmt.Errorf("server under test returned a certificate with an acmeIdentifier extension marked non-Critical") } - keyAuthz := string(ext.Value) - ok, err := ValidateSHA256KeyAuthorization(keyAuthz, token, thumbprint) + var keyAuthz []byte + remainder, err := asn1.Unmarshal(ext.Value, &keyAuthz) + if err != nil { + return fmt.Errorf("server under test returned a certificate with invalid acmeIdentifier extension value: %w", err) + } + if len(remainder) > 0 { + return fmt.Errorf("server under test returned a certificate with invalid acmeIdentifier extension value with additional trailing data") + } + + ok, err := ValidateRawSHA256KeyAuthorization(keyAuthz, token, thumbprint) if !ok || err != nil { return fmt.Errorf("server under test returned a certificate with an invalid key authorization (%w)", err) } diff --git a/builtin/logical/pki/acme_challenges_test.go b/builtin/logical/pki/acme_challenges_test.go index 3bcdf88141d7..62904a474344 100644 --- a/builtin/logical/pki/acme_challenges_test.go +++ b/builtin/logical/pki/acme_challenges_test.go @@ -10,6 +10,7 @@ import ( "crypto/tls" "crypto/x509" "crypto/x509/pkix" + "encoding/asn1" "encoding/base64" "fmt" "math/big" @@ -308,7 +309,8 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { t.Logf("using keyAuthorizationTestCase [tc=%d] as alpnTestCase [tc=%d]...", index, len(alpnTestCases)) // Properly encode the authorization. checksum := sha256.Sum256([]byte(tc.keyAuthz)) - authz := base64.RawURLEncoding.EncodeToString(checksum[:]) + authz, err := asn1.Marshal(checksum[:]) + require.NoError(t, err, "failed asn.1 marshalling authz") // Build a self-signed certificate. key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -329,11 +331,11 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { { Id: OIDACMEIdentifier, Critical: true, - Value: []byte(authz), + Value: authz, }, }, BasicConstraintsValid: true, - IsCA: true, + IsCA: false, } certBytes, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key) require.NoError(t, err, "failed to create certificate") @@ -378,7 +380,8 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { // Compute our authorization. checksum := sha256.Sum256([]byte("valid.valid")) - authz := base64.RawURLEncoding.EncodeToString(checksum[:]) + authz, err := asn1.Marshal(checksum[:]) + require.NoError(t, err, "failed to marshal authz with asn.1 ") // Build a leaf certificate which _could_ pass validation key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -399,11 +402,11 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { { Id: OIDACMEIdentifier, Critical: true, - Value: []byte(authz), + Value: authz, }, }, BasicConstraintsValid: true, - IsCA: true, + IsCA: false, } certBytes, err := x509.CreateCertificate(rand.Reader, tmpl, rootCert, key.Public(), rootKey) require.NoError(t, err, "failed to create leaf certificate") @@ -426,7 +429,8 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { // Test case: cert without DNSSan // Compute our authorization. checksum := sha256.Sum256([]byte("valid.valid")) - authz := base64.RawURLEncoding.EncodeToString(checksum[:]) + authz, err := asn1.Marshal(checksum[:]) + require.NoError(t, err, "failed to marshal authz with asn.1 ") // Build a leaf certificate without a DNSSan key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -447,11 +451,11 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { { Id: OIDACMEIdentifier, Critical: true, - Value: []byte(authz), + Value: authz, }, }, BasicConstraintsValid: true, - IsCA: true, + IsCA: false, } certBytes, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key) require.NoError(t, err, "failed to create leaf certificate") @@ -474,7 +478,8 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { // Test case: cert without matching DNSSan // Compute our authorization. checksum := sha256.Sum256([]byte("valid.valid")) - authz := base64.RawURLEncoding.EncodeToString(checksum[:]) + authz, err := asn1.Marshal(checksum[:]) + require.NoError(t, err, "failed to marshal authz with asn.1 ") // Build a leaf certificate which fails validation due to bad DNSName key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -495,11 +500,11 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { { Id: OIDACMEIdentifier, Critical: true, - Value: []byte(authz), + Value: authz, }, }, BasicConstraintsValid: true, - IsCA: true, + IsCA: false, } certBytes, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key) require.NoError(t, err, "failed to create leaf certificate") @@ -522,7 +527,8 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { // Test case: cert with additional SAN // Compute our authorization. checksum := sha256.Sum256([]byte("valid.valid")) - authz := base64.RawURLEncoding.EncodeToString(checksum[:]) + authz, err := asn1.Marshal(checksum[:]) + require.NoError(t, err, "failed to marshal authz with asn.1 ") // Build a leaf certificate which has an invalid additional SAN key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -544,11 +550,11 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { { Id: OIDACMEIdentifier, Critical: true, - Value: []byte(authz), + Value: authz, }, }, BasicConstraintsValid: true, - IsCA: true, + IsCA: false, } certBytes, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key) require.NoError(t, err, "failed to create leaf certificate") @@ -571,7 +577,8 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { // Test case: cert without CN // Compute our authorization. checksum := sha256.Sum256([]byte("valid.valid")) - authz := base64.RawURLEncoding.EncodeToString(checksum[:]) + authz, err := asn1.Marshal(checksum[:]) + require.NoError(t, err, "failed to marshal authz with asn.1 ") // Build a leaf certificate which should pass validation key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -588,11 +595,11 @@ func TestAcmeValidateTLSALPN01Challenge(t *testing.T) { { Id: OIDACMEIdentifier, Critical: true, - Value: []byte(authz), + Value: authz, }, }, BasicConstraintsValid: true, - IsCA: true, + IsCA: false, } certBytes, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key) require.NoError(t, err, "failed to create leaf certificate") diff --git a/builtin/logical/pkiext/pkiext_binary/acme_test.go b/builtin/logical/pkiext/pkiext_binary/acme_test.go index 5cdd146964cf..4081c077de4f 100644 --- a/builtin/logical/pkiext/pkiext_binary/acme_test.go +++ b/builtin/logical/pkiext/pkiext_binary/acme_test.go @@ -12,17 +12,21 @@ import ( "crypto/tls" "crypto/x509" "crypto/x509/pkix" + _ "embed" "encoding/hex" "errors" "fmt" + "html/template" "net" "net/http" "path" + "strings" "testing" "time" "golang.org/x/crypto/acme" + "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/builtin/logical/pkiext" "github.com/hashicorp/vault/helper/testhelpers" "github.com/hashicorp/vault/sdk/helper/certutil" @@ -30,6 +34,15 @@ import ( "github.com/stretchr/testify/require" ) +//go:embed testdata/caddy_http.json +var caddyConfigTemplateHTTP string + +//go:embed testdata/caddy_http_eab.json +var caddyConfigTemplateHTTPEAB string + +//go:embed testdata/caddy_tls_alpn.json +var caddyConfigTemplateTLSALPN string + // Test_ACME will start a Vault cluster using the docker based binary, and execute // a bunch of sub-tests against that cluster. It is up to each sub-test to run/configure // a new pki mount within the cluster to not interfere with each other. @@ -38,6 +51,9 @@ func Test_ACME(t *testing.T) { defer cluster.Cleanup() tc := map[string]func(t *testing.T, cluster *VaultPkiCluster){ + "caddy http": SubtestACMECaddy(caddyConfigTemplateHTTP, false), + "caddy http eab": SubtestACMECaddy(caddyConfigTemplateHTTPEAB, true), + "caddy tls-alpn": SubtestACMECaddy(caddyConfigTemplateTLSALPN, false), "certbot": SubtestACMECertbot, "certbot eab": SubtestACMECertbotEab, "acme ip sans": SubtestACMEIPAndDNS, @@ -65,6 +81,156 @@ func Test_ACME(t *testing.T) { t.Run("step down", func(gt *testing.T) { SubtestACMEStepDownNode(gt, cluster) }) } +// caddyConfig contains information used to render a Caddy configuration file from a template. +type caddyConfig struct { + Hostname string + Directory string + CACert string + EABID string + EABKey string +} + +// SubtestACMECaddy returns an ACME test for Caddy using the provided template. +func SubtestACMECaddy(configTemplate string, enableEAB bool) func(*testing.T, *VaultPkiCluster) { + return func(t *testing.T, cluster *VaultPkiCluster) { + ctx := context.Background() + + // Roll a random run ID for mount and hostname uniqueness. + runID, err := uuid.GenerateUUID() + require.NoError(t, err, "failed to generate a unique ID for test run") + runID = strings.Split(runID, "-")[0] + + // Create the PKI mount with ACME enabled + pki, err := cluster.CreateAcmeMount(runID) + require.NoError(t, err, "failed to set up ACME mount") + + // Conditionally enable EAB and retrieve the key. + var eabID, eabKey string + if enableEAB { + err = pki.UpdateAcmeConfig(true, map[string]interface{}{ + "eab_policy": "new-account-required", + }) + require.NoError(t, err, "failed to configure EAB policy in PKI mount") + + eabID, eabKey, err = pki.GetEabKey("acme/") + require.NoError(t, err, "failed to retrieve EAB key from PKI mount") + } + + directory := fmt.Sprintf("https://%s:8200/v1/%s/acme/directory", pki.GetActiveContainerIP(), runID) + vaultNetwork := pki.GetContainerNetworkName() + t.Logf("dir: %s", directory) + + logConsumer, logStdout, logStderr := getDockerLog(t) + + sleepTimer := "45" + + // Kick off Caddy container. + t.Logf("creating on network: %v", vaultNetwork) + caddyRunner, err := hDocker.NewServiceRunner(hDocker.RunOptions{ + // TODO: Replace with pull-through cache. - schultz + ImageRepo: "library/caddy", + ImageTag: "latest", + ContainerName: fmt.Sprintf("caddy_test_%s", runID), + NetworkName: vaultNetwork, + Ports: []string{"80/tcp", "443/tcp", "443/udp"}, + Entrypoint: []string{"sleep", sleepTimer}, + LogConsumer: logConsumer, + LogStdout: logStdout, + LogStderr: logStderr, + }) + require.NoError(t, err, "failed creating caddy service runner") + + caddyResult, err := caddyRunner.Start(ctx, true, false) + require.NoError(t, err, "could not start Caddy container") + require.NotNil(t, caddyResult, "could not start Caddy container") + + defer caddyRunner.Stop(ctx, caddyResult.Container.ID) + + networks, err := caddyRunner.GetNetworkAndAddresses(caddyResult.Container.ID) + require.NoError(t, err, "could not read caddy container's IP address") + require.Contains(t, networks, vaultNetwork, "expected to contain vault network") + + ipAddr := networks[vaultNetwork] + hostname := fmt.Sprintf("%s.dadgarcorp.com", runID) + + err = pki.AddHostname(hostname, ipAddr) + require.NoError(t, err, "failed to update vault host files") + + // Render the Caddy configuration from the specified template. + tmpl, err := template.New("config").Parse(configTemplate) + require.NoError(t, err, "failed to parse Caddy config template") + var b strings.Builder + err = tmpl.Execute( + &b, + caddyConfig{ + Hostname: hostname, + Directory: directory, + CACert: "/tmp/vault_ca_cert.crt", + EABID: eabID, + EABKey: eabKey, + }, + ) + require.NoError(t, err, "failed to render Caddy config template") + + // Push the Caddy config and the cluster listener's CA certificate over to the docker container. + cpCtx := hDocker.NewBuildContext() + cpCtx["caddy_config.json"] = hDocker.PathContentsFromString(b.String()) + cpCtx["vault_ca_cert.crt"] = hDocker.PathContentsFromString(string(cluster.GetListenerCACertPEM())) + err = caddyRunner.CopyTo(caddyResult.Container.ID, "/tmp/", cpCtx) + require.NoError(t, err, "failed to copy Caddy config and Vault listener CA certificate to container") + + // Start the Caddy server. + caddyCmd := []string{ + "caddy", + "start", + "--config", "/tmp/caddy_config.json", + } + stdout, stderr, retcode, err := caddyRunner.RunCmdWithOutput(ctx, caddyResult.Container.ID, caddyCmd) + t.Logf("Caddy Start Command: %v\nstdout: %v\nstderr: %v\n", caddyCmd, string(stdout), string(stderr)) + require.NoError(t, err, "got error running Caddy start command") + require.Equal(t, 0, retcode, "expected zero retcode Caddy start command result") + + // Start a cURL container. + curlRunner, err := hDocker.NewServiceRunner(hDocker.RunOptions{ + ImageRepo: "docker.mirror.hashicorp.services/curlimages/curl", + ImageTag: "latest", + ContainerName: fmt.Sprintf("curl_test_%s", runID), + NetworkName: vaultNetwork, + Entrypoint: []string{"sleep", sleepTimer}, + LogConsumer: logConsumer, + LogStdout: logStdout, + LogStderr: logStderr, + }) + require.NoError(t, err, "failed creating cURL service runner") + + curlResult, err := curlRunner.Start(ctx, true, false) + require.NoError(t, err, "could not start cURL container") + require.NotNil(t, curlResult, "could not start cURL container") + + // Retrieve the PKI mount CA cert and copy it over to the cURL container. + mountCACert, err := pki.GetCACertPEM() + require.NoError(t, err, "failed to retrieve PKI mount CA certificate") + + mountCACertCtx := hDocker.NewBuildContext() + mountCACertCtx["ca_cert.crt"] = hDocker.PathContentsFromString(mountCACert) + err = curlRunner.CopyTo(curlResult.Container.ID, "/tmp/", mountCACertCtx) + require.NoError(t, err, "failed to copy PKI mount CA certificate to cURL container") + + // Use cURL to hit the Caddy server and validate that a certificate was retrieved successfully. + curlCmd := []string{ + "curl", + "-L", + "--cacert", "/tmp/ca_cert.crt", + "--resolve", hostname + ":443:" + ipAddr, + "https://" + hostname + "/", + } + stdout, stderr, retcode, err = curlRunner.RunCmdWithOutput(ctx, curlResult.Container.ID, curlCmd) + t.Logf("cURL Command: %v\nstdout: %v\nstderr: %v\n", curlCmd, string(stdout), string(stderr)) + require.NoError(t, err, "got error running cURL command") + require.Equal(t, 0, retcode, "expected zero retcode cURL command result") + } +} + func SubtestACMECertbot(t *testing.T, cluster *VaultPkiCluster) { pki, err := cluster.CreateAcmeMount("pki") require.NoError(t, err, "failed setting up acme mount") diff --git a/builtin/logical/pkiext/pkiext_binary/pki_cluster.go b/builtin/logical/pkiext/pkiext_binary/pki_cluster.go index da33300934ba..9f6a19f7bd36 100644 --- a/builtin/logical/pkiext/pkiext_binary/pki_cluster.go +++ b/builtin/logical/pkiext/pkiext_binary/pki_cluster.go @@ -109,6 +109,11 @@ func (vpc *VaultPkiCluster) GetActiveNode() *api.Client { return vpc.GetActiveClusterNode().APIClient() } +// GetListenerCACertPEM returns the Vault cluster's PEM-encoded CA certificate. +func (vpc *VaultPkiCluster) GetListenerCACertPEM() []byte { + return vpc.cluster.CACertPEM +} + func (vpc *VaultPkiCluster) AddHostname(hostname, ip string) error { if vpc.Dns != nil { vpc.Dns.AddRecord(hostname, "A", ip) diff --git a/builtin/logical/pkiext/pkiext_binary/pki_mount.go b/builtin/logical/pkiext/pkiext_binary/pki_mount.go index f949cb6ae56a..770b7ac356db 100644 --- a/builtin/logical/pkiext/pkiext_binary/pki_mount.go +++ b/builtin/logical/pkiext/pkiext_binary/pki_mount.go @@ -133,6 +133,16 @@ func (vpm *VaultPkiMount) GetEabKey(acmeDirectory string) (string, string, error return eabId, base64EabKey, nil } +// GetCACertPEM retrieves the PKI mount's PEM-encoded CA certificate. +func (vpm *VaultPkiMount) GetCACertPEM() (string, error) { + caCertPath := path.Join(vpm.mount, "/cert/ca") + resp, err := vpm.GetActiveNode().Logical().ReadWithContext(context.Background(), caCertPath) + if err != nil { + return "", err + } + return resp.Data["certificate"].(string), nil +} + func mergeWithDefaults(config map[string]interface{}, defaults map[string]interface{}) map[string]interface{} { myConfig := config if myConfig == nil { diff --git a/builtin/logical/pkiext/pkiext_binary/testdata/caddy_http.json b/builtin/logical/pkiext/pkiext_binary/testdata/caddy_http.json new file mode 100644 index 000000000000..272ecd102575 --- /dev/null +++ b/builtin/logical/pkiext/pkiext_binary/testdata/caddy_http.json @@ -0,0 +1,66 @@ +{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":80", + ":443" + ], + "routes": [ + { + "match": [ + { + "host": [ + "{{.Hostname}}" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "Hello!", + "handler": "static_response" + } + ] + } + ] + } + ], + "terminal": true + } + ] + } + } + }, + "tls": { + "automation": { + "policies": [ + { + "subjects": [ + "{{.Hostname}}" + ], + "issuers": [ + { + "ca": "{{.Directory}}", + "module": "acme", + "challenges": { + "tls-alpn": { + "disabled": true + } + }, + "trusted_roots_pem_files": [ + "{{.CACert}}" + ] + } + ] + } + ] + } + } + } +} diff --git a/builtin/logical/pkiext/pkiext_binary/testdata/caddy_http_eab.json b/builtin/logical/pkiext/pkiext_binary/testdata/caddy_http_eab.json new file mode 100644 index 000000000000..61cab8894958 --- /dev/null +++ b/builtin/logical/pkiext/pkiext_binary/testdata/caddy_http_eab.json @@ -0,0 +1,70 @@ +{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":80", + ":443" + ], + "routes": [ + { + "match": [ + { + "host": [ + "{{.Hostname}}" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "Hello!", + "handler": "static_response" + } + ] + } + ] + } + ], + "terminal": true + } + ] + } + } + }, + "tls": { + "automation": { + "policies": [ + { + "subjects": [ + "{{.Hostname}}" + ], + "issuers": [ + { + "ca": "{{.Directory}}", + "module": "acme", + "external_account": { + "key_id": "{{.EABID}}", + "mac_key": "{{.EABKey}}" + }, + "challenges": { + "tls-alpn": { + "disabled": true + } + }, + "trusted_roots_pem_files": [ + "{{.CACert}}" + ] + } + ] + } + ] + } + } + } +} diff --git a/builtin/logical/pkiext/pkiext_binary/testdata/caddy_tls_alpn.json b/builtin/logical/pkiext/pkiext_binary/testdata/caddy_tls_alpn.json new file mode 100644 index 000000000000..0bc0ea9112e8 --- /dev/null +++ b/builtin/logical/pkiext/pkiext_binary/testdata/caddy_tls_alpn.json @@ -0,0 +1,66 @@ +{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":80", + ":443" + ], + "routes": [ + { + "match": [ + { + "host": [ + "{{.Hostname}}" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "Hello!", + "handler": "static_response" + } + ] + } + ] + } + ], + "terminal": true + } + ] + } + } + }, + "tls": { + "automation": { + "policies": [ + { + "subjects": [ + "{{.Hostname}}" + ], + "issuers": [ + { + "ca": "{{.Directory}}", + "module": "acme", + "challenges": { + "http": { + "disabled": true + } + }, + "trusted_roots_pem_files": [ + "{{.CACert}}" + ] + } + ] + } + ] + } + } + } +}