1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package iamclient
16
17 import (
18 "context"
19 "encoding/json"
20 "fmt"
21 "reflect"
22 "strings"
23
24 corekccv1alpha1 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/core/v1alpha1"
25 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/iam/v1beta1"
26 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/metadata"
27
28 "k8s.io/apimachinery/pkg/runtime/schema"
29 )
30
31 func (c *IAMClient) isDCLBasedIAMResource(iamInterface interface{}) bool {
32 _, resourceRef := extractNamespaceAndResourceReference(iamInterface)
33 return c.isDCLBasedResource(resourceRef.GroupVersionKind())
34 }
35
36 func (c *IAMClient) isDCLBasedResource(gvk schema.GroupVersionKind) bool {
37 return metadata.IsDCLBasedResourceKind(gvk, c.DCLIAMClient.converter.MetadataLoader)
38 }
39
40
41
42
43 func ResolveMemberIdentity(ctx context.Context, member v1beta1.Member,
44 memberFrom *v1beta1.MemberSource, namespace string, tfIAMClient *TFIAMClient) (id string, err error) {
45 if member != "" && memberFrom != nil {
46 return id, fmt.Errorf("both 'member' and 'memberFrom' are used. Exactly one of them must be used")
47 }
48
49 if member == "" && memberFrom == nil {
50 return id, fmt.Errorf("both 'member' and 'memberFrom' are empty. Exactly one of them must be used")
51 }
52
53 if member != "" {
54 return string(member), nil
55 }
56
57 var refs []*v1beta1.MemberReference
58 var gvks []schema.GroupVersionKind
59
60 if memberFrom.ServiceAccountRef != nil {
61 refs = append(refs, memberFrom.ServiceAccountRef)
62 gvks = append(gvks, IAMServiceAccountGVK)
63 }
64
65 if memberFrom.LogSinkRef != nil {
66 refs = append(refs, memberFrom.LogSinkRef)
67 gvks = append(gvks, LoggingLogSinkGVK)
68 }
69
70 if memberFrom.SQLInstanceRef != nil {
71 refs = append(refs, memberFrom.SQLInstanceRef)
72 gvks = append(gvks, SQLInstanceGVK)
73 }
74
75 if memberFrom.ServiceIdentityRef != nil {
76 refs = append(refs, memberFrom.ServiceIdentityRef)
77 gvks = append(gvks, ServiceIdentityGVK)
78 }
79
80 if len(refs) == 1 {
81 return tfIAMClient.resolveMemberReference(ctx, refs[0], gvks[0], namespace)
82 } else {
83 return id, fmt.Errorf("%v memberFrom refs found. Exactly one Of 'logSinkRef', 'serviceAccountRef', 'sqlInstanceRef', 'serviceIdentityRef' must be used", len(refs))
84 }
85 }
86
87 func extractNamespaceAndResourceReference(iamInterface interface{}) (string, v1beta1.ResourceReference) {
88 switch iamObject := iamInterface.(type) {
89 case *v1beta1.IAMPolicy:
90 return iamObject.Namespace, iamObject.Spec.ResourceReference
91 case *v1beta1.IAMPolicyMember:
92 return iamObject.Namespace, iamObject.Spec.ResourceReference
93 case *v1beta1.IAMAuditConfig:
94 return iamObject.Namespace, iamObject.Spec.ResourceReference
95 }
96 panic(fmt.Errorf("unknown type: %v", reflect.TypeOf(iamInterface).Name()))
97 }
98
99 func embedPolicyData(spec map[string]interface{}) error {
100 policyData, ok := spec["policyData"].(string)
101 if !ok {
102 return nil
103 }
104 delete(spec, "policyData")
105 m := make(map[string]interface{})
106 if err := json.Unmarshal([]byte(policyData), &m); err != nil {
107 return fmt.Errorf("error converting policyData '%v' to map: %w", policyData, err)
108 }
109 for k, v := range m {
110 spec[k] = v
111 }
112 return nil
113 }
114
115
116
117
118
119
120
121
122 func SetGVK(iamInterface interface{}) {
123 switch iamObject := iamInterface.(type) {
124 case *v1beta1.IAMPolicy:
125 setPolicyGVK(iamObject)
126 case *v1beta1.IAMPartialPolicy:
127 setPartialPolicyGVK(iamObject)
128 case *v1beta1.IAMPolicyMember:
129 setPolicyMemberGVK(iamObject)
130 case *v1beta1.IAMAuditConfig:
131 setAuditConfigGVK(iamObject)
132 default:
133 panic(fmt.Errorf("unknown type: %v", reflect.TypeOf(iamInterface).Name()))
134 }
135 }
136
137 func setPolicyGVK(policy *v1beta1.IAMPolicy) {
138 policy.SetGroupVersionKind(v1beta1.IAMPolicyGVK)
139 }
140
141 func setPartialPolicyGVK(partialPolicy *v1beta1.IAMPartialPolicy) {
142 partialPolicy.SetGroupVersionKind(v1beta1.IAMPartialPolicyGVK)
143 }
144
145 func setPolicyMemberGVK(policyMember *v1beta1.IAMPolicyMember) {
146 policyMember.SetGroupVersionKind(v1beta1.IAMPolicyMemberGVK)
147 }
148
149 func setAuditConfigGVK(auditConfig *v1beta1.IAMAuditConfig) {
150 auditConfig.SetGroupVersionKind(v1beta1.IAMAuditConfigGVK)
151 }
152
153 func resourceSupportsIAMPolicy(rc *corekccv1alpha1.ResourceConfig) bool {
154 return rc.IAMConfig.PolicyName != ""
155 }
156
157 func resourceSupportsIAMPolicyMember(rc *corekccv1alpha1.ResourceConfig) bool {
158 return rc.IAMConfig.PolicyMemberName != ""
159 }
160
161 func resourceSupportsIAMAuditConfigs(rc *corekccv1alpha1.ResourceConfig) bool {
162 return rc.IAMConfig.AuditConfigName != ""
163 }
164
165 func useIfNonEmptyElseDefaultTo(str, backup string) string {
166 if str != "" {
167 return str
168 }
169 return backup
170 }
171
172 func parseNameFromId(id string) (string, error) {
173 if strings.TrimSpace(id) == "" {
174 return "", fmt.Errorf("error parsing name from id: id is empty")
175 }
176 parts := strings.Split(id, "/")
177 return parts[len(parts)-1], nil
178 }
179
180 func idMatchesTemplate(id, idTemplate string) bool {
181 idTokens := strings.Split(id, "/")
182 idTemplateTokens := strings.Split(idTemplate, "/")
183 if len(idTokens) != len(idTemplateTokens) {
184 return false
185 }
186 for i := range idTokens {
187 if idTokens[i] != idTemplateTokens[i] &&
188 !idTemplateVarsRegex.MatchString(idTemplateTokens[i]) {
189 return false
190 }
191 }
192 return true
193 }
194
View as plain text