gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/authz/rbac_translator.go (about) 1 /* 2 * Copyright 2021 gRPC authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // Package authz exposes methods to manage authorization within gRPC. 18 // 19 // # Experimental 20 // 21 // Notice: This package is EXPERIMENTAL and may be changed or removed 22 // in a later release. 23 package authz 24 25 import ( 26 "bytes" 27 "encoding/json" 28 "fmt" 29 "strings" 30 31 v3rbacpb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/config/rbac/v3" 32 v3routepb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/config/route/v3" 33 v3matcherpb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/type/matcher/v3" 34 ) 35 36 type header struct { 37 Key string 38 Values []string 39 } 40 41 type peer struct { 42 Principals []string 43 } 44 45 type request struct { 46 Paths []string 47 Headers []header 48 } 49 50 type rule struct { 51 Name string 52 Source peer 53 Request request 54 } 55 56 // Represents the SDK authorization policy provided by user. 57 type authorizationPolicy struct { 58 Name string 59 DenyRules []rule `json:"deny_rules"` 60 AllowRules []rule `json:"allow_rules"` 61 } 62 63 func principalOr(principals []*v3rbacpb.Principal) *v3rbacpb.Principal { 64 return &v3rbacpb.Principal{ 65 Identifier: &v3rbacpb.Principal_OrIds{ 66 OrIds: &v3rbacpb.Principal_Set{ 67 Ids: principals, 68 }, 69 }, 70 } 71 } 72 73 func permissionOr(permission []*v3rbacpb.Permission) *v3rbacpb.Permission { 74 return &v3rbacpb.Permission{ 75 Rule: &v3rbacpb.Permission_OrRules{ 76 OrRules: &v3rbacpb.Permission_Set{ 77 Rules: permission, 78 }, 79 }, 80 } 81 } 82 83 func permissionAnd(permission []*v3rbacpb.Permission) *v3rbacpb.Permission { 84 return &v3rbacpb.Permission{ 85 Rule: &v3rbacpb.Permission_AndRules{ 86 AndRules: &v3rbacpb.Permission_Set{ 87 Rules: permission, 88 }, 89 }, 90 } 91 } 92 93 func getStringMatcher(value string) *v3matcherpb.StringMatcher { 94 switch { 95 case value == "*": 96 return &v3matcherpb.StringMatcher{ 97 MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{ 98 SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}}, 99 } 100 case strings.HasSuffix(value, "*"): 101 prefix := strings.TrimSuffix(value, "*") 102 return &v3matcherpb.StringMatcher{ 103 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: prefix}, 104 } 105 case strings.HasPrefix(value, "*"): 106 suffix := strings.TrimPrefix(value, "*") 107 return &v3matcherpb.StringMatcher{ 108 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: suffix}, 109 } 110 default: 111 return &v3matcherpb.StringMatcher{ 112 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: value}, 113 } 114 } 115 } 116 117 func getHeaderMatcher(key, value string) *v3routepb.HeaderMatcher { 118 switch { 119 case value == "*": 120 return &v3routepb.HeaderMatcher{ 121 Name: key, 122 HeaderMatchSpecifier: &v3routepb.HeaderMatcher_SafeRegexMatch{ 123 SafeRegexMatch: &v3matcherpb.RegexMatcher{Regex: ".+"}}, 124 } 125 case strings.HasSuffix(value, "*"): 126 prefix := strings.TrimSuffix(value, "*") 127 return &v3routepb.HeaderMatcher{ 128 Name: key, 129 HeaderMatchSpecifier: &v3routepb.HeaderMatcher_PrefixMatch{PrefixMatch: prefix}, 130 } 131 case strings.HasPrefix(value, "*"): 132 suffix := strings.TrimPrefix(value, "*") 133 return &v3routepb.HeaderMatcher{ 134 Name: key, 135 HeaderMatchSpecifier: &v3routepb.HeaderMatcher_SuffixMatch{SuffixMatch: suffix}, 136 } 137 default: 138 return &v3routepb.HeaderMatcher{ 139 Name: key, 140 HeaderMatchSpecifier: &v3routepb.HeaderMatcher_ExactMatch{ExactMatch: value}, 141 } 142 } 143 } 144 145 func parsePrincipalNames(principalNames []string) []*v3rbacpb.Principal { 146 ps := make([]*v3rbacpb.Principal, 0, len(principalNames)) 147 for _, principalName := range principalNames { 148 newPrincipalName := &v3rbacpb.Principal{ 149 Identifier: &v3rbacpb.Principal_Authenticated_{ 150 Authenticated: &v3rbacpb.Principal_Authenticated{ 151 PrincipalName: getStringMatcher(principalName), 152 }, 153 }} 154 ps = append(ps, newPrincipalName) 155 } 156 return ps 157 } 158 159 func parsePeer(source peer) *v3rbacpb.Principal { 160 if len(source.Principals) == 0 { 161 return &v3rbacpb.Principal{ 162 Identifier: &v3rbacpb.Principal_Any{ 163 Any: true, 164 }, 165 } 166 } 167 return principalOr(parsePrincipalNames(source.Principals)) 168 } 169 170 func parsePaths(paths []string) []*v3rbacpb.Permission { 171 ps := make([]*v3rbacpb.Permission, 0, len(paths)) 172 for _, path := range paths { 173 newPath := &v3rbacpb.Permission{ 174 Rule: &v3rbacpb.Permission_UrlPath{ 175 UrlPath: &v3matcherpb.PathMatcher{ 176 Rule: &v3matcherpb.PathMatcher_Path{Path: getStringMatcher(path)}}}} 177 ps = append(ps, newPath) 178 } 179 return ps 180 } 181 182 func parseHeaderValues(key string, values []string) []*v3rbacpb.Permission { 183 vs := make([]*v3rbacpb.Permission, 0, len(values)) 184 for _, value := range values { 185 newHeader := &v3rbacpb.Permission{ 186 Rule: &v3rbacpb.Permission_Header{ 187 Header: getHeaderMatcher(key, value)}} 188 vs = append(vs, newHeader) 189 } 190 return vs 191 } 192 193 var unsupportedHeaders = map[string]bool{ 194 "host": true, 195 "connection": true, 196 "keep-alive": true, 197 "proxy-authenticate": true, 198 "proxy-authorization": true, 199 "te": true, 200 "trailer": true, 201 "transfer-encoding": true, 202 "upgrade": true, 203 } 204 205 func unsupportedHeader(key string) bool { 206 return key[0] == ':' || strings.HasPrefix(key, "grpc-") || unsupportedHeaders[key] 207 } 208 209 func parseHeaders(headers []header) ([]*v3rbacpb.Permission, error) { 210 hs := make([]*v3rbacpb.Permission, 0, len(headers)) 211 for i, header := range headers { 212 if header.Key == "" { 213 return nil, fmt.Errorf(`"headers" %d: "key" is not present`, i) 214 } 215 header.Key = strings.ToLower(header.Key) 216 if unsupportedHeader(header.Key) { 217 return nil, fmt.Errorf(`"headers" %d: unsupported "key" %s`, i, header.Key) 218 } 219 if len(header.Values) == 0 { 220 return nil, fmt.Errorf(`"headers" %d: "values" is not present`, i) 221 } 222 values := parseHeaderValues(header.Key, header.Values) 223 hs = append(hs, permissionOr(values)) 224 } 225 return hs, nil 226 } 227 228 func parseRequest(request request) (*v3rbacpb.Permission, error) { 229 var and []*v3rbacpb.Permission 230 if len(request.Paths) > 0 { 231 and = append(and, permissionOr(parsePaths(request.Paths))) 232 } 233 if len(request.Headers) > 0 { 234 headers, err := parseHeaders(request.Headers) 235 if err != nil { 236 return nil, err 237 } 238 and = append(and, permissionAnd(headers)) 239 } 240 if len(and) > 0 { 241 return permissionAnd(and), nil 242 } 243 return &v3rbacpb.Permission{ 244 Rule: &v3rbacpb.Permission_Any{ 245 Any: true, 246 }, 247 }, nil 248 } 249 250 func parseRules(rules []rule, prefixName string) (map[string]*v3rbacpb.Policy, error) { 251 policies := make(map[string]*v3rbacpb.Policy) 252 for i, rule := range rules { 253 if rule.Name == "" { 254 return policies, fmt.Errorf(`%d: "name" is not present`, i) 255 } 256 permission, err := parseRequest(rule.Request) 257 if err != nil { 258 return nil, fmt.Errorf("%d: %v", i, err) 259 } 260 policyName := prefixName + "_" + rule.Name 261 policies[policyName] = &v3rbacpb.Policy{ 262 Principals: []*v3rbacpb.Principal{parsePeer(rule.Source)}, 263 Permissions: []*v3rbacpb.Permission{permission}, 264 } 265 } 266 return policies, nil 267 } 268 269 // translatePolicy translates SDK authorization policy in JSON format to two 270 // Envoy RBAC polices (deny followed by allow policy) or only one Envoy RBAC 271 // allow policy. If the input policy cannot be parsed or is invalid, an error 272 // will be returned. 273 func translatePolicy(policyStr string) ([]*v3rbacpb.RBAC, error) { 274 policy := &authorizationPolicy{} 275 d := json.NewDecoder(bytes.NewReader([]byte(policyStr))) 276 d.DisallowUnknownFields() 277 if err := d.Decode(policy); err != nil { 278 return nil, fmt.Errorf("failed to unmarshal policy: %v", err) 279 } 280 if policy.Name == "" { 281 return nil, fmt.Errorf(`"name" is not present`) 282 } 283 if len(policy.AllowRules) == 0 { 284 return nil, fmt.Errorf(`"allow_rules" is not present`) 285 } 286 rbacs := make([]*v3rbacpb.RBAC, 0, 2) 287 if len(policy.DenyRules) > 0 { 288 denyPolicies, err := parseRules(policy.DenyRules, policy.Name) 289 if err != nil { 290 return nil, fmt.Errorf(`"deny_rules" %v`, err) 291 } 292 denyRBAC := &v3rbacpb.RBAC{ 293 Action: v3rbacpb.RBAC_DENY, 294 Policies: denyPolicies, 295 } 296 rbacs = append(rbacs, denyRBAC) 297 } 298 allowPolicies, err := parseRules(policy.AllowRules, policy.Name) 299 if err != nil { 300 return nil, fmt.Errorf(`"allow_rules" %v`, err) 301 } 302 allowRBAC := &v3rbacpb.RBAC{Action: v3rbacpb.RBAC_ALLOW, Policies: allowPolicies} 303 return append(rbacs, allowRBAC), nil 304 }