istio

Форк
0
434 строки · 13.8 Кб
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

23
	authzpb "istio.io/api/security/v1beta1"
24
	"istio.io/istio/pilot/pkg/security/trustdomain"
25
)
26

27
const (
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_"
34

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.
48

49
	// Internal names used to generate corresponding Envoy matcher.
50
	methodHeader = ":method"
51
	pathMatcher  = "path-matcher"
52
	hostHeader   = ":authority"
53
)
54

55
type rule struct {
56
	key       string
57
	values    []string
58
	notValues []string
59
	g         generator
60
	// This generator aggregates value predicates
61
	extended extendedGenerator
62
}
63

64
type ruleList struct {
65
	rules []*rule
66
}
67

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.
70
type Model struct {
71
	permissions []ruleList
72
	principals  []ruleList
73
}
74

75
// New returns a model representing a single authorization policy.
76
func New(r *authzpb.Rule, useExtendedJwt bool) (*Model, error) {
77
	m := Model{}
78

79
	basePermission := ruleList{}
80
	basePrincipal := ruleList{}
81

82
	// Each condition in the when needs to be consolidated into either permission or principal.
83
	for _, when := range r.When {
84
		k := when.Key
85
		switch {
86
		case k == attrDestIP:
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):
93
			if useExtendedJwt {
94
				basePermission.appendLastExtended(envoyFilterGenerator{}, k, when.Values, when.NotValues)
95
			} else {
96
				basePermission.appendLast(envoyFilterGenerator{}, k, when.Values, when.NotValues)
97
			}
98
		case k == attrSrcIP:
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:
107
			if useExtendedJwt {
108
				basePrincipal.appendLastExtended(requestPrincipalGenerator{}, k, when.Values, when.NotValues)
109
			} else {
110
				basePrincipal.appendLast(requestPrincipalGenerator{}, k, when.Values, when.NotValues)
111
			}
112
		case k == attrRequestAudiences:
113
			if useExtendedJwt {
114
				basePrincipal.appendLastExtended(requestAudiencesGenerator{}, k, when.Values, when.NotValues)
115
			} else {
116
				basePrincipal.appendLast(requestAudiencesGenerator{}, k, when.Values, when.NotValues)
117
			}
118
		case k == attrRequestPresenter:
119
			if useExtendedJwt {
120
				basePrincipal.appendLastExtended(requestPresenterGenerator{}, k, when.Values, when.NotValues)
121
			} else {
122
				basePrincipal.appendLast(requestPresenterGenerator{}, k, when.Values, when.NotValues)
123
			}
124
		case strings.HasPrefix(k, attrRequestHeader):
125
			basePrincipal.appendLast(requestHeaderGenerator{}, k, when.Values, when.NotValues)
126
		case strings.HasPrefix(k, attrRequestClaims):
127
			if useExtendedJwt {
128
				basePrincipal.appendLastExtended(requestClaimGenerator{}, k, when.Values, when.NotValues)
129
			} else {
130
				basePrincipal.appendLast(requestClaimGenerator{}, k, when.Values, when.NotValues)
131
			}
132
		default:
133
			return nil, fmt.Errorf("unknown attribute %s", when.Key)
134
		}
135
	}
136

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)
143
			if useExtendedJwt {
144
				merged.insertFrontExtended(requestPrincipalGenerator{}, attrRequestPrincipal, s.RequestPrincipals, s.NotRequestPrincipals)
145
			} else {
146
				merged.insertFront(requestPrincipalGenerator{}, attrRequestPrincipal, s.RequestPrincipals, s.NotRequestPrincipals)
147
			}
148
			merged.insertFront(srcPrincipalGenerator{}, attrSrcPrincipal, s.Principals, s.NotPrincipals)
149
		}
150
		m.principals = append(m.principals, merged)
151
	}
152
	if len(r.From) == 0 {
153
		m.principals = append(m.principals, basePrincipal)
154
	}
155

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)
163
		}
164
		m.permissions = append(m.permissions, merged)
165
	}
166
	if len(r.To) == 0 {
167
		m.permissions = append(m.permissions, basePermission)
168
	}
169

170
	return &m, nil
171
}
172

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)
180
				}
181
				if len(r.notValues) != 0 {
182
					r.notValues = tdBundle.ReplaceTrustDomainAliases(r.notValues)
183
				}
184
			}
185
		}
186
	}
187
}
188

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)
194
		if err != nil {
195
			return nil, err
196
		}
197
		permissions = append(permissions, permission)
198
	}
199
	if len(permissions) == 0 {
200
		return nil, fmt.Errorf("must have at least 1 permission")
201
	}
