istio

Форк
0
162 строки · 7.5 Кб
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 trustdomain
16

17
import (
18
	"fmt"
19
	"strings"
20

21
	"istio.io/istio/pilot/pkg/features"
22
	"istio.io/istio/pkg/config/constants"
23
	istiolog "istio.io/istio/pkg/log"
24
)
25

26
var authzLog = istiolog.RegisterScope("authorization", "Istio Authorization Policy")
27

28
type Bundle struct {
29
	// Contain the local trust domain and its aliases.
30
	// The trust domain corresponds to the trust root of a system.
31
	// Refer to [SPIFFE-ID](https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain)
32
	// The trust domain aliases represent the aliases of `trust_domain`.
33
	// For example, if we have
34
	// trustDomain: td1, trustDomainAliases: ["td2", "td3"]
35
	// Any service with the identity `td1/ns/foo/sa/a-service-account`, `td2/ns/foo/sa/a-service-account`,
36
	// or `td3/ns/foo/sa/a-service-account` will be treated the same in the Istio mesh.
37
	TrustDomains []string
38
}
39

40
// NewBundle returns a new trust domain bundle.
41
func NewBundle(trustDomain string, trustDomainAliases []string) Bundle {
42
	return Bundle{
43
		// Put the new trust domain to the beginning of the list to avoid changing existing tests.
44
		TrustDomains: append([]string{trustDomain}, trustDomainAliases...),
45
	}
46
}
47

48
// ReplaceTrustDomainAliases checks the existing principals and returns a list of new principals
49
// with the current trust domain and its aliases.
50
// For example, for a user "bar" in namespace "foo".
51
// If the local trust domain is "td2" and its alias is "td1" (migrating from td1 to td2),
52
// replaceTrustDomainAliases returns ["td2/ns/foo/sa/bar", "td1/ns/foo/sa/bar]].
53
func (t Bundle) ReplaceTrustDomainAliases(principals []string) []string {
54
	principalsIncludingAliases := []string{}
55
	for _, principal := range principals {
56
		isTrustDomainBeingEnforced := isTrustDomainBeingEnforced(principal)
57
		// Return the existing principals if the policy doesn't care about the trust domain.
58
		if !isTrustDomainBeingEnforced {
59
			principalsIncludingAliases = append(principalsIncludingAliases, principal)
60
			continue
61
		}
62
		trustDomainFromPrincipal, err := getTrustDomainFromSpiffeIdentity(principal)
63
		if err != nil {
64
			authzLog.Errorf("unexpected incorrect Spiffe format: %s", principal)
65
			principalsIncludingAliases = append(principalsIncludingAliases, principal)
66
			continue
67
		}
68
		// Only generate configuration if the extracted trust domain from the policy is part of the trust domain list,
69
		// or if the extracted/existing trust domain is "cluster.local", which is a pointer to the local trust domain
70
		// and its aliases.
71
		if stringMatch(trustDomainFromPrincipal, t.TrustDomains) || trustDomainFromPrincipal == constants.DefaultClusterLocalDomain {
72
			// Generate configuration for trust domain and trust domain aliases.
73
			principalsIncludingAliases = append(principalsIncludingAliases, t.replaceTrustDomains(principal, trustDomainFromPrincipal)...)
74
		} else {
75
			msg := fmt.Sprintf("Trust domain %s from principal %s does not match the current trust "+
76
				"domain or its aliases", trustDomainFromPrincipal, principal)
77
			// when SkipValidateTrustDomain is being used the message isn't very meaningful so we'll log it at a lower level
78
			// logging it at this level may help users who are looking to disable skipping validation understand if it's safe
79
			if !features.SkipValidateTrustDomain {
80
				authzLog.Warn(msg)
81
			} else {
82
				authzLog.Debug(msg)
83
			}
84
			// If the trust domain from the existing doesn't match with the new trust domain aliases or "cluster.local",
85
			// keep the policy as it is.
86
			principalsIncludingAliases = append(principalsIncludingAliases, principal)
87
		}
88
	}
89
	return principalsIncludingAliases
90
}
91

