kubelatte-ce

Форк
2
Форк от sbertech/kubelatte-ce
/
permission_manager.go 
296 строк · 7.7 Кб
1
package permission
2

3
import (
4
	"fmt"
5
	"gitverse.ru/synapse/kubelatte/pkg/observability/logger"
6
	"gitverse.ru/synapse/kubelatte/pkg/util/env"
7
	"golang.org/x/net/context"
8
	v1 "k8s.io/api/authorization/v1"
9
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10
	kclientset "k8s.io/client-go/kubernetes"
11
	"sync"
12
	"time"
13
)
14

15
type PermissionerI interface {
16
	Init(client kclientset.Interface, operatorNamespace string, mutator, validator, creator, sideeffect bool) PermissionerI
17
	DeleteNamespaceTi(ns string)
18
	AddNamespaceTi(ns string)
19
	GetPermissions() []Permission
20
	StartCheck()
21
}
22

23
var PermissionsSet bool
24

25
var instance PermissionerI
26

27
type Manager struct {
28
	cancelCheck       bool
29
	startOnly         bool
30
	logOnly           bool
31
	checkPeriod       time.Duration
32
	ticker            *time.Ticker
33
	permissions       []Permission
34
	client            kclientset.Interface
35
	rwMutex           *sync.Mutex
36
	operatorNamespace string
37
	tiNamespaces      map[string][]Permission
38
	isCreator         bool
39
	isMutator         bool
40
	isSideEffect      bool
41
	isValidator       bool
42
}
43

44
type Permission struct {
45
	Resources []string
46
	Verbs     []string
47
	Group     string
48
	Version   string
49
	Namespace string
50
	Required  bool
51
}
52

53
func NewManager() PermissionerI {
54
	instance = &Manager{
55
		rwMutex:      &sync.Mutex{},
56
		tiNamespaces: make(map[string][]Permission),
57
	}
58
	return instance
59
}
60

61
func (m *Manager) Init(client kclientset.Interface, operatorNamespace string, mutator, validator, creator, sideeffect bool) PermissionerI {
62
	if !env.KbltPermissionsCheck {
63
		PermissionsSet = true
64
		m.cancelCheck = true
65
		return m
66
	}
67

68
	m.checkPeriod = env.KbltPermissionsCheckPeriod
69
	m.logOnly = env.KbltPermissionsLogOnly
70
	m.startOnly = env.KbltPermissionsStartOnly
71

72
	m.client = client
73
	m.isCreator = creator
74
	m.isMutator = mutator
75
	m.isValidator = validator
76
	m.isSideEffect = sideeffect
77
	m.operatorNamespace = operatorNamespace
78
	m.permissions = m.GetPermissions()
79
	return m
80
}
81

82
func (m *Manager) StartCheck() {
83
	if m == nil || m.cancelCheck {
84
		return
85
	}
86

87
	m.checkPermsForFirstTime(context.Background())
88
	if m.startOnly {
89
		return
90
	}
91

92
	go m.startPermissionWatcher(context.Background())
93
}
94

95
func (m *Manager) checkPermsForFirstTime(ctx context.Context) {
96
	for {
97
		err := m.checkPermissionsAndSetStatus(ctx)
98
		if err == nil {
99
			break
100
		}
101
		time.Sleep(m.checkPeriod)
102
	}
103
}
104

105
func (m *Manager) checkPermissionsAndSetStatus(ctx context.Context) error {
106
	err := m.checkPermissions(ctx)
107
	PermissionsSet = m.logOnly || err == nil
108
	if m.logOnly {
109
		return nil
110
	}
111
	return err
112
}
113

114
func (m *Manager) startPermissionWatcher(ctx context.Context) {
115
	m.ticker = time.NewTicker(m.checkPeriod)
116
	_ = m.checkPermissionsAndSetStatus(ctx)
117
	for {
118
		select {
119
		case <-m.ticker.C:
120
			_ = m.checkPermissionsAndSetStatus(ctx)
121
		case <-ctx.Done():
122
			m.stop(ctx)
123
			return
124
		}
125
	}
126
}
127

128
func (m *Manager) stop(ctx context.Context) {
129
	if m.ticker != nil {
130
		m.ticker.Stop()
131
	}
132
	ctx.Done()
133
}
134

135
func (m *Manager) checkPermissions(ctx context.Context) error {
136
	log := logger.FromContext(ctx)
137
	var cnt int
138
	for _, perm := range m.permissions {
139
		cnt += len(perm.Verbs) * len(perm.Resources)
140
	}
141
	errChan := make(chan error, cnt)
142
	wg := &sync.WaitGroup{}
143

144
	for _, permission := range m.permissions {
145
		for _, verb := range permission.Verbs {
146
			for _, resource := range permission.Resources {
147
				wg.Add(1)
148
				time.Sleep(time.Millisecond * 100) // do not dos kuber api
149
				go func(verb, resource, group, version, namespace string, required bool, waitGroup *sync.WaitGroup, errChan chan error) {
150
					defer waitGroup.Done()
151

152
					rv := &v1.SelfSubjectAccessReview{
153
						Spec: v1.SelfSubjectAccessReviewSpec{
154
							ResourceAttributes: &v1.ResourceAttributes{
155
								Namespace: namespace,
156
								Verb:      verb,
157
								Group:     group,
158
								Version:   version,
159
								Resource:  resource,
160
							},
161
						},
162
					}
163
					resp, err := m.client.AuthorizationV1().SelfSubjectAccessReviews().Create(ctx, rv, metav1.CreateOptions{})
164
					if err != nil {
165
						errChan <- err
166
						log.Errorf("cant check permissions: %s", err.Error())
167
						return
168
					}
169
					if !resp.Status.Allowed {
170
						if !required {
171
							log.Warnf("[Permission Manager] not allowed: %s %s %s", verb, resource, resp.Status.Reason)
172
							return
173
						}
174
						errChan <- fmt.Errorf("not allowed")
175
						log.Errorf("[Permission Manager] not allowed %s %s %s %s", verb, resource, resp.Status.Reason, resp.Status.EvaluationError)
176
						return
177
					}
178
				}(verb, resource, permission.Group, permission.Version, permission.Namespace, permission.Required, wg, errChan)
179
			}
180
		}
181
	}
182
	wg.Wait()
183
	close(errChan)
184
	if err := <-errChan; err != nil {
185
		return fmt.Errorf("[Init Manager] Permissions error")
186
	}
187

188
	return nil
189
}
190

