matchers.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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. package rbac
  17. import (
  18. "errors"
  19. "fmt"
  20. "net"
  21. "regexp"
  22. v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
  23. v3rbacpb "github.com/envoyproxy/go-control-plane/envoy/config/rbac/v3"
  24. v3route_componentspb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
  25. v3matcherpb "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
  26. internalmatcher "google.golang.org/grpc/internal/xds/matcher"
  27. )
  28. // matcher is an interface that takes data about incoming RPC's and returns
  29. // whether it matches with whatever matcher implements this interface.
  30. type matcher interface {
  31. match(data *rpcData) bool
  32. }
  33. // policyMatcher helps determine whether an incoming RPC call matches a policy.
  34. // A policy is a logical role (e.g. Service Admin), which is comprised of
  35. // permissions and principals. A principal is an identity (or identities) for a
  36. // downstream subject which are assigned the policy (role), and a permission is
  37. // an action(s) that a principal(s) can take. A policy matches if both a
  38. // permission and a principal match, which will be determined by the child or
  39. // permissions and principal matchers. policyMatcher implements the matcher
  40. // interface.
  41. type policyMatcher struct {
  42. permissions *orMatcher
  43. principals *orMatcher
  44. }
  45. func newPolicyMatcher(policy *v3rbacpb.Policy) (*policyMatcher, error) {
  46. permissions, err := matchersFromPermissions(policy.Permissions)
  47. if err != nil {
  48. return nil, err
  49. }
  50. principals, err := matchersFromPrincipals(policy.Principals)
  51. if err != nil {
  52. return nil, err
  53. }
  54. return &policyMatcher{
  55. permissions: &orMatcher{matchers: permissions},
  56. principals: &orMatcher{matchers: principals},
  57. }, nil
  58. }
  59. func (pm *policyMatcher) match(data *rpcData) bool {
  60. // A policy matches if and only if at least one of its permissions match the
  61. // action taking place AND at least one if its principals match the
  62. // downstream peer.
  63. return pm.permissions.match(data) && pm.principals.match(data)
  64. }
  65. // matchersFromPermissions takes a list of permissions (can also be
  66. // a single permission, e.g. from a not matcher which is logically !permission)
  67. // and returns a list of matchers which correspond to that permission. This will
  68. // be called in many instances throughout the initial construction of the RBAC
  69. // engine from the AND and OR matchers and also from the NOT matcher.
  70. func matchersFromPermissions(permissions []*v3rbacpb.Permission) ([]matcher, error) {
  71. var matchers []matcher
  72. for _, permission := range permissions {
  73. switch permission.GetRule().(type) {
  74. case *v3rbacpb.Permission_AndRules:
  75. mList, err := matchersFromPermissions(permission.GetAndRules().Rules)
  76. if err != nil {
  77. return nil, err
  78. }
  79. matchers = append(matchers, &andMatcher{matchers: mList})
  80. case *v3rbacpb.Permission_OrRules:
  81. mList, err := matchersFromPermissions(permission.GetOrRules().Rules)
  82. if err != nil {
  83. return nil, err
  84. }
  85. matchers = append(matchers, &orMatcher{matchers: mList})
  86. case *v3rbacpb.Permission_Any:
  87. matchers = append(matchers, &alwaysMatcher{})
  88. case *v3rbacpb.Permission_Header:
  89. m, err := newHeaderMatcher(permission.GetHeader())
  90. if err != nil {
  91. return nil, err
  92. }
  93. matchers = append(matchers, m)
  94. case *v3rbacpb.Permission_UrlPath:
  95. m, err := newURLPathMatcher(permission.GetUrlPath())
  96. if err != nil {
  97. return nil, err
  98. }
  99. matchers = append(matchers, m)
  100. case *v3rbacpb.Permission_DestinationIp:
  101. // Due to this being on server side, the destination IP is the local
  102. // IP.
  103. m, err := newLocalIPMatcher(permission.GetDestinationIp())
  104. if err != nil {
  105. return nil, err
  106. }
  107. matchers = append(matchers, m)
  108. case *v3rbacpb.Permission_DestinationPort:
  109. matchers = append(matchers, newPortMatcher(permission.GetDestinationPort()))
  110. case *v3rbacpb.Permission_NotRule:
  111. mList, err := matchersFromPermissions([]*v3rbacpb.Permission{{Rule: permission.GetNotRule().Rule}})
  112. if err != nil {
  113. return nil, err
  114. }
  115. matchers = append(matchers, &notMatcher{matcherToNot: mList[0]})
  116. case *v3rbacpb.Permission_Metadata:
  117. // Never matches - so no-op if not inverted, always match if
  118. // inverted.
  119. if permission.GetMetadata().GetInvert() { // Test metadata being no-op and also metadata with invert always matching
  120. matchers = append(matchers, &alwaysMatcher{})
  121. }
  122. case *v3rbacpb.Permission_RequestedServerName:
  123. // Not supported in gRPC RBAC currently - a permission typed as
  124. // requested server name in the initial config will be a no-op.
  125. }
  126. }
  127. return matchers, nil
  128. }
  129. func matchersFromPrincipals(principals []*v3rbacpb.Principal) ([]matcher, error) {
  130. var matchers []matcher
  131. for _, principal := range principals {
  132. switch principal.GetIdentifier().(type) {
  133. case *v3rbacpb.Principal_AndIds:
  134. mList, err := matchersFromPrincipals(principal.GetAndIds().Ids)
  135. if err != nil {
  136. return nil, err
  137. }
  138. matchers = append(matchers, &andMatcher{matchers: mList})
  139. case *v3rbacpb.Principal_OrIds:
  140. mList, err := matchersFromPrincipals(principal.GetOrIds().Ids)
  141. if err != nil {
  142. return nil, err
  143. }
  144. matchers = append(matchers, &orMatcher{matchers: mList})
  145. case *v3rbacpb.Principal_Any:
  146. matchers = append(matchers, &alwaysMatcher{})
  147. case *v3rbacpb.Principal_Authenticated_:
  148. authenticatedMatcher, err := newAuthenticatedMatcher(principal.GetAuthenticated())
  149. if err != nil {
  150. return nil, err
  151. }
  152. matchers = append(matchers, authenticatedMatcher)
  153. case *v3rbacpb.Principal_DirectRemoteIp:
  154. m, err := newRemoteIPMatcher(principal.GetDirectRemoteIp())
  155. if err != nil {
  156. return nil, err
  157. }
  158. matchers = append(matchers, m)
  159. case *v3rbacpb.Principal_Header:
  160. // Do we need an error here?
  161. m, err := newHeaderMatcher(principal.GetHeader())
  162. if err != nil {
  163. return nil, err
  164. }
  165. matchers = append(matchers, m)
  166. case *v3rbacpb.Principal_UrlPath:
  167. m, err := newURLPathMatcher(principal.GetUrlPath())
  168. if err != nil {
  169. return nil, err
  170. }
  171. matchers = append(matchers, m)
  172. case *v3rbacpb.Principal_NotId:
  173. mList, err := matchersFromPrincipals([]*v3rbacpb.Principal{{Identifier: principal.GetNotId().Identifier}})
  174. if err != nil {
  175. return nil, err
  176. }
  177. matchers = append(matchers, &notMatcher{matcherToNot: mList[0]})
  178. case *v3rbacpb.Principal_SourceIp:
  179. // The source ip principal identifier is deprecated. Thus, a
  180. // principal typed as a source ip in the identifier will be a no-op.
  181. // The config should use DirectRemoteIp instead.
  182. case *v3rbacpb.Principal_RemoteIp:
  183. // RBAC in gRPC treats direct_remote_ip and remote_ip as logically
  184. // equivalent, as per A41.
  185. m, err := newRemoteIPMatcher(principal.GetRemoteIp())
  186. if err != nil {
  187. return nil, err
  188. }
  189. matchers = append(matchers, m)
  190. case *v3rbacpb.Principal_Metadata:
  191. // Not supported in gRPC RBAC currently - a principal typed as
  192. // Metadata in the initial config will be a no-op.
  193. }
  194. }
  195. return matchers, nil
  196. }
  197. // orMatcher is a matcher where it successfully matches if one of it's
  198. // children successfully match. It also logically represents a principal or
  199. // permission, but can also be it's own entity further down the tree of
  200. // matchers. orMatcher implements the matcher interface.
  201. type orMatcher struct {
  202. matchers []matcher
  203. }
  204. func (om *orMatcher) match(data *rpcData) bool {
  205. // Range through child matchers and pass in data about incoming RPC, and
  206. // only one child matcher has to match to be logically successful.
  207. for _, m := range om.matchers {
  208. if m.match(data) {
  209. return true
  210. }
  211. }
  212. return false
  213. }
  214. // andMatcher is a matcher that is successful if every child matcher
  215. // matches. andMatcher implements the matcher interface.
  216. type andMatcher struct {
  217. matchers []matcher
  218. }
  219. func (am *andMatcher) match(data *rpcData) bool {
  220. for _, m := range am.matchers {
  221. if !m.match(data) {
  222. return false
  223. }
  224. }
  225. return true
  226. }
  227. // alwaysMatcher is a matcher that will always match. This logically
  228. // represents an any rule for a permission or a principal. alwaysMatcher
  229. // implements the matcher interface.
  230. type alwaysMatcher struct {
  231. }
  232. func (am *alwaysMatcher) match(data *rpcData) bool {
  233. return true
  234. }
  235. // notMatcher is a matcher that nots an underlying matcher. notMatcher
  236. // implements the matcher interface.
  237. type notMatcher struct {
  238. matcherToNot matcher
  239. }
  240. func (nm *notMatcher) match(data *rpcData) bool {
  241. return !nm.matcherToNot.match(data)
  242. }
  243. // headerMatcher is a matcher that matches on incoming HTTP Headers present
  244. // in the incoming RPC. headerMatcher implements the matcher interface.
  245. type headerMatcher struct {
  246. matcher internalmatcher.HeaderMatcher
  247. }
  248. func newHeaderMatcher(headerMatcherConfig *v3route_componentspb.HeaderMatcher) (*headerMatcher, error) {
  249. var m internalmatcher.HeaderMatcher
  250. switch headerMatcherConfig.HeaderMatchSpecifier.(type) {
  251. case *v3route_componentspb.HeaderMatcher_ExactMatch:
  252. m = internalmatcher.NewHeaderExactMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetExactMatch(), headerMatcherConfig.InvertMatch)
  253. case *v3route_componentspb.HeaderMatcher_SafeRegexMatch:
  254. regex, err := regexp.Compile(headerMatcherConfig.GetSafeRegexMatch().Regex)
  255. if err != nil {
  256. return nil, err
  257. }
  258. m = internalmatcher.NewHeaderRegexMatcher(headerMatcherConfig.Name, regex, headerMatcherConfig.InvertMatch)
  259. case *v3route_componentspb.HeaderMatcher_RangeMatch:
  260. m = internalmatcher.NewHeaderRangeMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetRangeMatch().Start, headerMatcherConfig.GetRangeMatch().End, headerMatcherConfig.InvertMatch)
  261. case *v3route_componentspb.HeaderMatcher_PresentMatch:
  262. m = internalmatcher.NewHeaderPresentMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetPresentMatch(), headerMatcherConfig.InvertMatch)
  263. case *v3route_componentspb.HeaderMatcher_PrefixMatch:
  264. m = internalmatcher.NewHeaderPrefixMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetPrefixMatch(), headerMatcherConfig.InvertMatch)
  265. case *v3route_componentspb.HeaderMatcher_SuffixMatch:
  266. m = internalmatcher.NewHeaderSuffixMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetSuffixMatch(), headerMatcherConfig.InvertMatch)
  267. case *v3route_componentspb.HeaderMatcher_ContainsMatch:
  268. m = internalmatcher.NewHeaderContainsMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetContainsMatch(), headerMatcherConfig.InvertMatch)
  269. default:
  270. return nil, errors.New("unknown header matcher type")
  271. }
  272. return &headerMatcher{matcher: m}, nil
  273. }
  274. func (hm *headerMatcher) match(data *rpcData) bool {
  275. return hm.matcher.Match(data.md)
  276. }
  277. // urlPathMatcher matches on the URL Path of the incoming RPC. In gRPC, this
  278. // logically maps to the full method name the RPC is calling on the server side.
  279. // urlPathMatcher implements the matcher interface.
  280. type urlPathMatcher struct {
  281. stringMatcher internalmatcher.StringMatcher
  282. }
  283. func newURLPathMatcher(pathMatcher *v3matcherpb.PathMatcher) (*urlPathMatcher, error) {
  284. stringMatcher, err := internalmatcher.StringMatcherFromProto(pathMatcher.GetPath())
  285. if err != nil {
  286. return nil, err
  287. }
  288. return &urlPathMatcher{stringMatcher: stringMatcher}, nil
  289. }
  290. func (upm *urlPathMatcher) match(data *rpcData) bool {
  291. return upm.stringMatcher.Match(data.fullMethod)
  292. }
  293. // remoteIPMatcher and localIPMatcher both are matchers that match against
  294. // a CIDR Range. Two different matchers are needed as the remote and destination
  295. // ip addresses come from different parts of the data about incoming RPC's
  296. // passed in. Matching a CIDR Range means to determine whether the IP Address
  297. // falls within the CIDR Range or not. They both implement the matcher
  298. // interface.
  299. type remoteIPMatcher struct {
  300. // ipNet represents the CidrRange that this matcher was configured with.
  301. // This is what will remote and destination IP's will be matched against.
  302. ipNet *net.IPNet
  303. }
  304. func newRemoteIPMatcher(cidrRange *v3corepb.CidrRange) (*remoteIPMatcher, error) {
  305. // Convert configuration to a cidrRangeString, as Go standard library has
  306. // methods that parse cidr string.
  307. cidrRangeString := fmt.Sprintf("%s/%d", cidrRange.AddressPrefix, cidrRange.PrefixLen.Value)
  308. _, ipNet, err := net.ParseCIDR(cidrRangeString)
  309. if err != nil {
  310. return nil, err
  311. }
  312. return &remoteIPMatcher{ipNet: ipNet}, nil
  313. }
  314. func (sim *remoteIPMatcher) match(data *rpcData) bool {
  315. return sim.ipNet.Contains(net.IP(net.ParseIP(data.peerInfo.Addr.String())))
  316. }
  317. type localIPMatcher struct {
  318. ipNet *net.IPNet
  319. }
  320. func newLocalIPMatcher(cidrRange *v3corepb.CidrRange) (*localIPMatcher, error) {
  321. cidrRangeString := fmt.Sprintf("%s/%d", cidrRange.AddressPrefix, cidrRange.PrefixLen.Value)
  322. _, ipNet, err := net.ParseCIDR(cidrRangeString)
  323. if err != nil {
  324. return nil, err
  325. }
  326. return &localIPMatcher{ipNet: ipNet}, nil
  327. }
  328. func (dim *localIPMatcher) match(data *rpcData) bool {
  329. return dim.ipNet.Contains(net.IP(net.ParseIP(data.localAddr.String())))
  330. }
  331. // portMatcher matches on whether the destination port of the RPC matches the
  332. // destination port this matcher was instantiated with. portMatcher
  333. // implements the matcher interface.
  334. type portMatcher struct {
  335. destinationPort uint32
  336. }
  337. func newPortMatcher(destinationPort uint32) *portMatcher {
  338. return &portMatcher{destinationPort: destinationPort}
  339. }
  340. func (pm *portMatcher) match(data *rpcData) bool {
  341. return data.destinationPort == pm.destinationPort
  342. }
  343. // authenticatedMatcher matches on the name of the Principal. If set, the URI
  344. // SAN or DNS SAN in that order is used from the certificate, otherwise the
  345. // subject field is used. If unset, it applies to any user that is
  346. // authenticated. authenticatedMatcher implements the matcher interface.
  347. type authenticatedMatcher struct {
  348. stringMatcher *internalmatcher.StringMatcher
  349. }
  350. func newAuthenticatedMatcher(authenticatedMatcherConfig *v3rbacpb.Principal_Authenticated) (*authenticatedMatcher, error) {
  351. // Represents this line in the RBAC documentation = "If unset, it applies to
  352. // any user that is authenticated" (see package-level comments).
  353. if authenticatedMatcherConfig.PrincipalName == nil {
  354. return &authenticatedMatcher{}, nil
  355. }
  356. stringMatcher, err := internalmatcher.StringMatcherFromProto(authenticatedMatcherConfig.PrincipalName)
  357. if err != nil {
  358. return nil, err
  359. }
  360. return &authenticatedMatcher{stringMatcher: &stringMatcher}, nil
  361. }
  362. func (am *authenticatedMatcher) match(data *rpcData) bool {
  363. if data.authType != "tls" {
  364. // Connection is not authenticated.
  365. return false
  366. }
  367. if am.stringMatcher == nil {
  368. // Allows any authenticated user.
  369. return true
  370. }
  371. // "If there is no client certificate (thus no SAN nor Subject), check if ""
  372. // (empty string) matches. If it matches, the principal_name is said to
  373. // match" - A41
  374. if len(data.certs) == 0 {
  375. return am.stringMatcher.Match("")
  376. }
  377. cert := data.certs[0]
  378. // The order of matching as per the RBAC documentation (see package-level comments)
  379. // is as follows: URI SANs, DNS SANs, and then subject name.
  380. for _, uriSAN := range cert.URIs {
  381. if am.stringMatcher.Match(uriSAN.String()) {
  382. return true
  383. }
  384. }
  385. for _, dnsSAN := range cert.DNSNames {
  386. if am.stringMatcher.Match(dnsSAN) {
  387. return true
  388. }
  389. }
  390. return am.stringMatcher.Match(cert.Subject.String())
  391. }