@@ -30,16 +30,17 @@ import (
3030 corev1 "k8s.io/api/core/v1"
3131 rbacv1 "k8s.io/api/rbac/v1"
3232 apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
33+ "sigs.k8s.io/controller-runtime/pkg/client"
3334
3435 "github.com/operator-framework/operator-sdk/internal/generate/collector"
3536 "github.com/operator-framework/operator-sdk/internal/util/k8sutil"
3637)
3738
3839// ApplyTo applies relevant manifests in c to csv, sorts the applied updates,
3940// and validates the result.
40- func ApplyTo (c * collector.Manifests , csv * operatorsv1alpha1.ClusterServiceVersion ) error {
41+ func ApplyTo (c * collector.Manifests , csv * operatorsv1alpha1.ClusterServiceVersion , extraSAs [] string ) error {
4142 // Apply manifests to the CSV object.
42- if err := apply (c , csv ); err != nil {
43+ if err := apply (c , csv , extraSAs ); err != nil {
4344 return err
4445 }
4546
@@ -50,12 +51,13 @@ func ApplyTo(c *collector.Manifests, csv *operatorsv1alpha1.ClusterServiceVersio
5051}
5152
5253// apply applies relevant manifests in c to csv.
53- func apply (c * collector.Manifests , csv * operatorsv1alpha1.ClusterServiceVersion ) error {
54+ func apply (c * collector.Manifests , csv * operatorsv1alpha1.ClusterServiceVersion , extraSAs [] string ) error {
5455 strategy := getCSVInstallStrategy (csv )
5556 switch strategy .StrategyName {
5657 case operatorsv1alpha1 .InstallStrategyNameDeployment :
57- applyRoles (c , & strategy .StrategySpec )
58- applyClusterRoles (c , & strategy .StrategySpec )
58+ inPerms , inCPerms , _ := c .SplitCSVPermissionsObjects (extraSAs )
59+ applyRoles (c , inPerms , & strategy .StrategySpec , extraSAs )
60+ applyClusterRoles (c , inCPerms , & strategy .StrategySpec , extraSAs )
5961 applyDeployments (c , & strategy .StrategySpec )
6062 }
6163 csv .Spec .InstallStrategy = strategy
@@ -82,34 +84,46 @@ const defaultServiceAccountName = "default"
8284
8385// applyRoles applies Roles to strategy's permissions field by combining Roles bound to ServiceAccounts
8486// into one set of permissions.
85- func applyRoles (c * collector.Manifests , strategy * operatorsv1alpha1.StrategyDetailsDeployment ) { //nolint:dupl
86- objs , _ := c . SplitCSVPermissionsObjects ( )
87- roleSet := make (map [string ]* rbacv1.Role )
87+ func applyRoles (c * collector.Manifests , objs []client. Object , strategy * operatorsv1alpha1.StrategyDetailsDeployment , extraSAs [] string ) { //nolint:dupl
88+ roleSet := make ( map [ string ]rbacv1. Role )
89+ cRoleSet := make (map [string ]rbacv1.ClusterRole )
8890 for i := range objs {
8991 switch t := objs [i ].(type ) {
9092 case * rbacv1.Role :
91- roleSet [t .GetName ()] = t
92- }
93- }
94-
95- saToPermissions := make (map [string ]operatorsv1alpha1.StrategyDeploymentPermissions )
96- for _ , dep := range c .Deployments {
97- saName := dep .Spec .Template .Spec .ServiceAccountName
98- if saName == "" {
99- saName = defaultServiceAccountName
93+ roleSet [t .GetName ()] = * t
94+ case * rbacv1.ClusterRole :
95+ cRoleSet [t .GetName ()] = * t
10096 }
101- saToPermissions [saName ] = operatorsv1alpha1.StrategyDeploymentPermissions {ServiceAccountName : saName }
10297 }
10398
104- // Collect all role names by their corresponding service accounts via bindings. This lets us
99+ // Collect all role and cluster role names by their corresponding service accounts via bindings. This lets us
105100 // look up all service accounts a role is bound to and create one set of permissions per service account.
101+ saToPermissions := initPermissionSet (c .Deployments , extraSAs )
106102 for _ , binding := range c .RoleBindings {
107- if role , hasRole := roleSet [binding .RoleRef .Name ]; hasRole {
108- for _ , subject := range binding .Subjects {
109- if perm , hasSA := saToPermissions [subject .Name ]; hasSA && subject .Kind == "ServiceAccount" {
110- perm .Rules = append (perm .Rules , role .Rules ... )
111- saToPermissions [subject .Name ] = perm
112- }
103+ for _ , subject := range binding .Subjects {
104+ perm , hasSA := saToPermissions [subject .Name ]
105+ if subject .Kind != "ServiceAccount" || ! hasSA {
106+ continue
107+ }
108+ var (
109+ rules []rbacv1.PolicyRule
110+ hasRole bool
111+ )
112+ switch binding .RoleRef .Kind {
113+ case "Role" :
114+ role , has := roleSet [binding .RoleRef .Name ]
115+ rules = role .Rules
116+ hasRole = has
117+ case "ClusterRole" :
118+ role , has := cRoleSet [binding .RoleRef .Name ]
119+ rules = role .Rules
120+ hasRole = has
121+ default :
122+ continue
123+ }
124+ if hasRole {
125+ perm .Rules = append (perm .Rules , rules ... )
126+ saToPermissions [subject .Name ] = perm
113127 }
114128 }
115129 }
@@ -121,39 +135,35 @@ func applyRoles(c *collector.Manifests, strategy *operatorsv1alpha1.StrategyDeta
121135 perms = append (perms , perm )
122136 }
123137 }
138+ sort .Slice (perms , func (i , j int ) bool {
139+ return perms [i ].ServiceAccountName < perms [j ].ServiceAccountName
140+ })
124141 strategy .Permissions = perms
125142}
126143
127144// applyClusterRoles applies ClusterRoles to strategy's clusterPermissions field by combining ClusterRoles
128145// bound to ServiceAccounts into one set of clusterPermissions.
129- func applyClusterRoles (c * collector.Manifests , strategy * operatorsv1alpha1.StrategyDetailsDeployment ) { //nolint:dupl
130- objs , _ := c .SplitCSVClusterPermissionsObjects ()
131- roleSet := make (map [string ]* rbacv1.ClusterRole )
146+ func applyClusterRoles (c * collector.Manifests , objs []client.Object , strategy * operatorsv1alpha1.StrategyDetailsDeployment , extraSAs []string ) { //nolint:dupl
147+ roleSet := make (map [string ]rbacv1.ClusterRole )
132148 for i := range objs {
133149 switch t := objs [i ].(type ) {
134150 case * rbacv1.ClusterRole :
135- roleSet [t .GetName ()] = t
151+ roleSet [t .GetName ()] = * t
136152 }
137153 }
138154
139- saToPermissions := make (map [string ]operatorsv1alpha1.StrategyDeploymentPermissions )
140- for _ , dep := range c .Deployments {
141- saName := dep .Spec .Template .Spec .ServiceAccountName
142- if saName == "" {
143- saName = defaultServiceAccountName
144- }
145- saToPermissions [saName ] = operatorsv1alpha1.StrategyDeploymentPermissions {ServiceAccountName : saName }
146- }
147-
148155 // Collect all role names by their corresponding service accounts via bindings. This lets us
149156 // look up all service accounts a role is bound to and create one set of permissions per service account.
157+ saToPermissions := initPermissionSet (c .Deployments , extraSAs )
150158 for _ , binding := range c .ClusterRoleBindings {
151- if role , hasRole := roleSet [binding .RoleRef .Name ]; hasRole {
152- for _ , subject := range binding .Subjects {
153- if perm , hasSA := saToPermissions [subject .Name ]; hasSA && subject .Kind == "ServiceAccount" {
154- perm .Rules = append (perm .Rules , role .Rules ... )
155- saToPermissions [subject .Name ] = perm
156- }
159+ for _ , subject := range binding .Subjects {
160+ perm , hasSA := saToPermissions [subject .Name ]
161+ if ! hasSA || subject .Kind != "ServiceAccount" {
162+ continue
163+ }
164+ if role , hasRole := roleSet [binding .RoleRef .Name ]; hasRole {
165+ perm .Rules = append (perm .Rules , role .Rules ... )
166+ saToPermissions [subject .Name ] = perm
157167 }
158168 }
159169 }
@@ -165,9 +175,28 @@ func applyClusterRoles(c *collector.Manifests, strategy *operatorsv1alpha1.Strat
165175 perms = append (perms , perm )
166176 }
167177 }
178+ sort .Slice (perms , func (i , j int ) bool {
179+ return perms [i ].ServiceAccountName < perms [j ].ServiceAccountName
180+ })
168181 strategy .ClusterPermissions = perms
169182}
170183
184+ // initPermissionSet initializes a map of ServiceAccount name to permissions, which are empty.
185+ func initPermissionSet (deps []appsv1.Deployment , extraSAs []string ) map [string ]operatorsv1alpha1.StrategyDeploymentPermissions {
186+ saToPermissions := make (map [string ]operatorsv1alpha1.StrategyDeploymentPermissions )
187+ for _ , dep := range deps {
188+ saName := dep .Spec .Template .Spec .ServiceAccountName
189+ if saName == "" {
190+ saName = defaultServiceAccountName
191+ }
192+ saToPermissions [saName ] = operatorsv1alpha1.StrategyDeploymentPermissions {ServiceAccountName : saName }
193+ }
194+ for _ , extraSA := range extraSAs {
195+ saToPermissions [extraSA ] = operatorsv1alpha1.StrategyDeploymentPermissions {ServiceAccountName : extraSA }
196+ }
197+ return saToPermissions
198+ }
199+
171200// applyDeployments updates strategy's deployments with the Deployments
172201// in the collector.
173202func applyDeployments (c * collector.Manifests , strategy * operatorsv1alpha1.StrategyDetailsDeployment ) {
0 commit comments