Skip to content

Commit b10307f

Browse files
committed
fix(init): cleanup leftover cross-namespace ownerreferences
1 parent 2959328 commit b10307f

File tree

2 files changed

+664
-2
lines changed

2 files changed

+664
-2
lines changed

cmd/olm/cleanup.go

Lines changed: 122 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ import (
44
"time"
55

66
"github.com/sirupsen/logrus"
7+
rbacv1 "k8s.io/api/rbac/v1"
78
"k8s.io/apimachinery/pkg/api/errors"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/apimachinery/pkg/types"
911
"k8s.io/apimachinery/pkg/util/wait"
12+
"k8s.io/client-go/util/retry"
1013

14+
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
1115
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
1216
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
1317
)
@@ -19,6 +23,7 @@ const (
1923

2024
type checkResourceFunc func() error
2125
type deleteResourceFunc func() error
26+
type mutateMeta func(obj metav1.Object) (mutated bool)
2227

2328
func cleanup(logger *logrus.Logger, c operatorclient.ClientInterface, crc versioned.Interface) {
2429
if err := waitForDelete(checkCatalogSource(crc, "olm-operators"), deleteCatalogSource(crc, "olm-operators")); err != nil {
@@ -44,6 +49,10 @@ func cleanup(logger *logrus.Logger, c operatorclient.ClientInterface, crc versio
4449
if err := waitForDelete(checkClusterServiceVersion(crc, "packageserver.v0.9.0"), deleteClusterServiceVersion(crc, "packageserver.v0.9.0")); err != nil {
4550
logger.WithError(err).Fatal("couldn't clean previous release")
4651
}
52+
53+
if err := cleanupOwnerReferences(c, crc); err != nil {
54+
logger.WithError(err).Fatal("couldn't cleanup cross-namespace ownerreferences")
55+
}
4756
}
4857

4958
func waitForDelete(checkResource checkResourceFunc, deleteResource deleteResourceFunc) error {
@@ -53,8 +62,7 @@ func waitForDelete(checkResource checkResourceFunc, deleteResource deleteResourc
5362
if err := deleteResource(); err != nil {
5463
return err
5564
}
56-
var err error
57-
err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
65+
err := wait.Poll(pollInterval, pollDuration, func() (bool, error) {
5866
err := checkResource()
5967
if errors.IsNotFound(err) {
6068
return true, nil
@@ -119,3 +127,115 @@ func deleteCatalogSource(crc versioned.Interface, name string) deleteResourceFun
119127
return crc.OperatorsV1alpha1().CatalogSources(*namespace).Delete(name, metav1.NewDeleteOptions(0))
120128
}
121129
}
130+
131+
// cleanupOwnerReferences cleans up inter-namespace and cluster-to-namespace scoped OwnerReferences to ClusterServiceVersions.
132+
//
133+
// Cross-namespace and cluster-to-namespace scoped OwnerReferences may cause sibling resources in the owner namespace to be
134+
// deleted sporadically (see CVE-2019-3884 https://access.redhat.com/security/cve/cve-2019-3884). Older versions of OLM use both types of
135+
// OwnerReference, and in cases where OLM is updated, they must be removed to prevent erroneous deletion of OLM's self-hosted components.
136+
func cleanupOwnerReferences(c operatorclient.ClientInterface, crc versioned.Interface) error {
137+
listOpts := metav1.ListOptions{}
138+
csvs, err := crc.OperatorsV1alpha1().ClusterServiceVersions(metav1.NamespaceAll).List(listOpts)
139+
if err != nil {
140+
return err
141+
}
142+
143+
uidNamespaces := map[types.UID]string{}
144+
for _, csv := range csvs.Items {
145+
uidNamespaces[csv.GetUID()] = csv.GetNamespace()
146+
}
147+
removeBadRefs := crossNamespaceOwnerReferenceRemoval(v1alpha1.ClusterServiceVersionKind, uidNamespaces)
148+
149+
// Cleanup cross-namespace OwnerReferences on CSVs, ClusterRoles/Bindings, and Roles/Bindings
150+
var objs []metav1.Object
151+
for _, obj := range csvs.Items {
152+
objs = append(objs, &obj)
153+
}
154+
155+
clusterRoles, _ := c.KubernetesInterface().RbacV1().ClusterRoles().List(listOpts)
156+
for _, obj := range clusterRoles.Items {
157+
objs = append(objs, &obj)
158+
}
159+
160+
clusterRoleBindings, _ := c.KubernetesInterface().RbacV1().ClusterRoleBindings().List(listOpts)
161+
for _, obj := range clusterRoleBindings.Items {
162+
objs = append(objs, &obj)
163+
}
164+
165+
roles, _ := c.KubernetesInterface().RbacV1().Roles(metav1.NamespaceAll).List(listOpts)
166+
for _, obj := range roles.Items {
167+
objs = append(objs, &obj)
168+
}
169+
roleBindings, _ := c.KubernetesInterface().RbacV1().RoleBindings(metav1.NamespaceAll).List(listOpts)
170+
for _, obj := range roleBindings.Items {
171+
objs = append(objs, &obj)
172+
}
173+
174+
for _, obj := range objs {
175+
if !removeBadRefs(obj) {
176+
continue
177+
}
178+
179+
update := func() error {
180+
// If this is not a type we care about, do nothing
181+
return nil
182+
}
183+
switch v := obj.(type) {
184+
case *v1alpha1.ClusterServiceVersion:
185+
update = func() error {
186+
_, err := crc.OperatorsV1alpha1().ClusterServiceVersions(v.GetNamespace()).Update(v)
187+
return err
188+
}
189+
case *rbacv1.ClusterRole:
190+
update = func() error {
191+
_, err = c.KubernetesInterface().RbacV1().ClusterRoles().Update(v)
192+
return err
193+
}
194+
case *rbacv1.ClusterRoleBinding:
195+
update = func() error {
196+
_, err = c.KubernetesInterface().RbacV1().ClusterRoleBindings().Update(v)
197+
return err
198+
}
199+
case *rbacv1.Role:
200+
update = func() error {
201+
_, err = c.KubernetesInterface().RbacV1().Roles(v.GetNamespace()).Update(v)
202+
return err
203+
}
204+
case *rbacv1.RoleBinding:
205+
update = func() error {
206+
_, err = c.KubernetesInterface().RbacV1().RoleBindings(v.GetNamespace()).Update(v)
207+
return err
208+
}
209+
}
210+
211+
if err := retry.RetryOnConflict(retry.DefaultBackoff, update); err != nil {
212+
return err
213+
}
214+
}
215+
216+
return nil
217+
}
218+
219+
func crossNamespaceOwnerReferenceRemoval(kind string, uidNamespaces map[types.UID]string) mutateMeta {
220+
return func(obj metav1.Object) (mutated bool) {
221+
var cleanRefs []metav1.OwnerReference
222+
objNamespace := obj.GetNamespace()
223+
for _, ref := range obj.GetOwnerReferences() {
224+
if ref.Kind == kind {
225+
refNamespace, ok := uidNamespaces[ref.UID]
226+
if !ok || (refNamespace != metav1.NamespaceAll && refNamespace != objNamespace) {
227+
mutated = true
228+
continue
229+
}
230+
}
231+
232+
cleanRefs = append(cleanRefs, ref)
233+
}
234+
235+
if mutated {
236+
obj.SetOwnerReferences(cleanRefs)
237+
}
238+
239+
return
240+
}
241+
}

0 commit comments

Comments
 (0)