1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package partialpolicy
16
17 import (
18 "fmt"
19 "sort"
20
21 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/iam/v1beta1"
22 )
23
24 type MemberIdentityResolver interface {
25 Resolve(v1beta1.Member, *v1beta1.MemberSource, string) (string, error)
26 }
27
28 type iamBindingKey struct {
29 Role string
30 Condition v1beta1.IAMCondition
31 }
32
33
34
35
36
37
38
39
40 func ComputePartialPolicyWithMergedBindings(partialPolicy *v1beta1.IAMPartialPolicy, livePolicy *v1beta1.IAMPolicy, resolver MemberIdentityResolver) (*v1beta1.IAMPartialPolicy, error) {
41 desiredPartialPolicy := partialPolicy.DeepCopy()
42 specifiedBindings, err := ConvertIAMPartialBindingsToIAMPolicyBindings(partialPolicy, resolver)
43 if err != nil {
44 return nil, fmt.Errorf("error converting IAMPartialPolicy bindings to IAMPolicy bindings: %w", err)
45 }
46
47
48 mergeBindings := mergeBindingSlices(specifiedBindings, livePolicy.Spec.Bindings)
49
50 toRemove := computeDeletedMembersPerBinding(specifiedBindings, partialPolicy.Status.LastAppliedBindings)
51
52 desiredAllBindings := removeMembersPerBinding(mergeBindings, toRemove)
53
54
55 sortBindingSlice(specifiedBindings)
56 desiredPartialPolicy.Status.LastAppliedBindings = specifiedBindings
57 sortBindingSlice(desiredAllBindings)
58 desiredPartialPolicy.Status.AllBindings = desiredAllBindings
59 return desiredPartialPolicy, nil
60 }
61
62
63
64
65
66
67
68
69 func ComputePartialPolicyWithRemainingBindings(partialPolicy *v1beta1.IAMPartialPolicy, livePolicy *v1beta1.IAMPolicy) *v1beta1.IAMPartialPolicy {
70 desiredPartialPolicy := partialPolicy.DeepCopy()
71 remainingBindings := removeMembersPerBinding(livePolicy.Spec.Bindings, partialPolicy.Status.LastAppliedBindings)
72
73 sortBindingSlice(remainingBindings)
74 desiredPartialPolicy.Status.AllBindings = remainingBindings
75
76 desiredPartialPolicy.Status.LastAppliedBindings = make([]v1beta1.IAMPolicyBinding, 0)
77 return desiredPartialPolicy
78 }
79
80 func ConvertIAMPartialBindingsToIAMPolicyBindings(partialPolicy *v1beta1.IAMPartialPolicy, resolver MemberIdentityResolver) (bindings []v1beta1.IAMPolicyBinding, err error) {
81 res := make([]v1beta1.IAMPolicyBinding, 0)
82 for _, binding := range partialPolicy.Spec.Bindings {
83 convertedBinding, err := toIAMPolicyBinding(binding, resolver, partialPolicy.Namespace)
84 if err != nil {
85 return bindings, fmt.Errorf("error converting IAMPartialPolicy binding to IAMPolicy binding: %w", err)
86 }
87 res = append(res, convertedBinding)
88 }
89 return mergeBindingsWithSameRoleAndCondition(res), nil
90 }
91
92 func toIAMPolicyBinding(b v1beta1.IAMPartialPolicyBinding, resolver MemberIdentityResolver, defaultNamespace string) (binding v1beta1.IAMPolicyBinding, err error) {
93 members := make([]v1beta1.Member, 0)
94 for _, m := range b.Members {
95 resolvedMember, err := resolver.Resolve(m.Member, m.MemberFrom, defaultNamespace)
96 if err != nil {
97 return binding, fmt.Errorf("error resolving member identity of IAMPartialPolicy binding: %w", err)
98 }
99 members = append(members, v1beta1.Member(resolvedMember))
100 }
101
102 return v1beta1.IAMPolicyBinding{
103 Role: b.Role,
104 Condition: b.Condition,
105 Members: members,
106 }, nil
107 }
108
109 func mergeBindingsWithSameRoleAndCondition(bindings []v1beta1.IAMPolicyBinding) []v1beta1.IAMPolicyBinding {
110 bindingMap := mergeBindings(bindings)
111 mergedBindings := make([]v1beta1.IAMPolicyBinding, 0)
112 for _, v := range bindingMap {
113 if len(v.Members) > 0 {
114 mergedBindings = append(mergedBindings, v)
115 }
116 }
117 return mergedBindings
118 }
119
120 func mergeBindingSlices(bindingSlice1, bindingSlice2 []v1beta1.IAMPolicyBinding) []v1beta1.IAMPolicyBinding {
121 mergedBindings := make([]v1beta1.IAMPolicyBinding, 0)
122 mergedBindings = append(mergedBindings, bindingSlice1...)
123 mergedBindings = append(mergedBindings, bindingSlice2...)
124 return mergeBindingsWithSameRoleAndCondition(mergedBindings)
125 }
126
127 func mergeBindings(bindings []v1beta1.IAMPolicyBinding) map[iamBindingKey]v1beta1.IAMPolicyBinding {
128 bindingMap := make(map[iamBindingKey]v1beta1.IAMPolicyBinding)
129 for _, a := range bindings {
130 k := getIamBindingKey(a)
131 b, ok := bindingMap[k]
132 if !ok {
133 bindingMap[k] = *a.DeepCopy()
134 continue
135 }
136 b.Members = mergeMembers(b.Members, a.Members)
137 bindingMap[k] = b
138 }
139 return bindingMap
140 }
141
142 func computeDeletedMembersPerBinding(bindings, lastAppliedBindings []v1beta1.IAMPolicyBinding) []v1beta1.IAMPolicyBinding {
143 res := make([]v1beta1.IAMPolicyBinding, 0)
144 bindingMap := mergeBindings(bindings)
145 lastAppliedBindingMap := mergeBindings(lastAppliedBindings)
146 for k, a := range lastAppliedBindingMap {
147 b, ok := bindingMap[k]
148 if !ok {
149 res = append(res, *a.DeepCopy())
150 continue
151 }
152 removedMembers := computeDeletedMembers(b.Members, a.Members)
153 if len(removedMembers) > 0 {
154 b.Members = removedMembers
155 res = append(res, b)
156 }
157 }
158 return res
159 }
160
161 func getIamBindingKey(binding v1beta1.IAMPolicyBinding) iamBindingKey {
162 k := iamBindingKey{}
163 k.Role = binding.Role
164 if binding.Condition != nil {
165 k.Condition = *binding.Condition
166 }
167 return k
168 }
169
170 func removeMembersPerBinding(bindings, deletedBindings []v1beta1.IAMPolicyBinding) []v1beta1.IAMPolicyBinding {
171 bindingMap := mergeBindings(bindings)
172 for _, a := range deletedBindings {
173 k := getIamBindingKey(a)
174 if b, ok := bindingMap[k]; ok {
175 b.Members = removeDeletedMembers(b.Members, a.Members)
176 bindingMap[k] = b
177 }
178 }
179 res := make([]v1beta1.IAMPolicyBinding, 0)
180 for _, b := range bindingMap {
181 if len(b.Members) > 0 {
182 res = append(res, b)
183 }
184 }
185 return res
186 }
187
188 func removeDeletedMembers(members, deletedMembers []v1beta1.Member) []v1beta1.Member {
189 memberMap := make(map[v1beta1.Member]bool)
190 for _, m := range deletedMembers {
191 memberMap[m] = true
192 }
193 res := make([]v1beta1.Member, 0)
194 for _, m := range members {
195 if _, ok := memberMap[m]; !ok {
196 res = append(res, m)
197 }
198 }
199 return res
200 }
201
202 func computeDeletedMembers(members, lastAppliedMembers []v1beta1.Member) []v1beta1.Member {
203 memberMap := make(map[v1beta1.Member]bool)
204 res := make([]v1beta1.Member, 0)
205 for _, m := range members {
206 memberMap[m] = true
207 }
208 for _, m := range lastAppliedMembers {
209 if _, ok := memberMap[m]; !ok {
210 res = append(res, m)
211 }
212 }
213 return res
214 }
215
216 func mergeMembers(memberSlice1, memberSlice2 []v1beta1.Member) []v1beta1.Member {
217 memberMap := make(map[v1beta1.Member]bool)
218 for _, m := range memberSlice1 {
219 memberMap[m] = true
220 }
221 for _, m := range memberSlice2 {
222 memberMap[m] = true
223 }
224 res := make([]v1beta1.Member, 0)
225 for k, _ := range memberMap {
226 res = append(res, k)
227 }
228 sort.Slice(res, func(i, j int) bool {
229 return res[i] < res[j]
230 })
231 return res
232 }
233
234 func sortBindingSlice(bindings []v1beta1.IAMPolicyBinding) {
235 sort.Slice(bindings, func(i, j int) bool {
236 k1 := getIamBindingKey(bindings[i])
237 k2 := getIamBindingKey(bindings[j])
238 if k1.Role != k2.Role {
239 return k1.Role < k2.Role
240 }
241 if k1.Condition.Title != k2.Condition.Title {
242 return k1.Condition.Title < k2.Condition.Title
243 }
244 if k1.Condition.Description != k2.Condition.Description {
245 return k1.Condition.Description < k2.Condition.Description
246 }
247 if k1.Condition.Expression != k2.Condition.Expression {
248 return k1.Condition.Expression < k2.Condition.Expression
249 }
250 return false
251 })
252 }
253
View as plain text