Skip to content

Commit

Permalink
fix: using configuration for tls and ca secret names
Browse files Browse the repository at this point in the history
  • Loading branch information
davideimola authored and prometherion committed Mar 31, 2022
1 parent 0bfca6b commit 7b3b0d6
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 56 deletions.
2 changes: 2 additions & 0 deletions api/v1alpha1/capsuleconfiguration_annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ const (
ForbiddenNodeLabelsRegexpAnnotation = "capsule.clastix.io/forbidden-node-labels-regexp"
ForbiddenNodeAnnotationsAnnotation = "capsule.clastix.io/forbidden-node-annotations"
ForbiddenNodeAnnotationsRegexpAnnotation = "capsule.clastix.io/forbidden-node-annotations-regexp"
CASecretNameAnnotation = "capsule.clastix.io/ca-secret-name"
TLSSecretNameAnnotation = "capsule.clastix.io/tls-secret-name"
)
18 changes: 12 additions & 6 deletions controllers/secret/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,20 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"

"github.com/clastix/capsule/pkg/cert"
"github.com/clastix/capsule/pkg/configuration"
)

type CAReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Namespace string
Log logr.Logger
Scheme *runtime.Scheme
Namespace string
Configuration configuration.Configuration
}

func (r *CAReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&corev1.Secret{}, forOptionPerInstanceName(CASecretName)).
For(&corev1.Secret{}).
Complete(r)
}

