diff --git a/factory/gen.go b/factory/gen.go index cbe34fe..0def051 100644 --- a/factory/gen.go +++ b/factory/gen.go @@ -19,7 +19,7 @@ import ( const ( cnPrefix = "listener.cattle.io/cn-" - static = "listener.cattle.io/static" + Static = "listener.cattle.io/static" hashKey = "listener.cattle.io/hash" ) @@ -122,7 +122,7 @@ func populateCN(secret *v1.Secret, cn ...string) *v1.Secret { } func NeedsUpdate(secret *v1.Secret, cn ...string) bool { - if secret.Annotations[static] == "true" { + if secret.Annotations[Static] == "true" { return false } diff --git a/listener.go b/listener.go index f3e84f3..86b4e58 100644 --- a/listener.go +++ b/listener.go @@ -19,8 +19,13 @@ type TLSStorage interface { Update(secret *v1.Secret) error } +type TLSFactory interface { + AddCN(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error) + Merge(secret *v1.Secret, existing *v1.Secret) (*v1.Secret, bool, error) +} + type SetFactory interface { - SetFactory(tls *factory.TLS) + SetFactory(tls TLSFactory) } type Config struct { @@ -63,7 +68,7 @@ type listener struct { sync.RWMutex net.Listener - factory *factory.TLS + factory TLSFactory storage TLSStorage version string tlsConfig tls.Config diff --git a/server/server.go b/server/server.go index cf069df..2b793cc 100644 --- a/server/server.go +++ b/server/server.go @@ -2,6 +2,8 @@ package server import ( "context" + "crypto" + "crypto/x509" "fmt" "net/http" @@ -11,15 +13,36 @@ import ( "github.com/sirupsen/logrus" ) -func ListenAndServe(ctx context.Context, httpsPort, httpPort int, handler http.Handler) error { +type ListenOpts struct { + CA *x509.Certificate + CAKey crypto.Signer + Storage dynamiclistener.TLSStorage +} + +func ListenAndServe(ctx context.Context, httpsPort, httpPort int, handler http.Handler, opts *ListenOpts) error { var ( // https listener will change this if http is enabled targetHandler = handler ) + + if opts == nil { + opts = &ListenOpts{} + } + if httpsPort > 0 { - caCert, caKey, err := factory.LoadOrGenCA() - if err != nil { - return err + var ( + caCert *x509.Certificate + caKey crypto.Signer + err error + ) + + if opts.CA != nil && opts.CAKey != nil { + caCert, caKey = opts.CA, opts.CAKey + } else { + caCert, caKey, err = factory.LoadOrGenCA() + if err != nil { + return err + } } tlsTCPListener, err := dynamiclistener.NewTCPListener("0.0.0.0", httpsPort) @@ -27,7 +50,12 @@ func ListenAndServe(ctx context.Context, httpsPort, httpPort int, handler http.H return err } - dynListener, dynHandler, err := dynamiclistener.NewListener(tlsTCPListener, memory.New(), caCert, caKey, dynamiclistener.Config{}) + storage := opts.Storage + if storage == nil { + storage = memory.New() + } + + dynListener, dynHandler, err := dynamiclistener.NewListener(tlsTCPListener, storage, caCert, caKey, dynamiclistener.Config{}) if err != nil { return err } diff --git a/storage/kubernetes/controller.go b/storage/kubernetes/controller.go index 0c91e75..ac435ed 100644 --- a/storage/kubernetes/controller.go +++ b/storage/kubernetes/controller.go @@ -6,7 +6,6 @@ import ( "time" "github.com/rancher/dynamiclistener" - "github.com/rancher/dynamiclistener/factory" "github.com/rancher/wrangler-api/pkg/generated/controllers/core" v1controller "github.com/rancher/wrangler-api/pkg/generated/controllers/core/v1" "github.com/rancher/wrangler/pkg/start" @@ -19,6 +18,17 @@ import ( type CoreGetter func() *core.Factory +func Load(ctx context.Context, secrets v1controller.SecretController, namespace, name string, backing dynamiclistener.TLSStorage) dynamiclistener.TLSStorage { + storage := &storage{ + name: name, + namespace: namespace, + storage: backing, + ctx: ctx, + } + storage.init(secrets) + return storage +} + func New(ctx context.Context, core CoreGetter, namespace, name string, backing dynamiclistener.TLSStorage) dynamiclistener.TLSStorage { storage := &storage{ name: name, @@ -55,10 +65,10 @@ type storage struct { storage dynamiclistener.TLSStorage secrets v1controller.SecretClient ctx context.Context - tls *factory.TLS + tls dynamiclistener.TLSFactory } -func (s *storage) SetFactory(tls *factory.TLS) { +func (s *storage) SetFactory(tls dynamiclistener.TLSFactory) { s.tls = tls } diff --git a/storage/static/static.go b/storage/static/static.go new file mode 100644 index 0000000..be8f64f --- /dev/null +++ b/storage/static/static.go @@ -0,0 +1,36 @@ +package static + +import ( + "github.com/rancher/dynamiclistener/factory" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type Storage struct { + Secret *v1.Secret +} + +func New(certPem, keyPem []byte) *Storage { + return &Storage{ + Secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + factory.Static: "true", + }, + }, + Data: map[string][]byte{ + v1.TLSCertKey: certPem, + v1.TLSPrivateKeyKey: keyPem, + }, + Type: v1.SecretTypeTLS, + }, + } +} + +func (s *Storage) Get() (*v1.Secret, error) { + return s.Secret, nil +} + +func (s *Storage) Update(_ *v1.Secret) error { + return nil +}