202

203
	var principals []*rbacpb.Principal
204
	for _, rl := range m.principals {
205
		principal, err := generatePrincipal(rl, forTCP, useAuthenticated, action)
206
		if err != nil {
207
			return nil, err
208
		}
209
		principals = append(principals, principal)
210
	}
211
	if len(principals) == 0 {
212
		return nil, fmt.Errorf("must have at least 1 principal")
213
	}
214

215
	return &rbacpb.Policy{
216
		Permissions: permissions,
217
		Principals:  principals,
218
	}, nil
219
}
220

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)
225
		if err != nil {
226
			return nil, err
227
		}
228
		and = append(and, ret...)
229
	}
230
	if len(and) == 0 {
231
		and = append(and, permissionAny())
232
	}
233
	return permissionAnd(and), nil
234
}
235

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)
240
		if err != nil {
241
			return nil, err
242
		}
243
		and = append(and, ret...)
244
	}
245
	if len(and) == 0 {
246
		and = append(and, principalAny())
247
	}
248
	return principalAnd(and), nil
249
}
250

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 {
257
				return nil, err
258
			}
259
			if p != nil {
260
				permissions = append(permissions, p)
261
			}
262
		}
263
	} else {
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 {
268
				return nil, err
269
			}
270
			if p != nil {
271
				or = append(or, p)
272
			}
273
		}
274
		if len(or) > 0 {
275
			permissions = append(permissions, permissionOr(or))
276
		}
277
	}
278

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 {
283
				return nil, err
284
			}
285
			if p != nil {
286
				permissions = append(permissions, permissionNot(p))
287
			}
288
		}
289
	} else {
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 {
294
				return nil, err
295
			}
296
			if p != nil {
297
				or = append(or, p)
298
			}
299
		}
300
		if len(or) > 0 {
301
			permissions = append(permissions, permissionNot(permissionOr(or)))
302
		}
303
	}
304
	return permissions, nil
305
}
306

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 {
313
				return nil, err
314
			}
315
			if p != nil {
316
				principals = append(principals, p)
317
			}
318
		}
319
	} else {
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 {
324
				return nil, err
325
			}
326
			if p != nil {
327
				or = append(or, p)
328
			}
329
		}
330
		if len(or) > 0 {
331
			principals = append(principals, principalOr(or))
332
		}
333
	}
334

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 {
339
				return nil, err
340
			}
341
			if p != nil {
342
				principals = append(principals, principalNot(p))
343
			}
344
		}
345
	} else {
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 {
350
				return nil, err
351
			}
352
			if p != nil {
353
				or = append(or, p)
354
			}
355
		}
356
		if len(or) > 0 {
357
			principals = append(principals, principalNot(principalOr(or)))
358
		}
359
	}
360
	return principals, nil
361
}
362

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).
367
		return err
368
	}
369

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).
372
	return nil
373
}
374

375
func (p *ruleList) copy() ruleList {
376
	r := ruleList{}
377
	r.rules = append([]*rule{}, p.rules...)
378
	return r
379
}
380

381
func (p *ruleList) insertFront(g generator, key string, values, notValues []string) {
382
	if len(values) == 0 && len(notValues) == 0 {
383
		return
384
	}
385
	r := &rule{
386
		key:       key,
387
		values:    values,
388
		notValues: notValues,
389
		g:         g,
390
	}
391

392
	p.rules = append([]*rule{r}, p.rules...)
393
}
394

395
func (p *ruleList) insertFrontExtended(g extendedGenerator, key string, values, notValues []string) {
396
	if len(values) == 0 && len(notValues) == 0 {
397
		return
398
	}
399
	r := &rule{
400
		key:       key,
401
		values:    values,
402
		notValues: notValues,
403
		extended:  g,
404
	}
405

406
	p.rules = append([]*rule{r}, p.rules...)
407
}
408

409
func (p *ruleList) appendLast(g generator, key string, values, notValues []string) {
410
	if len(values) == 0 && len(notValues) == 0 {
411
		return
412
	}
413
	r := &rule{
414
		key:       key,
415
		values:    values,
416
		notValues: notValues,
417
		g:         g,
418
	}
419

420
	p.rules = append(p.rules, r)
421
}
422

423
func (p *ruleList) appendLastExtended(g extendedGenerator, key string, values, notValues []string) {
424
	if len(values) == 0 && len(notValues) == 0 {
425
		return
426
	}
427
	r := &rule{
428
		key:       key,
429
		values:    values,
430
		notValues: notValues,
431
		extended:  g,
432
	}
433
	p.rules = append(p.rules, r)
434
}
435

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.