Skip to content

Commit 1410b4a

Browse files
committed
Modify installation steps for ClusterRoleBindings and Services to use SSA in order to avoid race conditions.
Signed-off-by: Daniel Franz <[email protected]>
1 parent 9f42a6f commit 1410b4a

File tree

6 files changed

+293
-116
lines changed

6 files changed

+293
-116
lines changed

pkg/controller/install/certresources.go

+61-82
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import (
1212
apierrors "k8s.io/apimachinery/pkg/api/errors"
1313
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1414
"k8s.io/apimachinery/pkg/util/intstr"
15+
corev1ac "k8s.io/client-go/applyconfigurations/core/v1"
16+
metav1ac "k8s.io/client-go/applyconfigurations/meta/v1"
17+
rbacv1ac "k8s.io/client-go/applyconfigurations/rbac/v1"
1518

1619
"github.com/operator-framework/api/pkg/operators/v1alpha1"
1720
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/certs"
@@ -241,43 +244,45 @@ func CalculateCertRotatesAt(certExpirationTime time.Time) time.Time {
241244
func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deploymentName string, ca *certs.KeyPair, expiration time.Time, depSpec appsv1.DeploymentSpec, ports []corev1.ServicePort) (*appsv1.DeploymentSpec, []byte, error) {
242245
logger := log.WithFields(log.Fields{})
243246

244-
// Create a service for the deployment
245-
service := &corev1.Service{
246-
Spec: corev1.ServiceSpec{
247-
Ports: ports,
248-
Selector: depSpec.Selector.MatchLabels,
249-
},
250-
}
251-
service.SetName(ServiceName(deploymentName))
252-
service.SetNamespace(i.owner.GetNamespace())
253-
ownerutil.AddNonBlockingOwner(service, i.owner)
254-
service.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue})
255-
256-
existingService, err := i.strategyClient.GetOpLister().CoreV1().ServiceLister().Services(i.owner.GetNamespace()).Get(service.GetName())
257-
if err == nil {
258-
if !ownerutil.Adoptable(i.owner, existingService.GetOwnerReferences()) {
259-
return nil, nil, fmt.Errorf("service %s not safe to replace: extraneous ownerreferences found", service.GetName())
260-
}
261-
service.SetOwnerReferences(existingService.GetOwnerReferences())
262-
263-
// Delete the Service to replace
264-
deleteErr := i.strategyClient.GetOpClient().DeleteService(service.GetNamespace(), service.GetName(), &metav1.DeleteOptions{})
265-
if deleteErr != nil && !apierrors.IsNotFound(deleteErr) {
266-
return nil, nil, fmt.Errorf("could not delete existing service %s", service.GetName())
267-
}
268-
}
269-
270-
// Attempt to create the Service
271-
_, err = i.strategyClient.GetOpClient().CreateService(service)
272-
if err != nil {
273-
logger.Warnf("could not create service %s", service.GetName())
274-
return nil, nil, fmt.Errorf("could not create service %s: %s", service.GetName(), err.Error())
247+
// apply Service
248+
serviceName := ServiceName(deploymentName)
249+
portsApplyConfig := []*corev1ac.ServicePortApplyConfiguration{}
250+
for _, p := range ports {
251+
ac := corev1ac.ServicePort().
252+
WithName(p.Name).
253+
WithPort(p.Port).
254+
WithTargetPort(p.TargetPort)
255+
portsApplyConfig = append(portsApplyConfig, ac)
256+
}
257+
258+
ownerRef := ownerutil.NonBlockingOwner(i.owner)
259+
ownerRefAC := metav1ac.OwnerReference().
260+
WithAPIVersion(ownerRef.APIVersion).
261+
WithKind(ownerRef.Kind).
262+
WithUID(ownerRef.UID).
263+
WithName(ownerRef.Name)
264+
if ownerRef.BlockOwnerDeletion != nil {
265+
ownerRefAC.WithBlockOwnerDeletion(*ownerRef.BlockOwnerDeletion)
266+
}
267+
if ownerRef.Controller != nil {
268+
ownerRefAC.WithController(*ownerRef.Controller)
269+
}
270+
svcApplyConfig := corev1ac.Service(serviceName, i.owner.GetNamespace()).
271+
WithSpec(corev1ac.ServiceSpec().
272+
WithPorts(portsApplyConfig...).
273+
WithSelector(depSpec.Selector.MatchLabels)).
274+
WithOwnerReferences(ownerRefAC).
275+
WithLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue})
276+
277+
if _, err := i.strategyClient.GetOpClient().ApplyService(svcApplyConfig, metav1.ApplyOptions{Force: true, FieldManager: "olm.install"}); err != nil {
278+
log.Errorf("could not apply service %s: %s", *svcApplyConfig.Name, err.Error())
279+
return nil, nil, err
275280
}
276281