191
func (m *Manager) GetPermissions() []Permission {
192
	var requestedPermissions []Permission
193

194
	var namespaces = Permission{
195
		Verbs:     []string{"get", "list", "watch"},
196
		Group:     "",
197
		Resources: []string{"namespaces"},
198
		Namespace: "",
199
		Required:  true,
200
	}
201
	var leases = Permission{
202
		Verbs:     []string{"get", "list", "watch", "create", "update", "watch", "delete", "patch"},
203
		Group:     "coordination.k8s.io",
204
		Resources: []string{"leases"},
205
		Namespace: m.operatorNamespace,
206
		Required:  true,
207
	}
208
	latteStatuses := make([]string, 0)
209
	latteRes := make([]string, 0)
210
	if m.isValidator || m.isMutator {
211
		latteStatuses = append(latteStatuses, "scopes/status", "templates/status")
212
		latteRes = append(latteRes, "scopes", "templates")
213
	}
214
	if m.isMutator {
215
		latteStatuses = append(latteStatuses, "triggers/status")
216
		latteRes = append(latteRes, "triggers")
217
	}
218

219
	var lateCrdPem = Permission{
220
		Verbs:     []string{"get", "list", "watch"},
221
		Group:     "kubelatte.synapse.sber",
222
		Resources: latteRes,
223
		Namespace: m.operatorNamespace,
224
		Required:  true,
225
	}
226
	var statuses = Permission{
227
		Verbs:     []string{"get", "list", "watch", "create", "update", "watch", "delete", "patch"},
228
		Group:     "kubelatte.synapse.sber",
229
		Resources: latteStatuses,
230
		Namespace: m.operatorNamespace,
231
		Required:  true,
232
	}
233

234
	requestedPermissions = append(requestedPermissions, statuses, leases, lateCrdPem, namespaces)
235
	return requestedPermissions
236
}
237

238
func (m *Manager) AddNamespaceTi(ns string) {
239
	if !m.isCreator {
240
		return
241
	}
242
	m.rwMutex.Lock()
243
	defer m.rwMutex.Unlock()
244
	log := logger.FromContext(context.Background())
245
	if _, ok := m.tiNamespaces[ns]; ok {
246
		return
247
	}
248
	log.Debugf("[Permission Manager] start check TI permissions in ns: %v", ns)
249
	perms := make([]Permission, 0, 3)
250
	perms = append(perms,
251
		Permission{
252
			Verbs:     []string{"get", "list", "watch"},
253
			Group:     "kubelatte.synapse.sber",
254
			Resources: []string{"triggerinstances"},
255
			Namespace: ns,
256
			Required:  false,
257
		},
258
		Permission{
259
			Verbs:     []string{"get", "list", "watch", "create", "update", "watch", "delete", "patch"},
260
			Group:     "kubelatte.synapse.sber",
261
			Resources: []string{"triggerinstances/status"},
262
			Namespace: ns,
263
			Required:  false,
264
		})
265
	if m.isSideEffect {
266
		perms = append(perms, Permission{
267
			Verbs:     []string{"create"},
268
			Group:     "kubelatte.synapse.sber",
269
			Resources: []string{"triggerinstances"},
270
			Namespace: ns,
271
			Required:  false,
272
		})
273
	}
274
	m.tiNamespaces[ns] = perms
275
	m.permissions = append(m.permissions, perms...)
276
}
277

278
func (m *Manager) DeleteNamespaceTi(ns string) {
279
	m.rwMutex.Lock()
280
	defer m.rwMutex.Unlock()
281
	log := logger.FromContext(context.Background())
282
	if _, ok := m.tiNamespaces[ns]; !ok {
283
		return
284
	}
285
	log.Debugf("[Permission Manager] stopped check TI permissions in ns: %v ", ns)
286
	for _, tiPermission := range m.tiNamespaces[ns] {
287
		for idx, perm := range m.permissions {
288
			if perm.Namespace == tiPermission.Namespace && perm.Resources[0] == tiPermission.Resources[0] {
289
				m.permissions[idx] = m.permissions[len(m.permissions)-1]
290
				m.permissions = m.permissions[:len(m.permissions)-1]
291
			}
292
		}
293
	}
294
	delete(m.tiNamespaces, ns)
295

296
}
297

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

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

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

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