mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 11:38:02 +00:00
Adds automated ACME tests using Caddy. (#21277)
* Adds automated ACME tests using Caddy. * Do not use CheckSignatureFrom method to validate TLS-ALPN-01 challenges * Uncomment TLS-ALPN test. * Fix validation of tls-alpn-01 keyAuthz Surprisingly, this failure was not caught by our earlier, but unmerged acme.sh tests: > 2023-06-07T19:35:27.6963070Z [32mPASS[0m builtin/logical/pkiext/pkiext_binary.Test_ACME/group/acme.sh_tls-alpn (33.06s) from https://github.com/hashicorp/vault/pull/20987. Notably, we had two failures: 1. The extension's raw value is not used, but is instead an OCTET STRING encoded version: > The extension has the following ASN.1 [X.680] format : > > Authorization ::= OCTET STRING (SIZE (32)) > > The extnValue of the id-pe-acmeIdentifier extension is the ASN.1 > DER encoding [X.690] of the Authorization structure, which > contains the SHA-256 digest of the key authorization for the > challenge. 2. Unlike DNS, the SHA-256 is directly embedded in the authorization, as evidenced by the `SIZE (32)` annotation in the quote above: we were instead expecting this to be url base-64 encoded, which would have a different size. This failure was caught by Matt, testing with Caddy. :-) Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Quick gofmt run. * Fix challenge encoding in TLS-ALPN-01 challenge tests * Rename a PKI test helper that retrieves the Vault cluster listener's cert to distinguish it from the method that retrieves the PKI mount's CA cert. Combine a couple of Docker file copy commands into one. --------- Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> Co-authored-by: Steve Clark <steven.clark@hashicorp.com> Co-authored-by: Alexander Scheel <alex.scheel@hashicorp.com>
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
66
builtin/logical/pkiext/pkiext_binary/testdata/caddy_http.json
vendored
Normal file
66
builtin/logical/pkiext/pkiext_binary/testdata/caddy_http.json
vendored
Normal file
@@ -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}}"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
builtin/logical/pkiext/pkiext_binary/testdata/caddy_http_eab.json
vendored
Normal file
70
builtin/logical/pkiext/pkiext_binary/testdata/caddy_http_eab.json
vendored
Normal file
@@ -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}}"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
builtin/logical/pkiext/pkiext_binary/testdata/caddy_tls_alpn.json
vendored
Normal file
66
builtin/logical/pkiext/pkiext_binary/testdata/caddy_tls_alpn.json
vendored
Normal file
@@ -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}}"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user