istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/security/authz/model/generator.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package model
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	rbacpb "github.com/envoyproxy/go-control-plane/envoy/config/rbac/v3"
    22  	matcherpb "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
    23  
    24  	"istio.io/istio/pilot/pkg/networking/util"
    25  	"istio.io/istio/pilot/pkg/security/authz/matcher"
    26  	"istio.io/istio/pilot/pkg/xds/filters"
    27  	"istio.io/istio/pkg/config/security"
    28  	"istio.io/istio/pkg/spiffe"
    29  )
    30  
    31  type generator interface {
    32  	permission(key, value string, forTCP bool) (*rbacpb.Permission, error)
    33  	principal(key, value string, forTCP bool, useAuthenticated bool) (*rbacpb.Principal, error)
    34  }
    35  
    36  type extendedGenerator interface {
    37  	extendedPermission(key string, value []string, forTCP bool) (*rbacpb.Permission, error)
    38  	extendedPrincipal(key string, value []string, forTCP bool) (*rbacpb.Principal, error)
    39  }
    40  
    41  type destIPGenerator struct{}
    42  
    43  func (destIPGenerator) permission(_, value string, _ bool) (*rbacpb.Permission, error) {
    44  	cidrRange, err := util.AddrStrToCidrRange(value)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	return permissionDestinationIP(cidrRange), nil
    49  }
    50  
    51  func (destIPGenerator) principal(_, _ string, _ bool, _ bool) (*rbacpb.Principal, error) {
    52  	return nil, fmt.Errorf("unimplemented")
    53  }
    54  
    55  type destPortGenerator struct{}
    56  
    57  func (destPortGenerator) permission(_, value string, _ bool) (*rbacpb.Permission, error) {
    58  	portValue, err := convertToPort(value)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	return permissionDestinationPort(portValue), nil
    63  }
    64  
    65  func (destPortGenerator) principal(_, _ string, _ bool, _ bool) (*rbacpb.Principal, error) {
    66  	return nil, fmt.Errorf("unimplemented")
    67  }
    68  
    69  type connSNIGenerator struct{}
    70  
    71  func (connSNIGenerator) permission(_, value string, _ bool) (*rbacpb.Permission, error) {
    72  	m := matcher.StringMatcher(value)
    73  	return permissionRequestedServerName(m), nil
    74  }
    75  
    76  func (connSNIGenerator) principal(_, _ string, _ bool, _ bool) (*rbacpb.Principal, error) {
    77  	return nil, fmt.Errorf("unimplemented")
    78  }
    79  
    80  type envoyFilterGenerator struct{}
    81  
    82  func (efg envoyFilterGenerator) permission(key, value string, _ bool) (*rbacpb.Permission, error) {
    83  	// Split key of format "experimental.envoy.filters.a.b[c]" to "envoy.filters.a.b" and "c".
    84  	parts := strings.SplitN(strings.TrimSuffix(strings.TrimPrefix(key, "experimental."), "]"), "[", 2)
    85  
    86  	if len(parts) != 2 {
    87  		return nil, fmt.Errorf("invalid key: %v", key)
    88  	}
    89  
    90  	// If value is of format [v], create a list matcher.
    91  	// Else, if value is of format v, create a string matcher.
    92  	if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") {
    93  		m := matcher.MetadataListMatcher(parts[0], parts[1:], matcher.StringMatcher(strings.Trim(value, "[]")), false)
    94  		return permissionMetadata(m), nil
    95  	}
    96  	m := matcher.MetadataStringMatcher(parts[0], parts[1], matcher.StringMatcher(value))
    97  	return permissionMetadata(m), nil
    98  }
    99  
   100  func (efg envoyFilterGenerator) extendedPermission(key string, values []string, _ bool) (*rbacpb.Permission, error) {
   101  	// Split key of format "experimental.envoy.filters.a.b[c]" to "envoy.filters.a.b" and "c".
   102  	parts := strings.SplitN(strings.TrimSuffix(strings.TrimPrefix(key, "experimental."), "]"), "[", 2)
   103  
   104  	if len(parts) != 2 {
   105  		return nil, fmt.Errorf("invalid key: %v", key)
   106  	}
   107  
   108  	matchers := []*matcherpb.ValueMatcher{}
   109  	for _, value := range values {
   110  		if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") {
   111  			matchers = append(matchers, &matcherpb.ValueMatcher{
   112  				MatchPattern: &matcherpb.ValueMatcher_ListMatch{
   113  					ListMatch: &matcherpb.ListMatcher{
   114  						MatchPattern: &matcherpb.ListMatcher_OneOf{
   115  							OneOf: &matcherpb.ValueMatcher{
   116  								MatchPattern: &matcherpb.ValueMatcher_StringMatch{
   117  									StringMatch: matcher.StringMatcher(strings.Trim(value, "[]")),
   118  								},
   119  							},
   120  						},
   121  					},
   122  				},
   123  			})
   124  		} else {
   125  			matchers = append(matchers, &matcherpb.ValueMatcher{
   126  				MatchPattern: &matcherpb.ValueMatcher_StringMatch{
   127  					StringMatch: matcher.StringMatcher(value),
   128  				},
   129  			})
   130  		}
   131  	}
   132  	m := matcher.MetadataValueMatcher(parts[0], parts[1], matcher.OrMatcher(matchers))
   133  	return permissionMetadata(m), nil
   134  }
   135  
   136  func (envoyFilterGenerator) principal(_, _ string, _ bool, _ bool) (*rbacpb.Principal, error) {
   137  	return nil, fmt.Errorf("unimplemented")
   138  }
   139  
   140  func (envoyFilterGenerator) extendedPrincipal(_ string, _ []string, _ bool) (*rbacpb.Principal, error) {
   141  	return nil, fmt.Errorf("unimplemented")
   142  }
   143  
   144  type srcIPGenerator struct{}
   145  
   146  func (srcIPGenerator) permission(_, _ string, _ bool) (*rbacpb.Permission, error) {
   147  	return nil, fmt.Errorf("unimplemented")
   148  }
   149  
   150  func (srcIPGenerator) principal(_, value string, _ bool, _ bool) (*rbacpb.Principal, error) {
   151  	cidr, err := util.AddrStrToCidrRange(value)
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	return principalDirectRemoteIP(cidr), nil
   156  }
   157  
   158  type remoteIPGenerator struct{}
   159  
   160  func (remoteIPGenerator) permission(_, _ string, _ bool) (*rbacpb.Permission, error) {
   161  	return nil, fmt.Errorf("unimplemented")
   162  }
   163  
   164  func (remoteIPGenerator) principal(_, value string, _ bool, _ bool) (*rbacpb.Principal, error) {
   165  	cidr, err := util.AddrStrToCidrRange(value)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  	return principalRemoteIP(cidr), nil
   170  }
   171  
   172  type srcNamespaceGenerator struct{}
   173  
   174  func (srcNamespaceGenerator) permission(_, _ string, _ bool) (*rbacpb.Permission, error) {
   175  	return nil, fmt.Errorf("unimplemented")
   176  }
   177  
   178  func (srcNamespaceGenerator) principal(_, value string, _ bool, useAuthenticated bool) (*rbacpb.Principal, error) {
   179  	v := strings.Replace(value, "*", ".*", -1)
   180  	m := matcher.StringMatcherRegex(fmt.Sprintf(".*/ns/%s/.*", v))
   181  	return principalAuthenticated(m, useAuthenticated), nil
   182  }
   183  
   184  type srcPrincipalGenerator struct{}
   185  
   186  func (srcPrincipalGenerator) permission(_, _ string, _ bool) (*rbacpb.Permission, error) {
   187  	return nil, fmt.Errorf("unimplemented")
   188  }
   189  
   190  func (srcPrincipalGenerator) principal(key, value string, _ bool, useAuthenticated bool) (*rbacpb.Principal, error) {
   191  	m := matcher.StringMatcherWithPrefix(value, spiffe.URIPrefix)
   192  	return principalAuthenticated(m, useAuthenticated), nil
   193  }
   194  
   195  type requestPrincipalGenerator struct{}
   196  
   197  func (requestPrincipalGenerator) permission(_, _ string, _ bool) (*rbacpb.Permission, error) {
   198  	return nil, fmt.Errorf("unimplemented")
   199  }
   200  
   201  func (requestPrincipalGenerator) extendedPermission(_ string, _ []string, _ bool) (*rbacpb.Permission, error) {
   202  	return nil, fmt.Errorf("unimplemented")
   203  }
   204  
   205  func (rpg requestPrincipalGenerator) principal(key, value string, forTCP bool, _ bool) (*rbacpb.Principal, error) {
   206  	if forTCP {
   207  		return nil, fmt.Errorf("%q is HTTP only", key)
   208  	}
   209  	m := matcher.MetadataStringMatcher(filters.AuthnFilterName, key, matcher.StringMatcher(value))
   210  	return principalMetadata(m), nil
   211  }
   212  
   213  var matchAny = matcher.StringMatcherRegex(".+")
   214  
   215  func (rpg requestPrincipalGenerator) extendedPrincipal(key string, values []string, forTCP bool) (*rbacpb.Principal, error) {
   216  	if forTCP {
   217  		return nil, fmt.Errorf("%q is HTTP only", key)
   218  	}
   219  	var or []*rbacpb.Principal
   220  	for _, value := range values {
   221  		// Use the last index of "/" since issuer may be an URL
   222  		idx := strings.LastIndex(value, "/")
   223  		found := idx >= 0
   224  		iss, sub := "", ""
   225  		if found {
   226  			iss, sub = value[:idx], value[idx+1:]
   227  		} else {
   228  			iss = value
   229  		}
   230  		var matchIss, matchSub *matcherpb.StringMatcher
   231  		switch {
   232  		case value == "*":
   233  			matchIss = matchAny
   234  			matchSub = matchAny
   235  		case strings.HasPrefix(value, "*"):
   236  			if found {
   237  				if iss == "*" {
   238  					matchIss = matchAny
   239  				} else {
   240  					matchIss = matcher.StringMatcherSuffix(strings.TrimPrefix(iss, "*"), false)
   241  				}
   242  				matchSub = matcher.StringMatcherExact(sub, false)
   243  			} else {
   244  				matchIss = matchAny
   245  				matchSub = matcher.StringMatcherSuffix(strings.TrimPrefix(value, "*"), false)
   246  			}
   247  		case strings.HasSuffix(value, "*"):
   248  			if found {
   249  				matchIss = matcher.StringMatcherExact(iss, false)
   250  				if sub == "*" {
   251  					matchSub = matchAny
   252  				} else {
   253  					matchSub = matcher.StringMatcherPrefix(strings.TrimSuffix(sub, "*"), false)
   254  				}
   255  			} else {
   256  				matchIss = matcher.StringMatcherPrefix(strings.TrimSuffix(value, "*"), false)
   257  				matchSub = matchAny
   258  			}
   259  		default:
   260  			matchSub = matcher.StringMatcherExact(sub, false)
   261  			matchIss = matcher.StringMatcherExact(iss, false)
   262  		}
   263  		im := MetadataStringMatcherForJWTClaim("iss", matchIss)
   264  		sm := MetadataStringMatcherForJWTClaim("sub", matchSub)
   265  		or = append(or, principalAnd([]*rbacpb.Principal{principalMetadata(im), principalMetadata(sm)}))
   266  	}
   267  	if len(or) == 1 {
   268  		return or[0], nil
   269  	} else if len(or) > 0 {
   270  		return principalOr(or), nil
   271  	}
   272  	return nil, nil
   273  }
   274  
   275  type requestAudiencesGenerator struct{}
   276  
   277  func (requestAudiencesGenerator) permission(key, value string, forTCP bool) (*rbacpb.Permission, error) {
   278  	return requestPrincipalGenerator{}.permission(key, value, forTCP)
   279  }
   280  
   281  func (requestAudiencesGenerator) extendedPermission(key string, values []string, forTCP bool) (*rbacpb.Permission, error) {
   282  	return requestPrincipalGenerator{}.extendedPermission(key, values, forTCP)
   283  }
   284  
   285  func (rag requestAudiencesGenerator) principal(key, value string, forTCP bool, useAuthenticated bool) (*rbacpb.Principal, error) {
   286  	if forTCP {
   287  		return nil, fmt.Errorf("%q is HTTP only", key)
   288  	}
   289  	m := matcher.MetadataStringMatcher(filters.AuthnFilterName, key, matcher.StringMatcher(value))
   290  	return principalMetadata(m), nil
   291  }
   292  
   293  func (rag requestAudiencesGenerator) extendedPrincipal(key string, values []string, forTCP bool) (*rbacpb.Principal, error) {
   294  	if forTCP {
   295  		return nil, fmt.Errorf("%q is HTTP only", key)
   296  	}
   297  	return principalMetadata(MetadataListValueMatcherForJWTClaims([]string{"aud"}, matcher.StringOrMatcher(values))), nil
   298  }
   299  
   300  type requestPresenterGenerator struct{}
   301  
   302  func (requestPresenterGenerator) permission(key, value string, forTCP bool) (*rbacpb.Permission, error) {
   303  	return requestPrincipalGenerator{}.permission(key, value, forTCP)
   304  }
   305  
   306  func (requestPresenterGenerator) extendedPermission(key string, values []string, forTCP bool) (*rbacpb.Permission, error) {
   307  	return requestPrincipalGenerator{}.extendedPermission(key, values, forTCP)
   308  }
   309  
   310  func (rpg requestPresenterGenerator) principal(key, value string, forTCP bool, useAuthenticated bool) (*rbacpb.Principal, error) {
   311  	if forTCP {
   312  		return nil, fmt.Errorf("%q is HTTP only", key)
   313  	}
   314  	m := matcher.MetadataStringMatcher(filters.AuthnFilterName, key, matcher.StringMatcher(value))
   315  	return principalMetadata(m), nil
   316  }
   317  
   318  func (rpg requestPresenterGenerator) extendedPrincipal(key string, values []string, forTCP bool) (*rbacpb.Principal, error) {
   319  	if forTCP {
   320  		return nil, fmt.Errorf("%q is HTTP only", key)
   321  	}
   322  	return principalMetadata(MetadataListValueMatcherForJWTClaims([]string{"azp"}, matcher.StringOrMatcher(values))), nil
   323  }
   324  
   325  type requestHeaderGenerator struct{}
   326  
   327  func (requestHeaderGenerator) permission(_, _ string, _ bool) (*rbacpb.Permission, error) {
   328  	return nil, fmt.Errorf("unimplemented")
   329  }
   330  
   331  func (requestHeaderGenerator) principal(key, value string, forTCP bool, _ bool) (*rbacpb.Principal, error) {
   332  	if forTCP {
   333  		return nil, fmt.Errorf("%q is HTTP only", key)
   334  	}
   335  
   336  	header, err := extractNameInBrackets(strings.TrimPrefix(key, attrRequestHeader))
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  	m := matcher.HeaderMatcher(header, value)
   341  	return principalHeader(m), nil
   342  }
   343  
   344  type requestClaimGenerator struct{}
   345  
   346  func (requestClaimGenerator) permission(_, _ string, _ bool) (*rbacpb.Permission, error) {
   347  	return nil, fmt.Errorf("unimplemented")
   348  }
   349  
   350  func (requestClaimGenerator) extendedPermission(_ string, _ []string, _ bool) (*rbacpb.Permission, error) {
   351  	return nil, fmt.Errorf("unimplemented")
   352  }
   353  
   354  func (rcg requestClaimGenerator) principal(key, value string, forTCP bool, _ bool) (*rbacpb.Principal, error) {
   355  	if forTCP {
   356  		return nil, fmt.Errorf("%q is HTTP only", key)
   357  	}
   358  
   359  	claims, err := extractNameInNestedBrackets(strings.TrimPrefix(key, attrRequestClaims))
   360  	if err != nil {
   361  		return nil, err
   362  	}
   363  	// Generate a metadata list matcher for the given path keys and value.
   364  	// On proxy side, the value should be of list type.
   365  	m := MetadataMatcherForJWTClaims(claims, matcher.StringMatcher(value), false)
   366  	return principalMetadata(m), nil
   367  }
   368  
   369  func (rcg requestClaimGenerator) extendedPrincipal(key string, values []string, forTCP bool) (*rbacpb.Principal, error) {
   370  	if forTCP {
   371  		return nil, fmt.Errorf("%q is HTTP only", key)
   372  	}
   373  
   374  	claims, err := extractNameInNestedBrackets(strings.TrimPrefix(key, attrRequestClaims))
   375  	if err != nil {
   376  		return nil, err
   377  	}
   378  	m := MetadataListValueMatcherForJWTClaims(claims, matcher.StringOrMatcher(values))
   379  	return principalMetadata(m), nil
   380  }
   381  
   382  type hostGenerator struct{}
   383  
   384  func (hg hostGenerator) permission(key, value string, forTCP bool) (*rbacpb.Permission, error) {
   385  	if forTCP {
   386  		return nil, fmt.Errorf("%q is HTTP only", key)
   387  	}
   388  
   389  	return permissionHeader(matcher.HostMatcher(hostHeader, value)), nil
   390  }
   391  
   392  func (hostGenerator) principal(key, value string, forTCP bool, _ bool) (*rbacpb.Principal, error) {
   393  	return nil, fmt.Errorf("unimplemented")
   394  }
   395  
   396  type pathGenerator struct{}
   397  
   398  func (g pathGenerator) permission(key, value string, forTCP bool) (*rbacpb.Permission, error) {
   399  	if forTCP {
   400  		return nil, fmt.Errorf("%q is HTTP only", key)
   401  	}
   402  
   403  	if security.ContainsPathTemplate(value) {
   404  		m := matcher.PathTemplateMatcher(value)
   405  		return permissionPathTemplate(m), nil
   406  	}
   407  
   408  	m := matcher.PathMatcher(value)
   409  	return permissionPath(m), nil
   410  }
   411  
   412  func (pathGenerator) principal(key, value string, forTCP bool, _ bool) (*rbacpb.Principal, error) {
   413  	return nil, fmt.Errorf("unimplemented")
   414  }
   415  
   416  type methodGenerator struct{}
   417  
   418  func (methodGenerator) permission(key, value string, forTCP bool) (*rbacpb.Permission, error) {
   419  	if forTCP {
   420  		return nil, fmt.Errorf("%q is HTTP only", key)
   421  	}
   422  
   423  	m := matcher.HeaderMatcher(methodHeader, value)
   424  	return permissionHeader(m), nil
   425  }
   426  
   427  func (methodGenerator) principal(key, value string, forTCP bool, _ bool) (*rbacpb.Principal, error) {
   428  	return nil, fmt.Errorf("unimplemented")
   429  }