Skip to content

Commit b5cef3e

Browse files
Merge pull request #118 from Miciah/set-constraints-on-router-ca
Set pathlen constraint on router-ca
2 parents 9a7a8f5 + 6912b76 commit b5cef3e

File tree

4 files changed

+468
-270
lines changed

4 files changed

+468
-270
lines changed

pkg/operator/controller/controller.go

Lines changed: 16 additions & 270 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package controller
22

33
import (
4-
"bytes"
54
"context"
65
"fmt"
76
"time"
@@ -13,8 +12,6 @@ import (
1312
"github.com/openshift/cluster-ingress-operator/pkg/manifests"
1413
"github.com/openshift/cluster-ingress-operator/pkg/util/slice"
1514

16-
"github.com/openshift/library-go/pkg/crypto"
17-
1815
appsv1 "k8s.io/api/apps/v1"
1916
corev1 "k8s.io/api/core/v1"
2017

@@ -25,7 +22,6 @@ import (
2522
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2623
"k8s.io/apimachinery/pkg/types"
2724
utilerrors "k8s.io/apimachinery/pkg/util/errors"
28-
"k8s.io/apimachinery/pkg/util/sets"
2925

3026
"sigs.k8s.io/controller-runtime/pkg/client"
3127
"sigs.k8s.io/controller-runtime/pkg/controller"
@@ -40,21 +36,6 @@ const (
4036
// considered for processing; this ensures the operator has a chance to handle
4137
// all states. TODO: Make this generic and not tied to the "default" ingress.
4238
ClusterIngressFinalizer = "ingress.openshift.io/default-cluster-ingress"
43-
44-
// GlobalMachineSpecifiedConfigNamespace is the location for global
45-
// config. In particular, the operator will put the configmap with the
46-
// CA certificate in this namespace.
47-
GlobalMachineSpecifiedConfigNamespace = "openshift-config-managed"
48-
49-
// caCertSecretName is the name of the secret that holds the CA certificate
50-
// that the operator will use to create default certificates for
51-
// clusteringresses.
52-
caCertSecretName = "router-ca"
53-
54-
// caCertConfigMapName is the name of the config map with the public key for
55-
// the CA certificate, which the operator publishes for other operators
56-
// to use.
57-
caCertConfigMapName = "router-ca"
5839
)
5940

6041
// New creates the operator controller from configuration. This is the
@@ -136,6 +117,11 @@ func (r *reconciler) reconcile(request reconcile.Request) (reconcile.Result, err
136117
}
137118
}
138119

120+
caSecret, err := r.ensureRouterCACertificateSecret()
121+
if err != nil {
122+
return reconcile.Result{}, fmt.Errorf("failed to get CA secret: %v", err)
123+
}
124+
139125
// Collect errors as we go.
140126
errs := []error{}
141127
result := reconcile.Result{}
@@ -179,7 +165,7 @@ func (r *reconciler) reconcile(request reconcile.Request) (reconcile.Result, err
179165
}
180166
} else {
181167
// Handle everything else.
182-
if err := r.ensureRouterForIngress(ingress, &result); err != nil {
168+
if err := r.ensureRouterForIngress(ingress, caSecret, &result); err != nil {
183169
errs = append(errs, fmt.Errorf("failed to ensure clusteringress: %v", err))
184170
}
185171
}
@@ -188,23 +174,13 @@ func (r *reconciler) reconcile(request reconcile.Request) (reconcile.Result, err
188174
// TODO: This should be in a different reconciler as it's independent of an
189175
// individual ingress. We only really need to trigger this when a
190176
// clusteringress is added or deleted...
191-
if len(errs) == 0 {
192-
// Find all clusteringresses to compute CA states.
193-
ingresses := &ingressv1alpha1.ClusterIngressList{}
194-
err = r.Client.List(context.TODO(), &client.ListOptions{Namespace: r.Namespace}, ingresses)
195-
if err != nil {
196-
return reconcile.Result{}, fmt.Errorf("failed to list clusteringresses in namespace %s: %v", r.Namespace, err)
197-
}
198-
if shouldPublishRouterCA(ingresses.Items) {
199-
if err := r.ensureRouterCAIsPublished(); err != nil {
200-
errs = append(errs, fmt.Errorf("failed to ensure router CA was published: %v", err))
201-
}
202-
} else {
203-
if err := r.ensureRouterCAIsUnpublished(); err != nil {
204-
errs = append(errs, fmt.Errorf("failed to ensure router CA was unpublished: %v", err))
205-
}
206-
}
177+
// Find all clusteringresses to compute CA states.
178+
ingresses := &ingressv1alpha1.ClusterIngressList{}
179+
err = r.Client.List(context.TODO(), &client.ListOptions{Namespace: r.Namespace}, ingresses)
180+
if err != nil {
181+
return reconcile.Result{}, fmt.Errorf("failed to list clusteringresses in namespace %s: %v", r.Namespace, err)
207182
}
183+
errs = append(errs, r.ensureRouterCAConfigMap(caSecret, ingresses.Items))
208184

209185
return result, utilerrors.NewAggregate(errs)
210186
}
@@ -313,7 +289,7 @@ func (r *reconciler) ensureRouterNamespace() error {
313289

314290
// ensureRouterForIngress ensures all necessary router resources exist for a
315291
// given clusteringress.
316-
func (r *reconciler) ensureRouterForIngress(ci *ingressv1alpha1.ClusterIngress, result *reconcile.Result) error {
292+
func (r *reconciler) ensureRouterForIngress(ci *ingressv1alpha1.ClusterIngress, caSecret *corev1.Secret, result *reconcile.Result) error {
317293
expected, err := r.ManifestFactory.RouterDeployment(ci)
318294
if err != nil {
319295
return fmt.Errorf("failed to build router deployment: %v", err)
@@ -367,16 +343,9 @@ func (r *reconciler) ensureRouterForIngress(ci *ingressv1alpha1.ClusterIngress,
367343
return utilerrors.NewAggregate(errs)
368344
}
369345

370-
if ci.Spec.DefaultCertificateSecret == nil {
371-
if err := r.ensureDefaultCertificateForIngress(current, ci); err != nil {
372-
errs = append(errs, fmt.Errorf("failed to create default certificate for clusteringress %s: %v", ci.Name, err))
373-
return utilerrors.NewAggregate(errs)
374-
}
375-
} else {
376-
if err := r.ensureDefaultCertificateDeleted(current, ci); err != nil {
377-
errs = append(errs, fmt.Errorf("failed to delete operator-generated default certificate for clusteringress %s: %v", ci.Name, err))
378-
return utilerrors.NewAggregate(errs)
379-
}
346+
if err := r.ensureDefaultCertificateForIngress(caSecret, current, ci); err != nil {
347+
errs = append(errs, err)
348+
return utilerrors.NewAggregate(errs)
380349
}
381350

382351
if err := r.ensureMetricsIntegration(ci, internalSvc, deploymentRef); err != nil {
@@ -538,144 +507,6 @@ func (r *reconciler) ensureInternalRouterServiceForIngress(ci *ingressv1alpha1.C
538507
return svc, nil
539508
}
540509

541-
// ensureDefaultCertificateForIngress ensures that a default certificate exists
542-
// for a given ClusterIngress.
543-
func (r *reconciler) ensureDefaultCertificateForIngress(deployment *appsv1.Deployment, ci *ingressv1alpha1.ClusterIngress) error {
544-
secret := &corev1.Secret{
545-
ObjectMeta: metav1.ObjectMeta{
546-
Name: fmt.Sprintf("router-certs-%s", ci.Name),
547-
Namespace: deployment.Namespace,
548-
},
549-
}
550-
err := r.Client.Get(context.TODO(), types.NamespacedName{Namespace: secret.Namespace, Name: secret.Name}, secret)
551-
if err != nil {
552-
if !errors.IsNotFound(err) {
553-
return fmt.Errorf("failed to get secret %s/%s: %v", secret.Namespace, secret.Name, err)
554-
}
555-
556-
ca, err := r.getRouterCA()
557-
if err != nil {
558-
return fmt.Errorf("failed to get CA certificate: %v", err)
559-
}
560-
hostnames := sets.NewString(fmt.Sprintf("*.%s", *ci.Spec.IngressDomain))
561-
cert, err := ca.MakeServerCert(hostnames, 0)
562-
if err != nil {
563-
return fmt.Errorf("failed to make CA: %v", err)
564-
}
565-
566-
secret.Type = corev1.SecretTypeTLS
567-
certBytes, keyBytes, err := cert.GetPEMBytes()
568-
if err != nil {
569-
return fmt.Errorf("failed to get certificate from secret %s/%s: %v", secret.Namespace, secret.Name, err)
570-
}
571-
secret.Data = map[string][]byte{
572-
"tls.crt": certBytes,
573-
"tls.key": keyBytes,
574-
}
575-
trueVar := true
576-
deploymentRef := metav1.OwnerReference{
577-
APIVersion: "apps/v1",
578-
Kind: "Deployment",
579-
Name: deployment.Name,
580-
UID: deployment.UID,
581-
Controller: &trueVar,
582-
}
583-
secret.SetOwnerReferences([]metav1.OwnerReference{deploymentRef})
584-
if err := r.Client.Create(context.TODO(), secret); err != nil {
585-
if !errors.IsAlreadyExists(err) {
586-
return fmt.Errorf("failed to create secret %s/%s: %v", secret.Namespace, secret.Name, err)
587-
}
588-
589-
return nil
590-
}
591-
logrus.Infof("created secret %s/%s", secret.Namespace, secret.Name)
592-
}
593-
594-
return nil
595-
}
596-
597-
// ensureDefaultCertificateDeleted ensures any operator-generated default
598-
// certificate for a given ClusterIngress is deleted.
599-
func (r *reconciler) ensureDefaultCertificateDeleted(deployment *appsv1.Deployment, ci *ingressv1alpha1.ClusterIngress) error {
600-
secret := &corev1.Secret{
601-
ObjectMeta: metav1.ObjectMeta{
602-
Name: fmt.Sprintf("router-certs-%s", ci.Name),
603-
Namespace: deployment.Namespace,
604-
},
605-
}
606-
err := r.Client.Delete(context.TODO(), secret)
607-
if err != nil {
608-
if errors.IsNotFound(err) {
609-
return nil
610-
}
611-
612-
return fmt.Errorf("failed to delete secret %s/%s: %v", secret.Namespace, secret.Name, err)
613-
}
614-
615-
logrus.Infof("deleted secret %s/%s", secret.Namespace, secret.Name)
616-
617-
return nil
618-
}
619-
620-
// getRouterCA gets the CA, or creates it if it does not already exist.
621-
func (r *reconciler) getRouterCA() (*crypto.CA, error) {
622-
secret, err := r.ensureRouterCACertificateSecret()
623-
if err != nil {
624-
return nil, fmt.Errorf("failed to get CA secret: %v", err)
625-
}
626-
627-
certBytes := secret.Data["tls.crt"]
628-
keyBytes := secret.Data["tls.key"]
629-
630-
ca, err := crypto.GetCAFromBytes(certBytes, keyBytes)
631-
if err != nil {
632-
return nil, fmt.Errorf("failed to get CA from secret %s/%s: %v", secret.Namespace, secret.Name, err)
633-
}
634-
635-
return ca, nil
636-
}
637-
638-
// ensureRouterCACertificateSecret ensures a CA certificate secret exists that
639-
// can be used to sign the default certificates for ClusterIngresses.
640-
func (r *reconciler) ensureRouterCACertificateSecret() (*corev1.Secret, error) {
641-
secret := &corev1.Secret{
642-
ObjectMeta: metav1.ObjectMeta{
643-
Name: caCertSecretName,
644-
Namespace: r.Namespace,
645-
},
646-
}
647-
err := r.Client.Get(context.TODO(), types.NamespacedName{Namespace: secret.Namespace, Name: secret.Name}, secret)
648-
if err != nil {
649-
if !errors.IsNotFound(err) {
650-
return nil, fmt.Errorf("failed to get secret %s/%s: %v", secret.Namespace, secret.Name, err)
651-
}
652-
653-
// TODO Use certrotationcontroller from library-go.
654-
signerName := fmt.Sprintf("%s@%d", "cluster-ingress-operator", time.Now().Unix())
655-
caConfig, err := crypto.MakeCAConfig(signerName, 0)
656-
if err != nil {
657-
return nil, fmt.Errorf("failed to make CA config: %v", err)
658-
}
659-
660-
secret.Type = corev1.SecretTypeTLS
661-
certBytes, keyBytes, err := caConfig.GetPEMBytes()
662-
if err != nil {
663-
return nil, fmt.Errorf("failed to get certificate: %v", err)
664-
}
665-
secret.Data = map[string][]byte{
666-
"tls.crt": certBytes,
667-
"tls.key": keyBytes,
668-
}
669-
if err := r.Client.Create(context.TODO(), secret); err != nil {
670-
return nil, fmt.Errorf("failed to create secret %s/%s: %v", secret.Namespace, secret.Name, err)
671-
}
672-
673-
logrus.Infof("created secret %s/%s", secret.Namespace, secret.Name)
674-
}
675-
676-
return secret, nil
677-
}
678-
679510
// ensureRouterDeleted ensures that any router resources associated with the
680511
// clusteringress are deleted.
681512
func (r *reconciler) ensureRouterDeleted(ci *ingressv1alpha1.ClusterIngress) error {
@@ -711,88 +542,3 @@ func deploymentConfigChanged(current, expected *appsv1.Deployment) (bool, *appsv
711542
updated.Spec.Replicas = &replicas
712543
return true, updated
713544
}
714-
715-
// shouldPublishRouterCA checks if some ClusterIngress uses the default
716-
// certificate, in which case the CA certificate needs to be published.
717-
func shouldPublishRouterCA(ingresses []ingressv1alpha1.ClusterIngress) bool {
718-
for _, ci := range ingresses {
719-
if ci.Spec.DefaultCertificateSecret == nil {
720-
return true
721-
}
722-
}
723-
return false
724-
}
725-
726-
// ensureRouterCAIsPublished ensures a configmap exists with the CA certificate
727-
// in a well known namespace.
728-
func (r *reconciler) ensureRouterCAIsPublished() error {
729-
secret, err := r.ensureRouterCACertificateSecret()
730-
if err != nil {
731-
return fmt.Errorf("failed to get CA secret: %v", err)
732-
}
733-
734-
cm := &corev1.ConfigMap{
735-
ObjectMeta: metav1.ObjectMeta{
736-
Name: caCertConfigMapName,
737-
Namespace: GlobalMachineSpecifiedConfigNamespace,
738-
},
739-
}
740-
err = r.Client.Get(context.TODO(), types.NamespacedName{Namespace: cm.Namespace, Name: cm.Name}, cm)
741-
if err != nil {
742-
if !errors.IsNotFound(err) {
743-
return fmt.Errorf("failed to get configmap %s/%s: %v", cm.Namespace, cm.Name, err)
744-
}
745-
746-
cm.Data = map[string]string{"ca-bundle.crt": string(secret.Data["tls.crt"])}
747-
if err := r.Client.Create(context.TODO(), cm); err != nil {
748-
if errors.IsAlreadyExists(err) {
749-
return nil
750-
}
751-
752-
return fmt.Errorf("failed to create configmap %s/%s: %v", cm.Namespace, cm.Name, err)
753-
}
754-
755-
logrus.Infof("created configmap %s/%s", cm.Namespace, cm.Name)
756-
757-
return nil
758-
}
759-
760-
if !bytes.Equal(secret.Data["tls.crt"], []byte(cm.Data["ca-bundle.crt"])) {
761-
cm.Data["ca-bundle.crt"] = string(secret.Data["tls.crt"])
762-
if err := r.Client.Update(context.TODO(), cm); err != nil {
763-
if errors.IsAlreadyExists(err) {
764-
return nil
765-
}
766-
767-
return fmt.Errorf("failed to update configmap %s/%s: %v", cm.Namespace, cm.Name, err)
768-
}
769-
770-
logrus.Infof("updated configmap %s/%s", cm.Namespace, cm.Name)
771-
772-
return nil
773-
}
774-
775-
return nil
776-
}
777-
778-
// ensureRouterCAIsUnpublished ensures the configmap with the CA certificate is
779-
// deleted.
780-
func (r *reconciler) ensureRouterCAIsUnpublished() error {
781-
cm := &corev1.ConfigMap{
782-
ObjectMeta: metav1.ObjectMeta{
783-
Name: caCertConfigMapName,
784-
Namespace: GlobalMachineSpecifiedConfigNamespace,
785-
},
786-
}
787-
if err := r.Client.Delete(context.TODO(), cm); err != nil {
788-
if errors.IsNotFound(err) {
789-
return nil
790-
}
791-
792-
return fmt.Errorf("failed to delete configmap %s/%s: %v", cm.Namespace, cm.Name, err)
793-
}
794-
795-
logrus.Infof("deleted configmap %s/%s", cm.Namespace, cm.Name)
796-
797-
return nil
798-
}

0 commit comments

Comments
 (0)