277282
// Create signed serving cert
278283
hosts := []string{
279-
fmt.Sprintf("%s.%s", service.GetName(), i.owner.GetNamespace()),
280-
fmt.Sprintf("%s.%s.svc", service.GetName(), i.owner.GetNamespace()),
284+
fmt.Sprintf("%s.%s", serviceName, i.owner.GetNamespace()),
285+
fmt.Sprintf("%s.%s.svc", serviceName, i.owner.GetNamespace()),
281286
}
282287
servingPair, err := certGenerator.Generate(expiration, Organization, ca, hosts)
283288
if err != nil {
@@ -288,14 +293,14 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo
288293
// Create Secret for serving cert
289294
certPEM, privPEM, err := servingPair.ToPEM()
290295
if err != nil {
291-
logger.Warnf("unable to convert serving certificate and private key to PEM format for Service %s", service.GetName())
296+
logger.Warnf("unable to convert serving certificate and private key to PEM format for Service %s", serviceName)
292297
return nil, nil, err
293298
}
294299

295300
// Add olmcahash as a label to the caPEM
296301
caPEM, _, err := ca.ToPEM()
297302
if err != nil {
298-
logger.Warnf("unable to convert CA certificate to PEM format for Service %s", service)
303+
logger.Warnf("unable to convert CA certificate to PEM format for Service %s", serviceName)
299304
return nil, nil, err
300305
}
301306
caHash := certs.PEMSHA256(caPEM)
@@ -308,7 +313,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo
308313
},
309314
Type: corev1.SecretTypeTLS,
310315
}
311-
secret.SetName(SecretName(service.GetName()))
316+
secret.SetName(SecretName(serviceName))
312317
secret.SetNamespace(i.owner.GetNamespace())
313318
secret.SetAnnotations(map[string]string{OLMCAHashAnnotationKey: caHash})
314319
secret.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue})
@@ -440,51 +445,25 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo
440445
return nil, nil, err
441446
}
442447

443-
// create ClusterRoleBinding to system:auth-delegator Role
444-
authDelegatorClusterRoleBinding := &rbacv1.ClusterRoleBinding{
445-
Subjects: []rbacv1.Subject{
446-
{
447-
Kind: "ServiceAccount",
448-
APIGroup: "",
449-
Name: depSpec.Template.Spec.ServiceAccountName,
450-
Namespace: i.owner.GetNamespace(),
451-
},
452-
},
453-
RoleRef: rbacv1.RoleRef{
454-
APIGroup: "rbac.authorization.k8s.io",
455-
Kind: "ClusterRole",
456-
Name: "system:auth-delegator",
457-
},
458-
}
459-
authDelegatorClusterRoleBinding.SetName(AuthDelegatorClusterRoleBindingName(service.GetName()))
460-
authDelegatorClusterRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue})
461-
462-
existingAuthDelegatorClusterRoleBinding, err := i.strategyClient.GetOpLister().RbacV1().ClusterRoleBindingLister().Get(authDelegatorClusterRoleBinding.GetName())
463-
if err == nil {
464-
// Check if the only owners are this CSV or in this CSV's replacement chain.
465-
if ownerutil.AdoptableLabels(existingAuthDelegatorClusterRoleBinding.GetLabels(), true, i.owner) {
466-
logger.WithFields(log.Fields{"obj": "authDelegatorCRB", "labels": existingAuthDelegatorClusterRoleBinding.GetLabels()}).Debug("adopting")
467-
if err := ownerutil.AddOwnerLabels(authDelegatorClusterRoleBinding, i.owner); err != nil {
468-
return nil, nil, err
469-
}
470-
}
471-
472-
// Attempt an update.
473-
if _, err := i.strategyClient.GetOpClient().UpdateClusterRoleBinding(authDelegatorClusterRoleBinding); err != nil {
474-
logger.Warnf("could not update auth delegator clusterrolebinding %s", authDelegatorClusterRoleBinding.GetName())
475-
return nil, nil, err
476-
}
477-
} else if apierrors.IsNotFound(err) {
478-
// Create the role.
479-
if err := ownerutil.AddOwnerLabels(authDelegatorClusterRoleBinding, i.owner); err != nil {
480-
return nil, nil, err
481-
}
482-
_, err = i.strategyClient.GetOpClient().CreateClusterRoleBinding(authDelegatorClusterRoleBinding)
483-
if err != nil {
484-
log.Warnf("could not create auth delegator clusterrolebinding %s", authDelegatorClusterRoleBinding.GetName())
485-
return nil, nil, err
486-
}
487-
} else {
448+
// apply ClusterRoleBinding to system:auth-delegator Role
449+
crbLabels := map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}
450+
for key, val := range ownerutil.OwnerLabel(i.owner, i.owner.GetObjectKind().GroupVersionKind().Kind) {
451+
crbLabels[key] = val
452+
}
453+
crbApplyConfig := rbacv1ac.ClusterRoleBinding(AuthDelegatorClusterRoleBindingName(serviceName)).
454+
WithSubjects(rbacv1ac.Subject().
455+
WithKind("ServiceAccount").
456+
WithAPIGroup("").
457+
WithName(depSpec.Template.Spec.ServiceAccountName).
458+
WithNamespace(i.owner.GetNamespace())).
459+
WithRoleRef(rbacv1ac.RoleRef().
460+
WithAPIGroup("rbac.authorization.k8s.io").
461+
WithKind("ClusterRole").
462+
WithName("system:auth-delegator")).
463+
WithLabels(crbLabels)
464+
465+
if _, err = i.strategyClient.GetOpClient().ApplyClusterRoleBinding(crbApplyConfig, metav1.ApplyOptions{Force: true, FieldManager: "olm.install"}); err != nil {
466+
log.Errorf("could not apply auth delegator clusterrolebinding %s: %s", *crbApplyConfig.Name, err.Error())
488467
return nil, nil, err
489468
}
490469

@@ -504,7 +483,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo
504483
Name: "extension-apiserver-authentication-reader",
505484
},
506485
}
507-
authReaderRoleBinding.SetName(AuthReaderRoleBindingName(service.GetName()))
486+
authReaderRoleBinding.SetName(AuthReaderRoleBindingName(serviceName))
508487
authReaderRoleBinding.SetNamespace(KubeSystem)
509488
authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue})
510489

0 commit comments

Comments
 (0)