diff options
author | Martin Polden <mpolden@mpolden.no> | 2024-06-12 11:26:23 +0200 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2024-06-12 11:26:23 +0200 |
commit | 17f9406eb10982c8201ace9de673c0d53af98ed0 (patch) | |
tree | f5239da97b2bdc4708b792173a06907c46759741 | |
parent | 15cb97dd996b2e1addd999f5db967e9008339047 (diff) |
Refactor reading of credentials
-rw-r--r-- | client/go/internal/cli/cmd/config.go | 85 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/config_test.go | 17 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/feed.go | 2 | ||||
-rw-r--r-- | client/go/internal/vespa/target.go | 11 |
4 files changed, 76 insertions, 39 deletions
diff --git a/client/go/internal/cli/cmd/config.go b/client/go/internal/cli/cmd/config.go index 77ca2cf8c12..032abfd598a 100644 --- a/client/go/internal/cli/cmd/config.go +++ b/client/go/internal/cli/cmd/config.go @@ -429,51 +429,76 @@ func (c *Config) privateKeyPath(app vespa.ApplicationID, targetType string) (cre return c.credentialsFile(app, targetType, false) } -func (c *Config) readTLSOptions(app vespa.ApplicationID, targetType string) (vespa.TLSOptions, error) { - _, trustAll := c.environment["VESPA_CLI_DATA_PLANE_TRUST_ALL"] - cert, certOk := c.environment["VESPA_CLI_DATA_PLANE_CERT"] - key, keyOk := c.environment["VESPA_CLI_DATA_PLANE_KEY"] - caCertText, caCertOk := c.environment["VESPA_CLI_DATA_PLANE_CA_CERT"] - options := vespa.TLSOptions{TrustAll: trustAll} - // CA certificate +func (c *Config) caCertificatePEM() ([]byte, string, error) { + envVar := "VESPA_CLI_DATA_PLANE_CA_CERT" + caCertText, caCertOk := c.environment[envVar] if caCertOk { - options.CACertificate = []byte(caCertText) - } else if caCertFile := c.caCertificatePath(); caCertFile != "" { + return []byte(caCertText), envVar, nil + } + if caCertFile := c.caCertificatePath(); caCertFile != "" { b, err := os.ReadFile(caCertFile) if err != nil { - return options, err + return nil, "", err + } + return b, caCertFile, nil + } + return nil, "", nil +} + +func (c *Config) credentialsPEM(envVar string, credentialsFile credentialsFile) ([]byte, string, error) { + if pem, ok := c.environment[envVar]; ok { + return []byte(pem), envVar, nil + } + pem, err := os.ReadFile(credentialsFile.path) + if err != nil { + if os.IsNotExist(err) && credentialsFile.optional { + return nil, "", nil } - options.CACertificate = b - options.CACertificateFile = caCertFile + return nil, "", err } - // Certificate and private key - if certOk && keyOk { - kp, err := tls.X509KeyPair([]byte(cert), []byte(key)) + return []byte(pem), credentialsFile.path, nil +} + +func (c *Config) readTLSOptions(app vespa.ApplicationID, targetType string) (vespa.TLSOptions, error) { + var options vespa.TLSOptions + // Certificate + if certPath, err := c.certificatePath(app, targetType); err == nil { + certPEM, certFile, err := c.credentialsPEM("VESPA_CLI_DATA_PLANE_CERT", certPath) if err != nil { return vespa.TLSOptions{}, err } - options.KeyPair = []tls.Certificate{kp} + options.CertificatePEM = certPEM + options.CertificateFile = certFile } else { - keyFile, err := c.privateKeyPath(app, targetType) + return vespa.TLSOptions{}, err + } + // Private key + if keyPath, err := c.privateKeyPath(app, targetType); err == nil { + keyPEM, keyFile, err := c.credentialsPEM("VESPA_CLI_DATA_PLANE_KEY", keyPath) if err != nil { return vespa.TLSOptions{}, err } - certFile, err := c.certificatePath(app, targetType) + options.PrivateKeyPEM = keyPEM + options.PrivateKeyFile = keyFile + } else { + return vespa.TLSOptions{}, err + + } + // CA certificate + _, options.TrustAll = c.environment["VESPA_CLI_DATA_PLANE_TRUST_ALL"] + caCertificate, caCertificateFile, err := c.caCertificatePEM() + if err != nil { + return vespa.TLSOptions{}, err + } + options.CACertificatePEM = caCertificate + options.CACertificateFile = caCertificateFile + // Key pair + if len(options.CertificatePEM) > 0 && len(options.PrivateKeyPEM) > 0 { + kp, err := tls.X509KeyPair(options.CertificatePEM, options.PrivateKeyPEM) if err != nil { return vespa.TLSOptions{}, err } - kp, err := tls.LoadX509KeyPair(certFile.path, keyFile.path) - allowMissing := os.IsNotExist(err) && keyFile.optional && certFile.optional - if err == nil { - options.KeyPair = []tls.Certificate{kp} - options.PrivateKeyFile = keyFile.path - options.CertificateFile = certFile.path - } else if err != nil && !allowMissing { - return vespa.TLSOptions{}, err - } - } - // If we found a key pair, parse it and check expiry - if options.KeyPair != nil { + options.KeyPair = []tls.Certificate{kp} cert, err := x509.ParseCertificate(options.KeyPair[0].Certificate[0]) if err != nil { return vespa.TLSOptions{}, err diff --git a/client/go/internal/cli/cmd/config_test.go b/client/go/internal/cli/cmd/config_test.go index a70766ff931..6c9321b3219 100644 --- a/client/go/internal/cli/cmd/config_test.go +++ b/client/go/internal/cli/cmd/config_test.go @@ -209,9 +209,14 @@ func TestConfigReadTLSOptions(t *testing.T) { assertTLSOptions(t, homeDir, app, vespa.TargetLocal, vespa.TLSOptions{ - TrustAll: true, - CACertificate: []byte("cacert"), - KeyPair: []tls.Certificate{keyPair}, + TrustAll: true, + KeyPair: []tls.Certificate{keyPair}, + CACertificatePEM: []byte("cacert"), + CertificatePEM: pemCert, + PrivateKeyPEM: pemKey, + CACertificateFile: "VESPA_CLI_DATA_PLANE_CA_CERT", + CertificateFile: "VESPA_CLI_DATA_PLANE_CERT", + PrivateKeyFile: "VESPA_CLI_DATA_PLANE_KEY", }, "VESPA_CLI_DATA_PLANE_TRUST_ALL=true", "VESPA_CLI_DATA_PLANE_CA_CERT=cacert", @@ -230,7 +235,9 @@ func TestConfigReadTLSOptions(t *testing.T) { vespa.TargetLocal, vespa.TLSOptions{ KeyPair: []tls.Certificate{keyPair}, - CACertificate: []byte("cacert"), + CACertificatePEM: []byte("cacert"), + CertificatePEM: pemCert, + PrivateKeyPEM: pemKey, CACertificateFile: caCertFile, CertificateFile: certFile, PrivateKeyFile: keyFile, @@ -249,6 +256,8 @@ func TestConfigReadTLSOptions(t *testing.T) { vespa.TargetLocal, vespa.TLSOptions{ KeyPair: []tls.Certificate{keyPair}, + CertificatePEM: pemCert, + PrivateKeyPEM: pemKey, CertificateFile: defaultCertFile, PrivateKeyFile: defaultKeyFile, }, diff --git a/client/go/internal/cli/cmd/feed.go b/client/go/internal/cli/cmd/feed.go index f69de6b3038..e696333a3f1 100644 --- a/client/go/internal/cli/cmd/feed.go +++ b/client/go/internal/cli/cmd/feed.go @@ -143,7 +143,7 @@ func createServices(n int, timeout time.Duration, cli *CLI, waiter *Waiter) ([]h // Create a separate HTTP client for each service client := cli.httpClientFactory(timeout) // Feeding should always use HTTP/2 - httputil.ForceHTTP2(client, service.TLSOptions.KeyPair, service.TLSOptions.CACertificate, service.TLSOptions.TrustAll) + httputil.ForceHTTP2(client, service.TLSOptions.KeyPair, service.TLSOptions.CACertificatePEM, service.TLSOptions.TrustAll) service.SetClient(client) services = append(services, service) } diff --git a/client/go/internal/vespa/target.go b/client/go/internal/vespa/target.go index 960917b75d6..5270b5669f9 100644 --- a/client/go/internal/vespa/target.go +++ b/client/go/internal/vespa/target.go @@ -126,9 +126,12 @@ type Target interface { // TLSOptions holds the client certificate to use for cloud API or service requests. type TLSOptions struct { - CACertificate []byte - KeyPair []tls.Certificate - TrustAll bool + KeyPair []tls.Certificate + TrustAll bool + + CACertificatePEM []byte + CertificatePEM []byte + PrivateKeyPEM []byte CACertificateFile string CertificateFile string @@ -149,7 +152,7 @@ type LogOptions struct { func (s *Service) Do(request *http.Request, timeout time.Duration) (*http.Response, error) { if !s.customClient { // Do not override TLS config if a custom client has been configured - httputil.ConfigureTLS(s.httpClient, s.TLSOptions.KeyPair, s.TLSOptions.CACertificate, s.TLSOptions.TrustAll) + httputil.ConfigureTLS(s.httpClient, s.TLSOptions.KeyPair, s.TLSOptions.CACertificatePEM, s.TLSOptions.TrustAll) } if s.auth != nil { if err := s.auth.Authenticate(request); err != nil { |