92
// replaceTrustDomains replace the given principal's trust domain with the trust domains from the
93
// trustDomains list and return the new principals.
94
func (t Bundle) replaceTrustDomains(principal, trustDomainFromPrincipal string) []string {
95
	principalsForAliases := []string{}
96
	for _, td := range t.TrustDomains {
97
		// If the trust domain has a prefix * (e.g. *local from *local/ns/foo/sa/bar), keep the principal
98
		// as-is for the matched trust domain. For others, replace the trust domain with the new trust domain
99
		// or alias.
100
		var newPrincipal string
101
		var err error
102
		if suffixMatch(td, trustDomainFromPrincipal) {
103
			newPrincipal = principal
104
		} else {
105
			newPrincipal, err = replaceTrustDomainInPrincipal(td, principal)
106
			if err != nil {
107
				authzLog.Errorf("Failed to replace trust domain with %s from principal %s: %v", td, principal, err)
108
				continue
109
			}
110
		}
111
		// Check to make sure we don't generate duplicated principals. This happens when trust domain
112
		// has a * prefix. For example, "*-td" can match with "old-td" and "new-td", but we only want
113
		// to keep the principal as-is in the generated config, .i.e. *-td.
114
		if !isKeyInList(newPrincipal, principalsForAliases) {
115
			principalsForAliases = append(principalsForAliases, newPrincipal)
116
		}
117
	}
118
	return principalsForAliases
119
}
120

121
// replaceTrustDomainInPrincipal returns a new SPIFFE identity with the new trust domain.
122
// The trust domain corresponds to the trust root of a system.
123
// Refer to
124
// [SPIFFE-ID](https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain)
125
// In Istio authorization, an identity is presented in the format:
126
// <trust-domain>/ns/<some-namespace>/sa/<some-service-account>
127
func replaceTrustDomainInPrincipal(trustDomain string, principal string) (string, error) {
128
	identityParts := strings.Split(principal, "/")
129
	// A valid SPIFFE identity in authorization has no SPIFFE:// prefix.
130
	// It is presented as <trust-domain>/ns/<some-namespace>/sa/<some-service-account>
131
	if len(identityParts) != 5 {
132
		return "", fmt.Errorf("wrong SPIFFE format: %s", principal)
133
	}
134
	return fmt.Sprintf("%s/%s", trustDomain, strings.Join(identityParts[1:], "/")), nil
135
}
136

137
// isTrustDomainBeingEnforced checks whether the trust domain is being checked in the filter or not.
138
// For example, in the principal "*/ns/foo/sa/bar", the trust domain is * and it matches to any trust domain,
139
// so it won't be checked in the filter.
140
func isTrustDomainBeingEnforced(principal string) bool {
141
	identityParts := strings.Split(principal, "/")
142
	if len(identityParts) != 5 {
143
		// If a principal is mis-configured and doesn't follow Spiffe format, e.g. "sa/bar",
144
		// there is really no trust domain from the principal, so the trust domain is also considered not being enforced.
145
		return false
146
	}
147
	// Check if the first part of the spiffe string is "*" (as opposed to *-something or "").
148
	return identityParts[0] != "*"
149
}
150

151
// getTrustDomainFromSpiffeIdentity gets the trust domain from the given principal and expects
152
// principal to have the right SPIFFE format.
153
func getTrustDomainFromSpiffeIdentity(principal string) (string, error) {
154
	identityParts := strings.Split(principal, "/")
155
	// A valid SPIFFE identity in authorization has no SPIFFE:// prefix.
156
	// It is presented as <trust-domain>/ns/<some-namespace>/sa/<some-service-account>
157
	if len(identityParts) != 5 {
158
		return "", fmt.Errorf("wrong SPIFFE format: %s", principal)
159
	}
160
	trustDomain := identityParts[0]
161
	return trustDomain, nil
162
}
163

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

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

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

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