feat: Allow external usage of secret and proxy modules (#113)

This commit is contained in:
Marc-Antoine 2022-12-09 06:49:43 +01:00 committed by GitHub
parent f858a1e4cd
commit a0a0af8c57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 48 deletions

View File

@ -11,7 +11,6 @@ import (
"github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2"
"github.com/caddyserver/certmagic" "github.com/caddyserver/certmagic"
"github.com/caddyserver/ingress/internal/k8s" "github.com/caddyserver/ingress/internal/k8s"
"github.com/caddyserver/ingress/pkg/storage"
"github.com/caddyserver/ingress/pkg/store" "github.com/caddyserver/ingress/pkg/store"
"go.uber.org/zap" "go.uber.org/zap"
apiv1 "k8s.io/api/core/v1" apiv1 "k8s.io/api/core/v1"
@ -28,6 +27,7 @@ import (
_ "github.com/caddyserver/caddy/v2/modules/caddytls/standardstek" _ "github.com/caddyserver/caddy/v2/modules/caddytls/standardstek"
_ "github.com/caddyserver/caddy/v2/modules/metrics" _ "github.com/caddyserver/caddy/v2/modules/metrics"
_ "github.com/caddyserver/ingress/pkg/proxy" _ "github.com/caddyserver/ingress/pkg/proxy"
_ "github.com/caddyserver/ingress/pkg/storage"
) )
const ( const (
@ -146,9 +146,6 @@ func NewCaddyController(
DeleteFunc: controller.onConfigMapDeleted, DeleteFunc: controller.onConfigMapDeleted,
}) })
// register kubernetes specific cert-magic storage module and proxy module
caddy.RegisterModule(storage.SecretStorage{})
// Create resource store // Create resource store
controller.resourceStore = store.NewStore(opts, podInfo) controller.resourceStore = store.NewStore(opts, podInfo)

View File

@ -1,6 +1,10 @@
package proxy package proxy
import "github.com/caddyserver/caddy/v2" import (
"github.com/caddyserver/caddy/v2"
"github.com/pires/go-proxyproto"
"net"
)
var ( var (
_ = caddy.Provisioner(&Wrapper{}) _ = caddy.Provisioner(&Wrapper{})
@ -12,9 +16,28 @@ func init() {
caddy.RegisterModule(Wrapper{}) caddy.RegisterModule(Wrapper{})
} }
// Wrapper provides PROXY protocol support to Caddy by implementing the caddy.ListenerWrapper interface.
// It must be loaded before the `tls` listener.
type Wrapper struct {
policy proxyproto.PolicyFunc
}
func (Wrapper) CaddyModule() caddy.ModuleInfo { func (Wrapper) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{ return caddy.ModuleInfo{
ID: "caddy.listeners.proxy_protocol", ID: "caddy.listeners.proxy_protocol",
New: func() caddy.Module { return new(Wrapper) }, New: func() caddy.Module { return new(Wrapper) },
} }
} }
func (pp *Wrapper) Provision(ctx caddy.Context) error {
pp.policy = func(upstream net.Addr) (proxyproto.Policy, error) {
return proxyproto.REQUIRE, nil
}
return nil
}
func (pp *Wrapper) WrapListener(l net.Listener) net.Listener {
pL := &proxyproto.Listener{Listener: l, Policy: pp.policy}
return pL
}

View File

@ -1,30 +0,0 @@
package proxy
import (
"github.com/caddyserver/caddy/v2"
"net"
"github.com/pires/go-proxyproto"
)
// Wrapper provides PROXY protocol support to Caddy by implementing the caddy.ListenerWrapper interface. It must be loaded before the `tls` listener.
type Wrapper struct {
// Allow is an optional list of CIDR ranges to allow/require PROXY headers from.
Allow []string `json:"allow,omitempty"`
policy proxyproto.PolicyFunc
}
func (pp *Wrapper) Provision(ctx caddy.Context) error {
pp.policy = func(upstream net.Addr) (proxyproto.Policy, error) {
return proxyproto.REQUIRE, nil
}
return nil
}
func (pp *Wrapper) WrapListener(l net.Listener) net.Listener {
pL := &proxyproto.Listener{Listener: l, Policy: pp.policy}
return pL
}

View File

@ -46,12 +46,17 @@ func cleanKey(key string, prefix string) string {
// SecretStorage facilitates storing certificates retrieved by certmagic in kubernetes secrets. // SecretStorage facilitates storing certificates retrieved by certmagic in kubernetes secrets.
type SecretStorage struct { type SecretStorage struct {
Namespace string Namespace string
KubeClient *kubernetes.Clientset LeaseId string
LeaseId string
kubeClient *kubernetes.Clientset
logger *zap.Logger logger *zap.Logger
} }
func init() {
caddy.RegisterModule(SecretStorage{})
}
func (SecretStorage) CaddyModule() caddy.ModuleInfo { func (SecretStorage) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{ return caddy.ModuleInfo{
ID: "caddy.storage.secret_store", ID: "caddy.storage.secret_store",
@ -66,7 +71,7 @@ func (s *SecretStorage) Provision(ctx caddy.Context) error {
clientset, _ := kubernetes.NewForConfig(config) clientset, _ := kubernetes.NewForConfig(config)
s.logger = ctx.Logger(s) s.logger = ctx.Logger(s)
s.KubeClient = clientset s.kubeClient = clientset
if s.LeaseId == "" { if s.LeaseId == "" {
s.LeaseId = uuid.New().String() s.LeaseId = uuid.New().String()
} }
@ -81,7 +86,7 @@ func (s *SecretStorage) CertMagicStorage() (certmagic.Storage, error) {
// Exists returns true if key exists in fs. // Exists returns true if key exists in fs.
func (s *SecretStorage) Exists(ctx context.Context, key string) bool { func (s *SecretStorage) Exists(ctx context.Context, key string) bool {
s.logger.Debug("finding secret", zap.String("name", key)) s.logger.Debug("finding secret", zap.String("name", key))
secrets, err := s.KubeClient.CoreV1().Secrets(s.Namespace).List(context.TODO(), metav1.ListOptions{ secrets, err := s.kubeClient.CoreV1().Secrets(s.Namespace).List(context.TODO(), metav1.ListOptions{
FieldSelector: fmt.Sprintf("metadata.name=%v", cleanKey(key, keyPrefix)), FieldSelector: fmt.Sprintf("metadata.name=%v", cleanKey(key, keyPrefix)),
}) })
@ -115,10 +120,10 @@ func (s *SecretStorage) Store(ctx context.Context, key string, value []byte) err
var err error var err error
if s.Exists(ctx, key) { if s.Exists(ctx, key) {
s.logger.Debug("creating secret", zap.String("name", key)) s.logger.Debug("creating secret", zap.String("name", key))
_, err = s.KubeClient.CoreV1().Secrets(s.Namespace).Update(context.TODO(), &se, metav1.UpdateOptions{}) _, err = s.kubeClient.CoreV1().Secrets(s.Namespace).Update(context.TODO(), &se, metav1.UpdateOptions{})
} else { } else {
s.logger.Debug("updating secret", zap.String("name", key)) s.logger.Debug("updating secret", zap.String("name", key))
_, err = s.KubeClient.CoreV1().Secrets(s.Namespace).Create(context.TODO(), &se, metav1.CreateOptions{}) _, err = s.kubeClient.CoreV1().Secrets(s.Namespace).Create(context.TODO(), &se, metav1.CreateOptions{})
} }
if err != nil { if err != nil {
@ -130,7 +135,7 @@ func (s *SecretStorage) Store(ctx context.Context, key string, value []byte) err
// Load retrieves the value at the given key. // Load retrieves the value at the given key.
func (s *SecretStorage) Load(ctx context.Context, key string) ([]byte, error) { func (s *SecretStorage) Load(ctx context.Context, key string) ([]byte, error) {
secret, err := s.KubeClient.CoreV1().Secrets(s.Namespace).Get(context.TODO(), cleanKey(key, keyPrefix), metav1.GetOptions{}) secret, err := s.kubeClient.CoreV1().Secrets(s.Namespace).Get(context.TODO(), cleanKey(key, keyPrefix), metav1.GetOptions{})
if err != nil { if err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
return nil, fs.ErrNotExist return nil, fs.ErrNotExist
@ -144,7 +149,7 @@ func (s *SecretStorage) Load(ctx context.Context, key string) ([]byte, error) {
// Delete deletes the value at the given key. // Delete deletes the value at the given key.
func (s *SecretStorage) Delete(ctx context.Context, key string) error { func (s *SecretStorage) Delete(ctx context.Context, key string) error {
err := s.KubeClient.CoreV1().Secrets(s.Namespace).Delete(context.TODO(), cleanKey(key, keyPrefix), metav1.DeleteOptions{}) err := s.kubeClient.CoreV1().Secrets(s.Namespace).Delete(context.TODO(), cleanKey(key, keyPrefix), metav1.DeleteOptions{})
if err != nil { if err != nil {
return err return err
} }
@ -158,7 +163,7 @@ func (s *SecretStorage) List(ctx context.Context, prefix string, recursive bool)
var keys []string var keys []string
s.logger.Debug("listing secrets", zap.String("name", prefix)) s.logger.Debug("listing secrets", zap.String("name", prefix))
secrets, err := s.KubeClient.CoreV1().Secrets(s.Namespace).List(context.TODO(), metav1.ListOptions{ secrets, err := s.kubeClient.CoreV1().Secrets(s.Namespace).List(context.TODO(), metav1.ListOptions{
LabelSelector: labels.SelectorFromSet(matchLabels).String(), LabelSelector: labels.SelectorFromSet(matchLabels).String(),
}) })
if err != nil { if err != nil {
@ -178,7 +183,7 @@ func (s *SecretStorage) List(ctx context.Context, prefix string, recursive bool)
// Stat returns information about key. // Stat returns information about key.
func (s *SecretStorage) Stat(ctx context.Context, key string) (certmagic.KeyInfo, error) { func (s *SecretStorage) Stat(ctx context.Context, key string) (certmagic.KeyInfo, error) {
secret, err := s.KubeClient.CoreV1().Secrets(s.Namespace).Get(context.TODO(), cleanKey(key, keyPrefix), metav1.GetOptions{}) secret, err := s.kubeClient.CoreV1().Secrets(s.Namespace).Get(context.TODO(), cleanKey(key, keyPrefix), metav1.GetOptions{})
if err != nil { if err != nil {
return certmagic.KeyInfo{}, err return certmagic.KeyInfo{}, err
} }
@ -229,7 +234,7 @@ func (s *SecretStorage) tryAcquireOrRenew(ctx context.Context, key string, shoul
Name: key, Name: key,
Namespace: s.Namespace, Namespace: s.Namespace,
}, },
Client: s.KubeClient.CoordinationV1(), Client: s.kubeClient.CoordinationV1(),
LockConfig: resourcelock.ResourceLockConfig{ LockConfig: resourcelock.ResourceLockConfig{
Identity: s.LeaseId, Identity: s.LeaseId,
}, },
@ -280,6 +285,6 @@ func (s *SecretStorage) tryAcquireOrRenew(ctx context.Context, key string, shoul
} }
func (s *SecretStorage) Unlock(ctx context.Context, key string) error { func (s *SecretStorage) Unlock(ctx context.Context, key string) error {
err := s.KubeClient.CoordinationV1().Leases(s.Namespace).Delete(context.TODO(), cleanKey(key, leasePrefix), metav1.DeleteOptions{}) err := s.kubeClient.CoordinationV1().Leases(s.Namespace).Delete(context.TODO(), cleanKey(key, leasePrefix), metav1.DeleteOptions{})
return err return err
} }