From 41a377d26569397c7cd91ff3bdd3599304b0298c Mon Sep 17 00:00:00 2001 From: kvmw Date: Thu, 24 Nov 2022 17:29:54 +0100 Subject: [PATCH] Enable storage server to serve https Signed-off-by: kvmw --- controllers/storage.go | 27 ++++++++++++++----- main.go | 60 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/controllers/storage.go b/controllers/storage.go index 34fea8ac4..e9ab19fd9 100644 --- a/controllers/storage.go +++ b/controllers/storage.go @@ -89,24 +89,30 @@ func (s *Storage) NewArtifactFor(kind string, metadata metav1.Object, revision, } // SetArtifactURL sets the URL on the given v1beta1.Artifact. -func (s Storage) SetArtifactURL(artifact *sourcev1.Artifact) { +func (s *Storage) SetArtifactURL(artifact *sourcev1.Artifact) { if artifact.Path == "" { return } format := "http://%s/%s" - if strings.HasPrefix(s.Hostname, "http://") || strings.HasPrefix(s.Hostname, "https://") { + if s.hasSchemeInHostname() { format = "%s/%s" } artifact.URL = fmt.Sprintf(format, s.Hostname, strings.TrimLeft(artifact.Path, "/")) } // SetHostname sets the hostname of the given URL string to the current Storage.Hostname and returns the result. -func (s Storage) SetHostname(URL string) string { +func (s *Storage) SetHostname(URL string) string { u, err := url.Parse(URL) if err != nil { return "" } - u.Host = s.Hostname + if s.hasSchemeInHostname() { + su, _ := url.Parse(s.Hostname) + u.Host = su.Host + u.Scheme = su.Scheme + } else { + u.Host = s.Hostname + } return u.String() } @@ -602,8 +608,13 @@ func (s *Storage) Symlink(artifact sourcev1.Artifact, linkName string) (string, return "", err } - url := fmt.Sprintf("http://%s/%s", s.Hostname, filepath.Join(filepath.Dir(artifact.Path), linkName)) - return url, nil + format := "http://%s/%s" + if s.hasSchemeInHostname() { + format = "%s/%s" + } + + u := fmt.Sprintf(format, s.Hostname, filepath.Join(filepath.Dir(artifact.Path), linkName)) + return u, nil } // Checksum returns the SHA256 checksum for the data of the given io.Reader as a string. @@ -632,6 +643,10 @@ func (s *Storage) LocalPath(artifact sourcev1.Artifact) string { return path } +func (s *Storage) hasSchemeInHostname() bool { + return strings.HasPrefix(s.Hostname, "http://") || strings.HasPrefix(s.Hostname, "https://") +} + // newHash returns a new SHA256 hash. func newHash() hash.Hash { return sha256.New() diff --git a/main.go b/main.go index 9aec36b20..4b8d1611a 100644 --- a/main.go +++ b/main.go @@ -17,9 +17,11 @@ limitations under the License. package main import ( + "crypto/tls" "fmt" "net" "net/http" + "net/url" "os" "path/filepath" "time" @@ -101,6 +103,8 @@ func main() { helmCachePurgeInterval string artifactRetentionTTL time.Duration artifactRetentionRecords int + storageCertDir string + storageHttpsEnabled bool ) flag.StringVar(&metricsAddr, "metrics-addr", envOrDefault("METRICS_ADDR", ":8080"), @@ -112,6 +116,8 @@ func main() { "The local storage path.") flag.StringVar(&storageAddr, "storage-addr", envOrDefault("STORAGE_ADDR", ":9090"), "The address the static file server binds to.") + flag.BoolVar(&storageHttpsEnabled, "storage-https-enabled", false, "The static server serves https.") + flag.StringVar(&storageCertDir, "storage-cert-path", "", "The path to static server certificate.") flag.StringVar(&storageAdvAddr, "storage-adv-addr", envOrDefault("STORAGE_ADV_ADDR", ""), "The advertised address of the static file server.") flag.IntVar(&concurrent, "concurrent", 2, "The number of concurrent reconciles per controller.") @@ -202,6 +208,9 @@ func main() { if storageAdvAddr == "" { storageAdvAddr = determineAdvStorageAddr(storageAddr, setupLog) } + + storageAdvAddr = appendScheme(storageAdvAddr, storageHttpsEnabled) + storage := mustInitStorage(storagePath, storageAdvAddr, artifactRetentionTTL, artifactRetentionRecords, setupLog) if gogitOnly, _ := features.Enabled(features.ForceGoGitImplementation); !gogitOnly { @@ -332,7 +341,7 @@ func main() { // to handle that. <-mgr.Elected() - startFileServer(storage.BasePath, storageAddr, setupLog) + startFileServer(storage.BasePath, storageAddr, storageHttpsEnabled, storageCertDir, setupLog) }() setupLog.Info("starting manager") @@ -342,13 +351,37 @@ func main() { } } -func startFileServer(path string, address string, l logr.Logger) { +func getCertificateLoader(certDir string) func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + return func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { + crt := fmt.Sprintf("%s/%s", certDir, "tls.crt") + key := fmt.Sprintf("%s/%s", certDir, "tls.key") + + certificate, err := tls.LoadX509KeyPair(crt, key) + return &certificate, err + } +} + +func startFileServer(path string, address string, enableHttpsStorage bool, certDir string, l logr.Logger) { l.Info("starting file server") - fs := http.FileServer(http.Dir(path)) - http.Handle("/", fs) - err := http.ListenAndServe(address, nil) - if err != nil { - l.Error(err, "file server error") + + server := http.Server{ + Addr: address, + Handler: http.FileServer(http.Dir(path)), + TLSConfig: &tls.Config{ + GetCertificate: getCertificateLoader(certDir), + }, + } + + if enableHttpsStorage { + err := server.ListenAndServeTLS("", "") + if err != nil { + l.Error(err, "https file server error") + } + } else { + err := server.ListenAndServe() + if err != nil { + l.Error(err, "http file server error") + } } } @@ -391,6 +424,19 @@ func determineAdvStorageAddr(storageAddr string, l logr.Logger) string { return net.JoinHostPort(host, port) } +func appendScheme(storageAdvAddr string, enableHttpsStorage bool) string { + u, err := url.Parse(storageAdvAddr) + if err != nil { + return storageAdvAddr + } + + u.Scheme = "http" + if enableHttpsStorage { + u.Scheme = "https" + } + return u.String() +} + func envOrDefault(envName, defaultValue string) string { ret := os.Getenv(envName) if ret != "" {