From 260fe2169b8a9fc607a23d4f56d50c855ce6f336 Mon Sep 17 00:00:00 2001 From: Avi Zimmerman Date: Sun, 9 Jul 2023 20:55:56 +0300 Subject: [PATCH] Allow inline TLS data in store configuration --- pkg/store/options.go | 28 +++++++++++++++++++++++++++- pkg/store/options_auth.go | 14 ++++++++++---- pkg/store/options_tls.go | 4 +++- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/pkg/store/options.go b/pkg/store/options.go index 3aa23fed6..4158baa05 100644 --- a/pkg/store/options.go +++ b/pkg/store/options.go @@ -19,6 +19,7 @@ package store import ( "crypto/tls" "crypto/x509" + "encoding/base64" "flag" "fmt" "os" @@ -113,12 +114,28 @@ func (o *Options) TLSConfig() (*tls.Config, error) { } var config tls.Config if o.Auth != nil && o.Auth.MTLS != nil { + config.Certificates = []tls.Certificate{} if o.Auth.MTLS.CertFile != "" && o.Auth.MTLS.KeyFile != "" { cert, err := tls.LoadX509KeyPair(o.Auth.MTLS.CertFile, o.Auth.MTLS.KeyFile) if err != nil { return nil, fmt.Errorf("load x509 key pair: %w", err) } - config.Certificates = []tls.Certificate{cert} + config.Certificates = append(config.Certificates, cert) + } + if o.Auth.MTLS.CertData != "" && o.Auth.MTLS.KeyData != "" { + cert, err := base64.StdEncoding.DecodeString(o.Auth.MTLS.CertData) + if err != nil { + return nil, fmt.Errorf("decode cert data: %w", err) + } + key, err := base64.StdEncoding.DecodeString(o.Auth.MTLS.KeyData) + if err != nil { + return nil, fmt.Errorf("decode key data: %w", err) + } + tlscert, err := tls.X509KeyPair(cert, key) + if err != nil { + return nil, fmt.Errorf("x509 key pair: %w", err) + } + config.Certificates = append(config.Certificates, tlscert) } } pool, err := x509.SystemCertPool() @@ -135,6 +152,15 @@ func (o *Options) TLSConfig() (*tls.Config, error) { return nil, fmt.Errorf("append certs from pem") } } + if o.TLS.CAData != "" { + data, err := base64.StdEncoding.DecodeString(o.TLS.CAData) + if err != nil { + return nil, fmt.Errorf("decode ca data: %w", err) + } + if ok := pool.AppendCertsFromPEM(data); !ok { + return nil, fmt.Errorf("append certs from pem") + } + } config.RootCAs = pool if o.TLS.VerifyChainOnly { config.InsecureSkipVerify = true diff --git a/pkg/store/options_auth.go b/pkg/store/options_auth.go index 7627bf1c9..77d69489a 100644 --- a/pkg/store/options_auth.go +++ b/pkg/store/options_auth.go @@ -42,10 +42,16 @@ type AuthOptions struct { // MTLSOptions are options for mutual TLS. type MTLSOptions struct { - // TLSCertFile is the path to a TLS certificate file to present when joining. + // CertFile is the path to a TLS certificate file to present when joining. Either this + // or CertData must be set. CertFile string `yaml:"cert-file,omitempty" json:"cert-file,omitempty" toml:"cert-file,omitempty"` - // TLSKeyFile is the path to a TLS key file for the certificate. + // CertData is the base64 encoded TLS certificate data to present when joining. Either this + // or CertFile must be set. + CertData string `yaml:"cert-data,omitempty" json:"cert-data,omitempty" toml:"cert-data,omitempty"` + // KeyFile is the path to a TLS key file for the certificate. Either this or KeyData must be set. KeyFile string `yaml:"key-file,omitempty" json:"key-file,omitempty" toml:"tls-file,omitempty"` + // KeyData is the base64 encoded TLS key data for the certificate. Either this or KeyFile must be set. + KeyData string `yaml:"key-data,omitempty" json:"key-data,omitempty" toml:"tls-data,omitempty"` } // BasicAuthOptions are options for basic authentication. @@ -120,10 +126,10 @@ func (o *AuthOptions) Validate() error { return nil } if o.MTLS != nil { - if o.MTLS.CertFile == "" { + if o.MTLS.CertFile == "" && o.MTLS.CertData == "" { return errors.New("auth.mtls.cert-file is required") } - if o.MTLS.KeyFile == "" { + if o.MTLS.KeyFile == "" && o.MTLS.KeyData == "" { return errors.New("auth.mtls.key-file is required") } } diff --git a/pkg/store/options_tls.go b/pkg/store/options_tls.go index 6f6abfdc2..faacf7854 100644 --- a/pkg/store/options_tls.go +++ b/pkg/store/options_tls.go @@ -31,8 +31,10 @@ const ( // TLSOptions are options for TLS communication when joining a mesh. type TLSOptions struct { - // TLSCAFile is the path to a TLS CA file for verification. If empty, the system CA pool is used. + // CAFile is the path to a TLS CA file for verification. If this and CAData are empty, the system CA pool is used. CAFile string `yaml:"tls-ca-file,omitempty" json:"tls-ca-file,omitempty" toml:"tls-ca-file,omitempty"` + // CAData is the base64 encoded TLS CA data for verification. If this and CAFile are empty, the system CA pool is used. + CAData string `yaml:"tls-ca-data,omitempty" json:"tls-ca-data,omitempty" toml:"tls-ca-data,omitempty"` // VerifyChainOnly is true if only the certificate chain should be verified. VerifyChainOnly bool `yaml:"verify-chain-only,omitempty" json:"verify-chain-only,omitempty" toml:"verify-chain-only,omitempty"` // InsecureSkipVerify is true if the server TLS cert should not be verified.