Skip to content

Commit

Permalink
Add certwatcher for TLS cert and key from controller-runtime
Browse files Browse the repository at this point in the history
- Add error for missing either tls-key or tls-cert arguments.
- Move server creation and configuration to serverutil

Signed-off-by: Tayler Geiger <[email protected]>
  • Loading branch information
trgeiger committed May 10, 2024
1 parent d34081c commit fa4bb3c
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 49 deletions.
75 changes: 26 additions & 49 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ limitations under the License.
package main

import (
"crypto/tls"
"flag"
"fmt"
"net"
"net/http"
"net/url"
"os"
"path/filepath"
Expand All @@ -41,8 +38,8 @@ import (

"github.com/operator-framework/catalogd/api/core/v1alpha1"
"github.com/operator-framework/catalogd/internal/garbagecollection"
"github.com/operator-framework/catalogd/internal/serverutil"
"github.com/operator-framework/catalogd/internal/source"
"github.com/operator-framework/catalogd/internal/third_party/server"
"github.com/operator-framework/catalogd/internal/version"
corecontrollers "github.com/operator-framework/catalogd/pkg/controllers/core"
"github.com/operator-framework/catalogd/pkg/features"
Expand Down Expand Up @@ -78,7 +75,6 @@ func main() {
gcInterval time.Duration
certFile string
keyFile string
listener net.Listener
)
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
Expand All @@ -92,8 +88,8 @@ func main() {
flag.StringVar(&cacheDir, "cache-dir", "/var/cache/", "The directory in the filesystem that catalogd will use for file based caching")
flag.BoolVar(&catalogdVersion, "version", false, "print the catalogd version and exit")
flag.DurationVar(&gcInterval, "gc-interval", 12*time.Hour, "interval in which garbage collection should be run against the catalog content cache")
flag.StringVar(&certFile, "tls-cert", "", "The certificate file used for serving catalog contents over HTTPS")
flag.StringVar(&keyFile, "tls-key", "", "The key file used for serving catalog contents over HTTPS")
flag.StringVar(&certFile, "tls-cert", "", "The certificate file used for serving catalog contents over HTTPS. Requires tls-key.")
flag.StringVar(&keyFile, "tls-key", "", "The key file used for serving catalog contents over HTTPS. Requires tls-cert.")
opts := zap.Options{
Development: true,
}
Expand All @@ -110,6 +106,18 @@ func main() {
}

ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

if (certFile != "" && keyFile == "") || (certFile == "" && keyFile != "") {
setupLog.Error(nil, "unable to configure TLS certificates: tls-cert and tls-key flags must be used together")
os.Exit(1)
}

protocol := "http://"
if certFile != "" && keyFile != "" {
protocol = "https://"
}
externalAddr = protocol + externalAddr

cfg := ctrl.GetConfigOrDie()
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme,
Expand Down Expand Up @@ -150,56 +158,25 @@ func main() {
os.Exit(1)
}

if certFile != "" && keyFile != "" {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
setupLog.Error(err, "unable to load certificate key pair")
os.Exit(1)
}
config := &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS13,
}
listener, err = tls.Listen("tcp", catalogServerAddr, config)
if err != nil {
setupLog.Error(err, "unable to create HTTPS server listener")
os.Exit(1)
}
externalAddr = "https://" + externalAddr
} else {
listener, err = net.Listen("tcp", catalogServerAddr)
if err != nil {
setupLog.Error(err, "unable to create HTTP server listener")
os.Exit(1)
}
externalAddr = "http://" + externalAddr
}

baseStorageURL, err := url.Parse(fmt.Sprintf("%s/catalogs/", externalAddr))
if err != nil {
setupLog.Error(err, "unable to create base storage URL")
os.Exit(1)
}

localStorage = storage.LocalDir{RootDir: storeDir, BaseURL: baseStorageURL}
shutdownTimeout := 30 * time.Second

catalogServer := server.Server{
Kind: "catalogs",
Server: &http.Server{
Addr: catalogServerAddr,
Handler: catalogdmetrics.AddMetricsToHandler(localStorage.StorageServerHandler()),
ReadTimeout: 5 * time.Second,
// TODO: Revert this to 10 seconds if/when the API
// evolves to have significantly smaller responses
WriteTimeout: 5 * time.Minute,
},
ShutdownTimeout: &shutdownTimeout,
Listener: listener,

catalogServerConfig := serverutil.CatalogServerConfig{
ExternalAddr: externalAddr,
CatalogAddr: catalogServerAddr,
CertFile: certFile,
KeyFile: keyFile,
LocalStorage: localStorage,
}

if err := mgr.Add(&catalogServer); err != nil {
setupLog.Error(err, "unable to start catalog server")
err = serverutil.AddCatalogServerToManager(mgr, catalogServerConfig)
if err != nil {
setupLog.Error(err, "unable to add catalog server to manager")
os.Exit(1)
}

Expand Down Expand Up @@ -236,7 +213,7 @@ func main() {
Interval: gcInterval,
}
if err := mgr.Add(gc); err != nil {
setupLog.Error(err, "problem adding garbage collector to manager")
setupLog.Error(err, "unable to add garbage collector to manager")
os.Exit(1)
}

Expand Down
69 changes: 69 additions & 0 deletions internal/serverutil/serverutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package serverutil

import (
"crypto/tls"
"net"
"net/http"
"time"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"

"github.com/operator-framework/catalogd/internal/third_party/server"
catalogdmetrics "github.com/operator-framework/catalogd/pkg/metrics"
"github.com/operator-framework/catalogd/pkg/storage"
)

type CatalogServerConfig struct {
ExternalAddr string
CatalogAddr string
CertFile string
KeyFile string
LocalStorage storage.Instance
}

func AddCatalogServerToManager(mgr ctrl.Manager, cfg CatalogServerConfig) error {
listener, err := net.Listen("tcp", cfg.CatalogAddr)
if err != nil {
return err
}

if cfg.CertFile != "" && cfg.KeyFile != "" {
tlsFileWatcher, err := certwatcher.New(cfg.CertFile, cfg.KeyFile)
if err != nil {
return err
}
config := &tls.Config{
GetCertificate: tlsFileWatcher.GetCertificate,
MinVersion: tls.VersionTLS12,
}
err = mgr.Add(tlsFileWatcher)
if err != nil {
return err
}
listener = tls.NewListener(listener, config)
}

shutdownTimeout := 30 * time.Second

catalogServer := server.Server{
Kind: "catalogs",
Server: &http.Server{
Addr: cfg.CatalogAddr,
Handler: catalogdmetrics.AddMetricsToHandler(cfg.LocalStorage.StorageServerHandler()),
ReadTimeout: 5 * time.Second,
// TODO: Revert this to 10 seconds if/when the API
// evolves to have significantly smaller responses
WriteTimeout: 5 * time.Minute,
},
ShutdownTimeout: &shutdownTimeout,
Listener: listener,
}

err = mgr.Add(&catalogServer)
if err != nil {
return err
}

return nil
}

0 comments on commit fa4bb3c

Please sign in to comment.