// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package cluster import ( "bytes" "crypto/rand" "encoding/base64" "fmt" "github.com/hashicorp/consul/sdk/testutil/retry" "io" "path/filepath" "testing" "github.com/hashicorp/go-uuid" "github.com/pkg/errors" "github.com/stretchr/testify/require" "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" ) const ( certVolumePrefix = "test-container-certs-" consulUID = "100" consulGID = "1000" consulUserArg = consulUID + ":" + consulGID ) func newSerfEncryptionKey() (string, error) { key := make([]byte, 32) n, err := rand.Reader.Read(key) if err != nil { return "", errors.Wrap(err, "error reading random data") } if n != 32 { return "", errors.Wrap(err, "couldn't read enough entropy. Generate more entropy!") } return base64.StdEncoding.EncodeToString(key), nil } func (c *BuildContext) createTLSCAFiles(t *testing.T) { id, err := uuid.GenerateUUID() require.NoError(t, err, "could not create cert volume UUID") c.certVolume = certVolumePrefix + id // TODO: cleanup anything with the prefix? retry.Run(t, func(r *retry.R) { // Create a volume to hold the data. err = utils.DockerExec([]string{"volume", "create", c.certVolume}, io.Discard) require.NoError(r, err, "could not create docker volume to hold cert data: %s", c.certVolume) }) t.Cleanup(func() { _ = utils.DockerExec([]string{"volume", "rm", c.certVolume}, io.Discard) }) retry.Run(t, func(r *retry.R) { err := utils.DockerExec([]string{"run", "--rm", "-i", "--net=none", "-v", c.certVolume + ":/data", "busybox:latest", "sh", "-c", // Need this so the permissions stick; docker seems to treat unused volumes differently. `touch /data/VOLUME_PLACEHOLDER && chown -R ` + consulUserArg + ` /data`, }, io.Discard) require.NoError(r, err, "could not initialize docker volume for cert data: %s", c.certVolume) }) retry.Run(t, func(r *retry.R) { err = utils.DockerExec([]string{"run", "--rm", "-i", "--net=none", "-u", consulUserArg, "-v", c.certVolume + ":/data", "-w", "/data", "--entrypoint", "", c.DockerImage(), "consul", "tls", "ca", "create", }, io.Discard) require.NoError(r, err, "could not create TLS certificate authority in docker volume: %s", c.certVolume) }) var w bytes.Buffer retry.Run(t, func(r *retry.R) { err = utils.DockerExec([]string{"run", "--rm", "-i", "--net=none", "-u", consulUserArg, "-v", c.certVolume + ":/data", "-w", "/data", "--entrypoint", "", c.DockerImage(), "cat", filepath.Join("/data", ConsulCACertPEM), }, &w) require.NoError(r, err, "could not extract TLS CA certificate authority public key from docker volume: %s", c.certVolume) }) c.caCert = w.String() } func (c *BuildContext) createTLSCertFiles(t *testing.T, dc string) (keyFileName, certFileName string) { require.NotEmpty(t, "the CA has not been initialized yet") retry.Run(t, func(r *retry.R) { err := utils.DockerExec([]string{"run", "--rm", "-i", "--net=none", "-u", consulUserArg, "-v", c.certVolume + ":/data", "-w", "/data", "--entrypoint", "", c.DockerImage(), "consul", "tls", "cert", "create", "-server", "-dc", dc, }, io.Discard) require.NoError(r, err, "could not create TLS server certificate dc=%q in docker volume: %s", dc, c.certVolume) }) prefix := fmt.Sprintf("%s-server-%s", dc, "consul") certFileName = fmt.Sprintf("%s-%d.pem", prefix, c.tlsCertIndex) keyFileName = fmt.Sprintf("%s-%d-key.pem", prefix, c.tlsCertIndex) retry.Run(t, func(r *retry.R) { for _, fn := range []string{certFileName, keyFileName} { err := utils.DockerExec([]string{"run", "--rm", "-i", "--net=none", "-u", consulUserArg, "-v", c.certVolume + ":/data:ro", "-w", "/data", "--entrypoint", "", c.DockerImage(), "stat", filepath.Join("/data", fn), }, io.Discard) require.NoError(r, err, "Generated TLS cert file %q does not exist in volume", fn) } }) return keyFileName, certFileName }