diff options
author | Martin Polden <mpolden@mpolden.no> | 2023-04-13 15:21:18 +0200 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2023-04-17 10:31:40 +0200 |
commit | 96d8aae1ec9b4f6130b6b610ce23d2bbdb79298a (patch) | |
tree | f482eaa488eb5d5925b49d665b29c07ab516ef7f /client/go/internal/cli/cmd/config_test.go | |
parent | cce3b08cbe1864e80d5b9e57891622706b1d8181 (diff) |
Support TLS in custom target
Diffstat (limited to 'client/go/internal/cli/cmd/config_test.go')
-rw-r--r-- | client/go/internal/cli/cmd/config_test.go | 119 |
1 files changed, 112 insertions, 7 deletions
diff --git a/client/go/internal/cli/cmd/config_test.go b/client/go/internal/cli/cmd/config_test.go index 458878b4356..66b65bf402b 100644 --- a/client/go/internal/cli/cmd/config_test.go +++ b/client/go/internal/cli/cmd/config_test.go @@ -2,15 +2,21 @@ package cmd import ( + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" "os" "path/filepath" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/vespa-engine/vespa/client/go/internal/cli/auth/auth0" "github.com/vespa-engine/vespa/client/go/internal/mock" - "github.com/vespa-engine/vespa/client/go/internal/util" "github.com/vespa-engine/vespa/client/go/internal/vespa" ) @@ -166,7 +172,7 @@ func TestReadAPIKey(t *testing.T) { require.Nil(t, err) assert.Equal(t, []byte("foo"), key) - // Cloud CI does not read key from disk as it's not expected to have any + // Cloud CI never reads key from disk as it's not expected to have any cli, _, _ = newTestCLI(t, "VESPA_CLI_CLOUD_CI=true") key, err = cli.config.readAPIKey(cli, vespa.PublicSystem, "t1") require.Nil(t, err) @@ -186,12 +192,111 @@ func TestReadAPIKey(t *testing.T) { require.Nil(t, err) assert.Equal(t, []byte("baz"), key) - // Auth0 is preferred when configured + // Prefer Auth0 if we have auth config cli, _, _ = newTestCLI(t) - cli.auth0Factory = func(httpClient util.HTTPClient, options auth0.Options) (auth0Client, error) { - return &mockAuth0{hasCredentials: true}, nil - } + require.Nil(t, os.WriteFile(filepath.Join(cli.config.homeDir, "auth.json"), []byte("foo"), 0600)) key, err = cli.config.readAPIKey(cli, vespa.PublicSystem, "t1") require.Nil(t, err) assert.Nil(t, key) } + +func TestConfigReadTLSOptions(t *testing.T) { + app := vespa.ApplicationID{Tenant: "t1", Application: "a1", Instance: "i1"} + homeDir := t.TempDir() + + // No environment variables, and no files on disk + assertTLSOptions(t, homeDir, app, vespa.TargetLocal, vespa.TLSOptions{}) + + // A single environment variable is set + assertTLSOptions(t, homeDir, app, vespa.TargetLocal, vespa.TLSOptions{TrustAll: true}, "VESPA_CLI_DATA_PLANE_TRUST_ALL=true") + + // Key pair is provided in-line in environment variables + pemCert, pemKey, keyPair := createKeyPair(t) + assertTLSOptions(t, homeDir, app, + vespa.TargetLocal, + vespa.TLSOptions{ + TrustAll: true, + CACertificate: []byte("cacert"), + KeyPair: []tls.Certificate{keyPair}, + }, + "VESPA_CLI_DATA_PLANE_TRUST_ALL=true", + "VESPA_CLI_DATA_PLANE_CA_CERT=cacert", + "VESPA_CLI_DATA_PLANE_CERT="+string(pemCert), + "VESPA_CLI_DATA_PLANE_KEY="+string(pemKey), + ) + + // Key pair is provided as file paths through environment variables + certFile := filepath.Join(homeDir, "cert") + keyFile := filepath.Join(homeDir, "key") + caCertFile := filepath.Join(homeDir, "cacert") + require.Nil(t, os.WriteFile(certFile, pemCert, 0600)) + require.Nil(t, os.WriteFile(keyFile, pemKey, 0600)) + require.Nil(t, os.WriteFile(caCertFile, []byte("cacert"), 0600)) + assertTLSOptions(t, homeDir, app, + vespa.TargetLocal, + vespa.TLSOptions{ + KeyPair: []tls.Certificate{keyPair}, + CACertificate: []byte("cacert"), + CACertificateFile: caCertFile, + CertificateFile: certFile, + PrivateKeyFile: keyFile, + }, + "VESPA_CLI_DATA_PLANE_CERT_FILE="+certFile, + "VESPA_CLI_DATA_PLANE_KEY_FILE="+keyFile, + "VESPA_CLI_DATA_PLANE_CA_CERT_FILE="+caCertFile, + ) + + // Key pair resides in default paths + defaultCertFile := filepath.Join(homeDir, app.String(), "data-plane-public-cert.pem") + defaultKeyFile := filepath.Join(homeDir, app.String(), "data-plane-private-key.pem") + require.Nil(t, os.WriteFile(defaultCertFile, pemCert, 0600)) + require.Nil(t, os.WriteFile(defaultKeyFile, pemKey, 0600)) + assertTLSOptions(t, homeDir, app, + vespa.TargetLocal, + vespa.TLSOptions{ + KeyPair: []tls.Certificate{keyPair}, + CertificateFile: defaultCertFile, + PrivateKeyFile: defaultKeyFile, + }, + ) +} + +func assertTLSOptions(t *testing.T, homeDir string, app vespa.ApplicationID, target string, want vespa.TLSOptions, envVars ...string) { + t.Helper() + envVars = append(envVars, "VESPA_CLI_HOME="+homeDir) + cli, _, _ := newTestCLI(t, envVars...) + require.Nil(t, cli.Run("config", "set", "application", app.String())) + config, err := cli.config.readTLSOptions(app, vespa.TargetLocal) + require.Nil(t, err) + assert.Equal(t, want, config) +} + +func createKeyPair(t *testing.T) ([]byte, []byte, tls.Certificate) { + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatal(err) + } + notBefore := time.Now() + notAfter := notBefore.Add(24 * time.Hour) + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{CommonName: "example.com"}, + NotBefore: notBefore, + NotAfter: notAfter, + } + certificateDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey) + if err != nil { + t.Fatal(err) + } + privateKeyDER, err := x509.MarshalPKCS8PrivateKey(privateKey) + if err != nil { + t.Fatal(err) + } + pemCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certificateDER}) + pemKey := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privateKeyDER}) + kp, err := tls.X509KeyPair(pemCert, pemKey) + if err != nil { + t.Fatal(err) + } + return pemCert, pemKey, kp +} |