-
Notifications
You must be signed in to change notification settings - Fork 239
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds the ability to inject a combined CA bundle into configmaps that are setup to want them
- Loading branch information
1 parent
0b6b46a
commit 3520332
Showing
5 changed files
with
212 additions
and
17 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
package configmapcainjector | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
|
||
configv1 "github.com/openshift/api/config/v1" | ||
"github.com/openshift/cluster-network-operator/pkg/controller/statusmanager" | ||
"github.com/openshift/cluster-network-operator/pkg/names" | ||
"github.com/openshift/cluster-network-operator/pkg/util/validation" | ||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/labels" | ||
"k8s.io/apimachinery/pkg/types" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/api/equality" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/client-go/util/retry" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller" | ||
"sigs.k8s.io/controller-runtime/pkg/event" | ||
"sigs.k8s.io/controller-runtime/pkg/handler" | ||
"sigs.k8s.io/controller-runtime/pkg/manager" | ||
"sigs.k8s.io/controller-runtime/pkg/predicate" | ||
"sigs.k8s.io/controller-runtime/pkg/reconcile" | ||
"sigs.k8s.io/controller-runtime/pkg/source" | ||
) | ||
|
||
func Add(mgr manager.Manager, status *statusmanager.StatusManager) error { | ||
reconciler := newReconciler(mgr, status) | ||
if reconciler == nil { | ||
return fmt.Errorf("failed to create reconciler") | ||
} | ||
|
||
return add(mgr, reconciler) | ||
} | ||
|
||
func newReconciler(mgr manager.Manager, status *statusmanager.StatusManager) reconcile.Reconciler { | ||
if err := configv1.Install(mgr.GetScheme()); err != nil { | ||
return nil | ||
} | ||
|
||
return &ReconcileConfigMapInjector{client: mgr.GetClient(), scheme: mgr.GetScheme(), status: status} | ||
} | ||
|
||
func add(mgr manager.Manager, r reconcile.Reconciler) error { | ||
// Create a new controller | ||
c, err := controller.New("configmap-trust-bundle-injector-controller", mgr, controller.Options{Reconciler: r}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// The events fire for changes/creation of the trusted-ca-bundle and any configmaps with the | ||
//"config.openshift.io/inject-trusted-cabundle" label | ||
pred := predicate.Funcs{ | ||
UpdateFunc: func(e event.UpdateEvent) bool { | ||
return shouldUpdateConfigMaps(e.MetaNew) | ||
}, | ||
DeleteFunc: func(e event.DeleteEvent) bool { | ||
return false | ||
}, | ||
CreateFunc: func(e event.CreateEvent) bool { | ||
return shouldUpdateConfigMaps(e.Meta) | ||
}, | ||
GenericFunc: func(e event.GenericEvent) bool { | ||
return shouldUpdateConfigMaps(e.Meta) | ||
}, | ||
} | ||
|
||
err = c.Watch(&source.Kind{Type: &corev1.ConfigMap{}}, &handler.EnqueueRequestForObject{}, pred) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
var _ reconcile.Reconciler = &ReconcileConfigMapInjector{} | ||
|
||
type ReconcileConfigMapInjector struct { | ||
client client.Client | ||
scheme *runtime.Scheme | ||
status *statusmanager.StatusManager | ||
} | ||
|
||
// Reconcile expectes requests to refers to configmaps of two different types. | ||
// 1. a configmap named trusted-ca-bundle in namespace openshift-config-managed and will ensure that all configmaps with the label | ||
// config.openshift.io/inject-trusted-cabundle = true have the certificate information stored in trusted-ca-bundle's ca-bundle.crt entry. | ||
// 2. a configmap in any namespace with the label config.openshift.io/inject-trusted-cabundle = true and will insure that it contains the ca-bundle.crt | ||
// entry in the configmap named trusted-ca-bundle in namespace openshift-config-managed. | ||
func (r *ReconcileConfigMapInjector) Reconcile(request reconcile.Request) (reconcile.Result, error) { | ||
log.Printf("Reconciling configmap from %s/%s\n", request.Name, request.Namespace) | ||
|
||
trustedCAbundleConfigMap := &corev1.ConfigMap{} | ||
trustedCAbundleConfigMapName := types.NamespacedName{ | ||
Namespace: names.TRUSTED_CA_BUNDLE_CONFIGMAP_NS, | ||
Name: names.TRUSTED_CA_BUNDLE_CONFIGMAP, | ||
} | ||
err := r.client.Get(context.TODO(), trustedCAbundleConfigMapName, trustedCAbundleConfigMap) | ||
if err != nil { | ||
log.Println(err) | ||
return reconcile.Result{}, err | ||
} | ||
_, trustedCAbundleData, err := validation.TrustBundleConfigMap(trustedCAbundleConfigMap) | ||
|
||
if err != nil { | ||
return reconcile.Result{}, err | ||
} | ||
//build a list of configMaps | ||
configMapsToChange := []corev1.ConfigMap{} | ||
|
||
//The trusted-ca-bundle changed | ||
if request.Name == names.TRUSTED_CA_BUNDLE_CONFIGMAP && request.Namespace == names.TRUSTED_CA_BUNDLE_CONFIGMAP_NS { | ||
|
||
configMapList := &corev1.ConfigMapList{} | ||
selector := labels.Set(map[string]string{names.TRUSTED_CA_BUNDLE_CONFIGMAP_LABEL: "true"}).AsSelector() | ||
err = r.client.List(context.TODO(), &client.ListOptions{LabelSelector: selector}, configMapList) | ||
if err != nil { | ||
log.Println(err) | ||
return reconcile.Result{}, err | ||
} | ||
configMapsToChange = configMapList.Items | ||
log.Printf("%s changed, updating %d configMaps", names.TRUSTED_CA_BUNDLE_CONFIGMAP, len(configMapsToChange)) | ||
} else { | ||
//changing a single labeled configmap | ||
|
||
//get the requested object | ||
requestedCAbundleConfigMap := &corev1.ConfigMap{} | ||
requestedCAbundleConfigMapName := types.NamespacedName{ | ||
Namespace: request.Namespace, | ||
Name: request.Name, | ||
} | ||
err = r.client.Get(context.TODO(), requestedCAbundleConfigMapName, requestedCAbundleConfigMap) | ||
if err != nil { | ||
log.Println(err) | ||
if apierrors.IsNotFound(err) { | ||
return reconcile.Result{}, nil | ||
} | ||
return reconcile.Result{}, err | ||
} | ||
configMapsToChange = append(configMapsToChange, *requestedCAbundleConfigMap) | ||
} | ||
|
||
errs := []error{} | ||
|
||
for _, configMap := range configMapsToChange { | ||
err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { | ||
retrievedConfigMap := &corev1.ConfigMap{} | ||
err = r.client.Get(context.TODO(), types.NamespacedName{Namespace: configMap.Namespace, Name: configMap.Name}, retrievedConfigMap) | ||
if err != nil { | ||
log.Println(err) | ||
return err | ||
} | ||
configMapToUpdate := retrievedConfigMap.DeepCopy() | ||
if configMapToUpdate.Data == nil { | ||
configMapToUpdate.Data = map[string]string{names.TRUSTED_CA_BUNDLE_CONFIGMAP_KEY: string(trustedCAbundleData)} | ||
} else { | ||
configMapToUpdate.Data[names.TRUSTED_CA_BUNDLE_CONFIGMAP_KEY] = string(trustedCAbundleData) | ||
} | ||
if equality.Semantic.DeepEqual(configMapToUpdate, retrievedConfigMap) { | ||
// nothing to update the new and old configmap object would be the same | ||
return nil | ||
} | ||
err = r.client.Update(context.TODO(), configMapToUpdate) | ||
if err != nil { | ||
log.Println(err) | ||
return err | ||
} | ||
return nil | ||
}) | ||
if err != nil { | ||
errs = append(errs, err) | ||
if len(errs) > 5 { | ||
return reconcile.Result{}, fmt.Errorf("Too many errors attempting to update configmaps with CA cert. data") | ||
} | ||
} | ||
} | ||
if len(errs) > 0 { | ||
return reconcile.Result{}, fmt.Errorf("some configmaps didn't fully update with CA cert. data") | ||
} | ||
return reconcile.Result{}, nil | ||
} | ||
|
||
func shouldUpdateConfigMaps(meta metav1.Object) bool { | ||
return meta.GetLabels()[names.TRUSTED_CA_BUNDLE_CONFIGMAP_LABEL] == "true" || | ||
(meta.GetName() == names.TRUSTED_CA_BUNDLE_CONFIGMAP && meta.GetNamespace() == names.TRUSTED_CA_BUNDLE_CONFIGMAP_NS) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters