-
Notifications
You must be signed in to change notification settings - Fork 228
OCPBUGS-9037, OCPBUGS-64565: Use cluster wildcard certificate for ingress canary #1155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,8 @@ import ( | |
| func Test_desiredCanaryDaemonSet(t *testing.T) { | ||
| // canaryImageName is the ingress-operator image | ||
| canaryImageName := "openshift/origin-cluster-ingress-operator:latest" | ||
| daemonset := desiredCanaryDaemonSet(canaryImageName) | ||
| certSecretName := "test_secret_name" | ||
| daemonset := desiredCanaryDaemonSet(canaryImageName, certSecretName) | ||
|
|
||
| expectedDaemonSetName := controller.CanaryDaemonSetName() | ||
|
|
||
|
|
@@ -83,6 +84,23 @@ func Test_desiredCanaryDaemonSet(t *testing.T) { | |
| if !cmp.Equal(tolerations, expectedTolerations) { | ||
| t.Errorf("expected daemonset tolerations to be %v, but got %v", expectedTolerations, tolerations) | ||
| } | ||
|
|
||
| volumes := daemonset.Spec.Template.Spec.Volumes | ||
| secretMode := int32(0420) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know why the defaultMode has to be set for the test but not in the function
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm setting the default mode on the expected result here. Default mode is set in the daemonset manifest here for the desired daemonset |
||
| expectedVolumes := []corev1.Volume{ | ||
| { | ||
| Name: "cert", | ||
| VolumeSource: corev1.VolumeSource{ | ||
| Secret: &corev1.SecretVolumeSource{ | ||
| SecretName: certSecretName, | ||
| DefaultMode: &secretMode, | ||
| }, | ||
| }, | ||
| }, | ||
| } | ||
| if !cmp.Equal(volumes, expectedVolumes) { | ||
| t.Errorf("expected daemonset volumes to be %v, but got %v", expectedVolumes, volumes) | ||
| } | ||
| } | ||
|
|
||
| func Test_canaryDaemonsetChanged(t *testing.T) { | ||
|
|
@@ -229,7 +247,7 @@ func Test_canaryDaemonsetChanged(t *testing.T) { | |
|
|
||
| for _, tc := range testCases { | ||
| t.Run(tc.description, func(t *testing.T) { | ||
| original := desiredCanaryDaemonSet("") | ||
| original := desiredCanaryDaemonSet("", "foobar") | ||
| mutated := original.DeepCopy() | ||
| tc.mutate(mutated) | ||
| if changed, updated := canaryDaemonSetChanged(original, mutated); changed != tc.expect { | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comment at the top of this file should be updated to document that the controller copies the certificate for the canary... though the more I think about it, the more I think we should have a separate controller for this purpose. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -10,6 +10,7 @@ import ( | |||||
| "time" | ||||||
|
|
||||||
| logf "github.com/openshift/cluster-ingress-operator/pkg/log" | ||||||
| "github.com/openshift/cluster-ingress-operator/pkg/manifests" | ||||||
| "github.com/openshift/cluster-ingress-operator/pkg/operator/controller" | ||||||
| ingresscontroller "github.com/openshift/cluster-ingress-operator/pkg/operator/controller/ingress" | ||||||
|
|
||||||
|
|
@@ -20,6 +21,7 @@ import ( | |||||
| "k8s.io/client-go/tools/record" | ||||||
|
|
||||||
| appsv1 "k8s.io/api/apps/v1" | ||||||
| corev1 "k8s.io/api/core/v1" | ||||||
|
|
||||||
| operatorv1 "github.com/openshift/api/operator/v1" | ||||||
|
|
||||||
|
|
@@ -105,6 +107,48 @@ func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) ( | |||||
| if _, err := r.ensureDefaultCertificateForIngress(ca, deployment.Namespace, deploymentRef, ingress); err != nil { | ||||||
| errs = append(errs, fmt.Errorf("failed to ensure default cert for %s: %v", ingress.Name, err)) | ||||||
| } | ||||||
| // The ingress canary verifies that the default ingress controller is functioning. Since it uses a | ||||||
| // passthrough route, we mirror the default ingress controller's certificate in the canary to detect any | ||||||
| // issues with that certificate, so if the default controller's cert is updated, update the canary's cert as | ||||||
| // well. | ||||||
| if ingress.Name == manifests.DefaultIngressControllerName { | ||||||
rfredette marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| log.Info("Ensuring canary certificate") | ||||||
| daemonset := &appsv1.DaemonSet{} | ||||||
| err = r.client.Get(ctx, controller.CanaryDaemonSetName(), daemonset) | ||||||
|
Comment on lines
+110
to
+117
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need a watch on secrets so that we update the canary's copy when the cluster-admin updates the original secret? Maybe re-using this controller isn't the best approach. I suppose we can refactor later on as a follow-up. |
||||||
| if err != nil { | ||||||
| if errors.IsNotFound(err) { | ||||||
| // All ingresses should have a deployment, so this one may not have been | ||||||
| // created yet. Retry after a reasonable amount of time. | ||||||
|
Comment on lines
+120
to
+121
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment looks like copypasta. |
||||||
| log.Info("Canary daemonset not found; will retry default cert sync") | ||||||
| result.RequeueAfter = 5 * time.Second | ||||||
| } else { | ||||||
| errs = append(errs, fmt.Errorf("failed to get daemonset: %w", err)) | ||||||
| } | ||||||
| } else { | ||||||
| defaultCertName := controller.RouterEffectiveDefaultCertificateSecretName(ingress, deployment.Namespace) | ||||||
| defaultCert := &corev1.Secret{} | ||||||
| if err := r.client.Get(ctx, defaultCertName, defaultCert); err != nil { | ||||||
| errs = append(errs, fmt.Errorf("failed to get certificate for canary: %w", err)) | ||||||
| } | ||||||
| canaryCert := defaultCert.DeepCopy() | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We really only care about I suppose using |
||||||
| canaryCertName := controller.RouterEffectiveDefaultCertificateSecretName(ingress, daemonset.Namespace) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should work, but is there a reason to copy the name from the effective certificate? If you used a static name, you could get rid of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One consequence of copying the name is that you can end up with multiple secrets in the canary namespace if For example, the If the canary daemonset were ever deleted, the owner reference would cause these secrets to be cleaned up, but otherwise you can accumulate these secrets. This isn't a major problem, but it does create some unnecessary cruft.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well... I wonder whether the issue referenced at #1155 (comment) will prevent garbage collection from working properly? |
||||||
| canaryRef := metav1.OwnerReference{ | ||||||
| APIVersion: "apps/v1", | ||||||
| Kind: "Daemonset", | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The kind is miscapitalized here:
Suggested change
Does using "Daemonset" actually work? I don't know how forgiving the API server [or garbage collector] is. |
||||||
| Name: daemonset.Name, | ||||||
| UID: daemonset.UID, | ||||||
| Controller: &trueVar, | ||||||
| } | ||||||
| canaryCert.ObjectMeta = metav1.ObjectMeta{ | ||||||
| Name: canaryCertName.Name, | ||||||
| Namespace: canaryCertName.Namespace, | ||||||
| OwnerReferences: []metav1.OwnerReference{canaryRef}, | ||||||
| } | ||||||
| if err := r.client.Create(ctx, canaryCert); err != nil { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might be way off, but I'm not sure why you can't just store the name of the default cert instead of creating a copy of it? I defer to @Miciah on this.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to copy the secret's data so that the canary application uses the exact certificate that is used as the default IngressController's default certificate. That is, we specifically need |
||||||
| errs = append(errs, fmt.Errorf("failed to ensure certificate for canary: %w", err)) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.