Expand Down Expand Up @@ -115,6 +117,10 @@ func (r CAReconciler) UpdateMutatingWebhookConfiguration(caBundle []byte) error
func (r CAReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
var err error

if request.Name != r.Configuration.CASecretName() {
return ctrl.Result{}, nil
}

r.Log = r.Log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
r.Log.Info("Reconciling CA Secret")

Expand All @@ -128,7 +134,7 @@ func (r CAReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl

var ca cert.CA
var rq time.Duration
ca, err = getCertificateAuthority(r.Client, r.Namespace)
ca, err = getCertificateAuthority(r.Client, r.Namespace, r.Configuration.CASecretName())
if err != nil && errors.Is(err, MissingCaError{}) {
ca, err = cert.GenerateCertificateAuthority()
if err != nil {
Expand Down Expand Up @@ -189,7 +195,7 @@ func (r CAReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl
tls := &corev1.Secret{}
err = r.Get(ctx, types.NamespacedName{
Namespace: r.Namespace,
Name: TLSSecretName,
Name: r.Configuration.TLSSecretName(),
}, tls)
if err != nil {
r.Log.Error(err, "Capsule TLS Secret missing")
Expand Down
3 changes: 0 additions & 3 deletions controllers/secret/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,4 @@ package secret
const (
certSecretKey = "tls.crt"
privateKeySecretKey = "tls.key"

CASecretName = "capsule-ca"
TLSSecretName = "capsule-tls"
)
30 changes: 3 additions & 27 deletions controllers/secret/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,20 @@ import (

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"

"github.com/clastix/capsule/pkg/cert"
)

func getCertificateAuthority(client client.Client, namespace string) (ca cert.CA, err error) {
func getCertificateAuthority(client client.Client, namespace, name string) (ca cert.CA, err error) {
instance := &corev1.Secret{}

err = client.Get(context.TODO(), types.NamespacedName{
Namespace: namespace,
Name: CASecretName,
Name: name,
}, instance)
if err != nil {
return nil, fmt.Errorf("missing secret %s, cannot reconcile", CASecretName)
return nil, fmt.Errorf("missing secret %s, cannot reconcile", name)
}

if instance.Data == nil {
Expand All @@ -39,24 +36,3 @@ func getCertificateAuthority(client client.Client, namespace string) (ca cert.CA

return
}

func forOptionPerInstanceName(instanceName string) builder.ForOption {
return builder.WithPredicates(predicate.Funcs{
CreateFunc: func(event event.CreateEvent) bool {
return filterByName(event.Object.GetName(), instanceName)
},
DeleteFunc: func(deleteEvent event.DeleteEvent) bool {
return filterByName(deleteEvent.Object.GetName(), instanceName)
},
UpdateFunc: func(updateEvent event.UpdateEvent) bool {
return filterByName(updateEvent.ObjectNew.GetName(), instanceName)
},
GenericFunc: func(genericEvent event.GenericEvent) bool {
return filterByName(genericEvent.Object.GetName(), instanceName)
},
})
}

func filterByName(objName, desired string) bool {
return objName == desired
}
18 changes: 12 additions & 6 deletions controllers/secret/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,30 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"

"github.com/clastix/capsule/pkg/cert"
"github.com/clastix/capsule/pkg/configuration"
)

type TLSReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Namespace string
Log logr.Logger
Scheme *runtime.Scheme
Namespace string
Configuration configuration.Configuration
}

func (r *TLSReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&corev1.Secret{}, forOptionPerInstanceName(TLSSecretName)).
For(&corev1.Secret{}).
Complete(r)
}

func (r TLSReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
var err error

if request.Name != r.Configuration.TLSSecretName() {
return ctrl.Result{}, nil
}

r.Log = r.Log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
r.Log.Info("Reconciling TLS Secret")

Expand All @@ -54,7 +60,7 @@ func (r TLSReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctr
var ca cert.CA
var rq time.Duration

ca, err = getCertificateAuthority(r.Client, r.Namespace)
ca, err = getCertificateAuthority(r.Client, r.Namespace, r.Configuration.CASecretName())
if err != nil {
return reconcile.Result{}, err
}
Expand Down Expand Up @@ -112,7 +118,7 @@ func (r TLSReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctr
return reconcile.Result{}, err
}

if instance.Name == TLSSecretName && res == controllerutil.OperationResultUpdated {
if instance.Name == r.Configuration.TLSSecretName() && res == controllerutil.OperationResultUpdated {
r.Log.Info("Capsule TLS certificates has been updated, Controller pods must be restarted to load new certificate")

hostname, _ := os.Hostname()
Expand Down
5 changes: 5 additions & 0 deletions docs/content/general/references.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ apiVersion: capsule.clastix.io/v1alpha1
kind: CapsuleConfiguration
metadata:
name: default
annotations:
capsule.clastix.io/ca-secret-name: "capsule-ca"
capsule.clastix.io/tls-secret-name: "capsule-tls"
spec:
userGroups: ["capsule.clastix.io"]
forceTenantPrefix: false
Expand All @@ -162,6 +165,8 @@ Option | Description | Default
`.spec.forceTenantPrefix` | Force the tenant name as prefix for namespaces: `<tenant_name>-<namespace>`. | `false`
`.spec.userGroups` | Array of Capsule groups to which all tenant owners must belong. | `[capsule.clastix.io]`
`.spec.protectedNamespaceRegex` | Disallows creation of namespaces matching the passed regexp. | `null`
`.metadata.annotations.capsule.clastix.io/ca-secret-name` | Set the Capsule Certificate Authority secret name | `capsule-ca`
`.metadata.annotations.capsule.clastic.io/tls-secret-name` | Set the Capsule TLS secret name | `capsule-tls`

Upon installation using Kustomize or Helm, a `capsule-default` resource will be created.
The reference to this configuration is managed by the CLI flag `--configuration-name`.
Expand Down
37 changes: 25 additions & 12 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"

Expand Down Expand Up @@ -127,21 +128,25 @@ func main() {

ctx := ctrl.SetupSignalHandler()

cfg := configuration.NewCapsuleConfiguration(manager.GetClient(), configurationName)

if err = (&secretcontroller.CAReconciler{
Client: manager.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("CA"),
Scheme: manager.GetScheme(),
Namespace: namespace,
Client: manager.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("CA"),
Scheme: manager.GetScheme(),
Namespace: namespace,
Configuration: cfg,
}).SetupWithManager(manager); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Namespace")
os.Exit(1)
}

if err = (&secretcontroller.TLSReconciler{
Client: manager.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Tls"),
Scheme: manager.GetScheme(),
Namespace: namespace,
Client: manager.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Tls"),
Scheme: manager.GetScheme(),
Namespace: namespace,
Configuration: cfg,
}).SetupWithManager(manager); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Namespace")
os.Exit(1)
Expand All @@ -153,13 +158,23 @@ func main() {
os.Exit(1)
}

ca, err := clientset.CoreV1().Secrets(namespace).Get(ctx, secretcontroller.CASecretName, metav1.GetOptions{})
directClient, err := client.New(ctrl.GetConfigOrDie(), client.Options{
Scheme: manager.GetScheme(),
Mapper: manager.GetRESTMapper(),
})
if err != nil {
setupLog.Error(err, "unable to create the direct client")
os.Exit(1)
}
directCfg := configuration.NewCapsuleConfiguration(directClient, configurationName)

ca, err := clientset.CoreV1().Secrets(namespace).Get(ctx, directCfg.CASecretName(), metav1.GetOptions{})
if err != nil {
setupLog.Error(err, "unable to get Capsule CA secret")
os.Exit(1)
}

tls, err := clientset.CoreV1().Secrets(namespace).Get(ctx, secretcontroller.TLSSecretName, metav1.GetOptions{})
tls, err := clientset.CoreV1().Secrets(namespace).Get(ctx, directCfg.TLSSecretName(), metav1.GetOptions{})
if err != nil {
setupLog.Error(err, "unable to get Capsule TLS secret")
os.Exit(1)
Expand Down Expand Up @@ -194,8 +209,6 @@ func main() {
os.Exit(1)
}

cfg := configuration.NewCapsuleConfiguration(manager.GetClient(), configurationName)

// webhooks: the order matters, don't change it and just append
webhooksList := append(
make([]webhook.Webhook, 0),
Expand Down
33 changes: 31 additions & 2 deletions pkg/configuration/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ import (
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"

capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1"
capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
)

// capsuleConfiguration is the Capsule Configuration retrieval mode
Expand Down Expand Up @@ -62,6 +61,36 @@ func (c capsuleConfiguration) ForceTenantPrefix() bool {
return c.retrievalFn().Spec.ForceTenantPrefix
}

func (c capsuleConfiguration) CASecretName() (name string) {
name = CASecretName

if c.retrievalFn().Annotations == nil {
return
}

v, ok := c.retrievalFn().Annotations[capsulev1alpha1.CASecretNameAnnotation]
if ok {
return v
}

return
}

func (c capsuleConfiguration) TLSSecretName() (name string) {
name = TLSSecretName

if c.retrievalFn().Annotations == nil {
return
}

v, ok := c.retrievalFn().Annotations[capsulev1alpha1.TLSSecretNameAnnotation]
if ok {
return v
}

return
}

func (c capsuleConfiguration) UserGroups() []string {
return c.retrievalFn().Spec.UserGroups
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,16 @@ import (
capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
)

const (
CASecretName = "capsule-ca"
TLSSecretName = "capsule-tls"
)

type Configuration interface {
ProtectedNamespaceRegexp() (*regexp.Regexp, error)
ForceTenantPrefix() bool
CASecretName() string
TLSSecretName() string
UserGroups() []string
ForbiddenUserNodeLabels() *capsulev1beta1.ForbiddenListSpec
ForbiddenUserNodeAnnotations() *capsulev1beta1.ForbiddenListSpec
Expand Down

0 comments on commit 7b3b0d6

Please sign in to comment.