@@ -4,10 +4,14 @@ import (
4
4
"time"
5
5
6
6
"github.com/sirupsen/logrus"
7
+ rbacv1 "k8s.io/api/rbac/v1"
7
8
"k8s.io/apimachinery/pkg/api/errors"
8
9
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10
+ "k8s.io/apimachinery/pkg/types"
9
11
"k8s.io/apimachinery/pkg/util/wait"
12
+ "k8s.io/client-go/util/retry"
10
13
14
+ "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
11
15
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
12
16
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
13
17
)
@@ -19,6 +23,7 @@ const (
19
23
20
24
type checkResourceFunc func () error
21
25
type deleteResourceFunc func () error
26
+ type mutateMeta func (obj metav1.Object ) (mutated bool )
22
27
23
28
func cleanup (logger * logrus.Logger , c operatorclient.ClientInterface , crc versioned.Interface ) {
24
29
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
44
49
if err := waitForDelete (checkClusterServiceVersion (crc , "packageserver.v0.9.0" ), deleteClusterServiceVersion (crc , "packageserver.v0.9.0" )); err != nil {
45
50
logger .WithError (err ).Fatal ("couldn't clean previous release" )
46
51
}
52
+
53
+ if err := cleanupOwnerReferences (c , crc ); err != nil {
54
+ logger .WithError (err ).Fatal ("couldn't cleanup cross-namespace ownerreferences" )
55
+ }
47
56
}
48
57
49
58
func waitForDelete (checkResource checkResourceFunc , deleteResource deleteResourceFunc ) error {
@@ -53,8 +62,7 @@ func waitForDelete(checkResource checkResourceFunc, deleteResource deleteResourc
53
62
if err := deleteResource (); err != nil {
54
63
return err
55
64
}
56
- var err error
57
- err = wait .Poll (pollInterval , pollDuration , func () (bool , error ) {
65
+ err := wait .Poll (pollInterval , pollDuration , func () (bool , error ) {
58
66
err := checkResource ()
59
67
if errors .IsNotFound (err ) {
60
68
return true , nil
@@ -119,3 +127,115 @@ func deleteCatalogSource(crc versioned.Interface, name string) deleteResourceFun
119
127
return crc .OperatorsV1alpha1 ().CatalogSources (* namespace ).Delete (name , metav1 .NewDeleteOptions (0 ))
120
128
}
121
129
}
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