1
// Copyright Istio Authors
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
7
// http://www.apache.org/licenses/LICENSE-2.0
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.
21
rbacpb "github.com/envoyproxy/go-control-plane/envoy/config/rbac/v3"
23
authzpb "istio.io/api/security/v1beta1"
24
"istio.io/istio/pilot/pkg/security/trustdomain"
28
RBACTCPFilterStatPrefix = "tcp."
29
RBACShadowEngineResult = "shadow_engine_result"
30
RBACShadowEffectivePolicyID = "shadow_effective_policy_id"
31
RBACShadowRulesAllowStatPrefix = "istio_dry_run_allow_"
32
RBACShadowRulesDenyStatPrefix = "istio_dry_run_deny_"
33
RBACExtAuthzShadowRulesStatPrefix = "istio_ext_authz_"
35
attrRequestHeader = "request.headers" // header name is surrounded by brackets, e.g. "request.headers[User-Agent]".
36
attrSrcIP = "source.ip" // supports both single ip and cidr, e.g. "10.1.2.3" or "10.1.0.0/16".
37
attrRemoteIP = "remote.ip" // original client ip determined from x-forwarded-for or proxy protocol.
38
attrSrcNamespace = "source.namespace" // e.g. "default".
39
attrSrcPrincipal = "source.principal" // source identity, e,g, "cluster.local/ns/default/sa/productpage".
40
attrRequestPrincipal = "request.auth.principal" // authenticated principal of the request.
41
attrRequestAudiences = "request.auth.audiences" // intended audience(s) for this authentication information.
42
attrRequestPresenter = "request.auth.presenter" // authorized presenter of the credential.
43
attrRequestClaims = "request.auth.claims" // claim name is surrounded by brackets, e.g. "request.auth.claims[iss]".
44
attrDestIP = "destination.ip" // supports both single ip and cidr, e.g. "10.1.2.3" or "10.1.0.0/16".
45
attrDestPort = "destination.port" // must be in the range [0, 65535].
46
attrConnSNI = "connection.sni" // server name indication, e.g. "www.example.com".
47
attrEnvoyFilter = "experimental.envoy.filters." // an experimental attribute for checking Envoy Metadata directly.
49
// Internal names used to generate corresponding Envoy matcher.
50
methodHeader = ":method"
51
pathMatcher = "path-matcher"
52
hostHeader = ":authority"
60
// This generator aggregates value predicates
61
extended extendedGenerator
68
// Model represents a single rule from an authorization policy. The conditions of the rule are consolidated into
69
// permission or principal to align with the Envoy RBAC filter API.
71
permissions []ruleList
75
// New returns a model representing a single authorization policy.
76
func New(r *authzpb.Rule, useExtendedJwt bool) (*Model, error) {
79
basePermission := ruleList{}
80
basePrincipal := ruleList{}
82
// Each condition in the when needs to be consolidated into either permission or principal.
83
for _, when := range r.When {
87
basePermission.appendLast(destIPGenerator{}, k, when.Values, when.NotValues)
88
case k == attrDestPort:
89
basePermission.appendLast(destPortGenerator{}, k, when.Values, when.NotValues)
90
case k == attrConnSNI:
91
basePermission.appendLast(connSNIGenerator{}, k, when.Values, when.NotValues)
92
case strings.HasPrefix(k, attrEnvoyFilter):
94
basePermission.appendLastExtended(envoyFilterGenerator{}, k, when.Values, when.NotValues)
96
basePermission.appendLast(envoyFilterGenerator{}, k, when.Values, when.NotValues)
99
basePrincipal.appendLast(srcIPGenerator{}, k, when.Values, when.NotValues)
100
case k == attrRemoteIP:
101
basePrincipal.appendLast(remoteIPGenerator{}, k, when.Values, when.NotValues)
102
case k == attrSrcNamespace:
103
basePrincipal.appendLast(srcNamespaceGenerator{}, k, when.Values, when.NotValues)
104
case k == attrSrcPrincipal:
105
basePrincipal.appendLast(srcPrincipalGenerator{}, k, when.Values, when.NotValues)
106
case k == attrRequestPrincipal:
108
basePrincipal.appendLastExtended(requestPrincipalGenerator{}, k, when.Values, when.NotValues)
110
basePrincipal.appendLast(requestPrincipalGenerator{}, k, when.Values, when.NotValues)
112
case k == attrRequestAudiences:
114
basePrincipal.appendLastExtended(requestAudiencesGenerator{}, k, when.Values, when.NotValues)
116
basePrincipal.appendLast(requestAudiencesGenerator{}, k, when.Values, when.NotValues)
118
case k == attrRequestPresenter:
120
basePrincipal.appendLastExtended(requestPresenterGenerator{}, k, when.Values, when.NotValues)
122
basePrincipal.appendLast(requestPresenterGenerator{}, k, when.Values, when.NotValues)
124
case strings.HasPrefix(k, attrRequestHeader):
125
basePrincipal.appendLast(requestHeaderGenerator{}, k, when.Values, when.NotValues)
126
case strings.HasPrefix(k, attrRequestClaims):
128
basePrincipal.appendLastExtended(requestClaimGenerator{}, k, when.Values, when.NotValues)
130
basePrincipal.appendLast(requestClaimGenerator{}, k, when.Values, when.NotValues)
133
return nil, fmt.Errorf("unknown attribute %s", when.Key)
137
for _, from := range r.From {
138
merged := basePrincipal.copy()
139
if s := from.Source; s != nil {
140
merged.insertFront(srcIPGenerator{}, attrSrcIP, s.IpBlocks, s.NotIpBlocks)
141
merged.insertFront(remoteIPGenerator{}, attrRemoteIP, s.RemoteIpBlocks, s.NotRemoteIpBlocks)
142
merged.insertFront(srcNamespaceGenerator{}, attrSrcNamespace, s.Namespaces, s.NotNamespaces)
144
merged.insertFrontExtended(requestPrincipalGenerator{}, attrRequestPrincipal, s.RequestPrincipals, s.NotRequestPrincipals)
146
merged.insertFront(requestPrincipalGenerator{}, attrRequestPrincipal, s.RequestPrincipals, s.NotRequestPrincipals)
148
merged.insertFront(srcPrincipalGenerator{}, attrSrcPrincipal, s.Principals, s.NotPrincipals)
150
m.principals = append(m.principals, merged)
152
if len(r.From) == 0 {
153
m.principals = append(m.principals, basePrincipal)
156
for _, to := range r.To {
157
merged := basePermission.copy()
158
if o := to.Operation; o != nil {
159
merged.insertFront(destPortGenerator{}, attrDestPort, o.Ports, o.NotPorts)
160
merged.insertFront(pathGenerator{}, pathMatcher, o.Paths, o.NotPaths)
161
merged.insertFront(methodGenerator{}, methodHeader, o.Methods, o.NotMethods)
162
merged.insertFront(hostGenerator{}, hostHeader, o.Hosts, o.NotHosts)
164
m.permissions = append(m.permissions, merged)
167
m.permissions = append(m.permissions, basePermission)
173
// MigrateTrustDomain replaces the trust domain in source principal based on the trust domain aliases information.
174
func (m *Model) MigrateTrustDomain(tdBundle trustdomain.Bundle) {
175
for _, p := range m.principals {
176
for _, r := range p.rules {
177
if r.key == attrSrcPrincipal {
178
if len(r.values) != 0 {
179
r.values = tdBundle.ReplaceTrustDomainAliases(r.values)
181
if len(r.notValues) != 0 {
182
r.notValues = tdBundle.ReplaceTrustDomainAliases(r.notValues)
189
// Generate generates the Envoy RBAC config from the model.
190
func (m Model) Generate(forTCP bool, useAuthenticated bool, action rbacpb.RBAC_Action) (*rbacpb.Policy, error) {
191
var permissions []*rbacpb.Permission
192
for _, rl := range m.permissions {
193
permission, err := generatePermission(rl, forTCP, action)
197
permissions = append(permissions, permission)
199
if len(permissions) == 0 {
200
return nil, fmt.Errorf("must have at least 1 permission")
203
var principals []*rbacpb.Principal
204
for _, rl := range m.principals {
205
principal, err := generatePrincipal(rl, forTCP, useAuthenticated, action)
209
principals = append(principals, principal)
211
if len(principals) == 0 {
212
return nil, fmt.Errorf("must have at least 1 principal")
215
return &rbacpb.Policy{
216
Permissions: permissions,
217
Principals: principals,
221
func generatePermission(rl ruleList, forTCP bool, action rbacpb.RBAC_Action) (*rbacpb.Permission, error) {
222
var and []*rbacpb.Permission
223
for _, r := range rl.rules {
224
ret, err := r.permission(forTCP, action)
228
and = append(and, ret...)
231
and = append(and, permissionAny())
233
return permissionAnd(and), nil
236
func generatePrincipal(rl ruleList, forTCP bool, useAuthenticated bool, action rbacpb.RBAC_Action) (*rbacpb.Principal, error) {
237
var and []*rbacpb.Principal
238
for _, r := range rl.rules {
239
ret, err := r.principal(forTCP, useAuthenticated, action)
243
and = append(and, ret...)
246
and = append(and, principalAny())
248
return principalAnd(and), nil
251
func (r rule) permission(forTCP bool, action rbacpb.RBAC_Action) ([]*rbacpb.Permission, error) {
252
var permissions []*rbacpb.Permission
253
if r.extended != nil {
254
if len(r.values) > 0 {
255
p, err := r.extended.extendedPermission(r.key, r.values, forTCP)
256
if err := r.checkError(action, err); err != nil {
260
permissions = append(permissions, p)
264
var or []*rbacpb.Permission
265
for _, value := range r.values {
266
p, err := r.g.permission(r.key, value, forTCP)
267
if err := r.checkError(action, err); err != nil {
275
permissions = append(permissions, permissionOr(or))
279
if r.extended != nil {
280
if len(r.notValues) > 0 {
281
p, err := r.extended.extendedPermission(r.key, r.notValues, forTCP)
282
if err := r.checkError(action, err); err != nil {
286
permissions = append(permissions, permissionNot(p))
290
var or []*rbacpb.Permission
291
for _, notValue := range r.notValues {
292
p, err := r.g.permission(r.key, notValue, forTCP)
293
if err := r.checkError(action, err); err != nil {
301
permissions = append(permissions, permissionNot(permissionOr(or)))
304
return permissions, nil
307
func (r rule) principal(forTCP bool, useAuthenticated bool, action rbacpb.RBAC_Action) ([]*rbacpb.Principal, error) {
308
var principals []*rbacpb.Principal
309
if r.extended != nil {
310
if len(r.values) > 0 {
311
p, err := r.extended.extendedPrincipal(r.key, r.values, forTCP)
312
if err := r.checkError(action, err); err != nil {
316
principals = append(principals, p)
320
var or []*rbacpb.Principal
321
for _, value := range r.values {
322
p, err := r.g.principal(r.key, value, forTCP, useAuthenticated)
323
if err := r.checkError(action, err); err != nil {
331
principals = append(principals, principalOr(or))
335
if r.extended != nil {
336
if len(r.notValues) > 0 {
337
p, err := r.extended.extendedPrincipal(r.key, r.notValues, forTCP)
338
if err := r.checkError(action, err); err != nil {
342
principals = append(principals, principalNot(p))
346
var or []*rbacpb.Principal
347
for _, notValue := range r.notValues {
348
p, err := r.g.principal(r.key, notValue, forTCP, useAuthenticated)
349
if err := r.checkError(action, err); err != nil {
357
principals = append(principals, principalNot(principalOr(or)))
360
return principals, nil
363
func (r rule) checkError(action rbacpb.RBAC_Action, err error) error {
364
if action == rbacpb.RBAC_ALLOW {
365
// Return the error as-is for allow policy. This will make all rules in the current permission ignored, effectively
366
// result in a smaller allow policy (i.e. less likely to allow a request).
370
// Ignore the error for a deny or audit policy. This will make the current rule ignored and continue the generation of
371
// the next rule, effectively resulting in a wider deny or audit policy (i.e. more likely to deny or audit a request).
375
func (p *ruleList) copy() ruleList {
377
r.rules = append([]*rule{}, p.rules...)
381
func (p *ruleList) insertFront(g generator, key string, values, notValues []string) {
382
if len(values) == 0 && len(notValues) == 0 {
388
notValues: notValues,
392
p.rules = append([]*rule{r}, p.rules...)
395
func (p *ruleList) insertFrontExtended(g extendedGenerator, key string, values, notValues []string) {
396
if len(values) == 0 && len(notValues) == 0 {
402
notValues: notValues,
406
p.rules = append([]*rule{r}, p.rules...)
409
func (p *ruleList) appendLast(g generator, key string, values, notValues []string) {
410
if len(values) == 0 && len(notValues) == 0 {
416
notValues: notValues,
420
p.rules = append(p.rules, r)
423
func (p *ruleList) appendLastExtended(g extendedGenerator, key string, values, notValues []string) {
424
if len(values) == 0 && len(notValues) == 0 {
430
notValues: notValues,
433
p.rules = append(p.rules, r)