-
Notifications
You must be signed in to change notification settings - Fork 53
/
rbac_provider.go
93 lines (87 loc) · 2.53 KB
/
rbac_provider.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package storage
import (
"context"
"fmt"
"sort"
corev1 "github.com/rancher/opni/pkg/apis/core/v1"
"github.com/rancher/opni/pkg/logger"
"github.com/rancher/opni/pkg/rbac"
"go.uber.org/zap"
)
type rbacProvider struct {
store SubjectAccessCapableStore
logger *zap.SugaredLogger
}
func NewRBACProvider(store SubjectAccessCapableStore) rbac.Provider {
return &rbacProvider{
store: store,
logger: logger.New().Named("rbac"),
}
}
func (p *rbacProvider) SubjectAccess(
ctx context.Context,
req *corev1.SubjectAccessRequest,
) (*corev1.ReferenceList, error) {
// Look up all role bindings which exist for this user, then look up the roles
// referenced by those role bindings. Aggregate the resulting tenant IDs from
// the roles and filter out any duplicates.
rbs, err := p.store.ListRoleBindings(ctx)
if err != nil {
return nil, fmt.Errorf("failed to list role bindings: %w", err)
}
allowedClusters := map[string]struct{}{}
// All applicable role bindings for this user are ORed together
for _, roleBinding := range rbs.Items {
appliesToUser := false
for _, s := range roleBinding.Subjects {
if s == req.Subject {
appliesToUser = true
}
}
if !appliesToUser {
continue
}
if taints := roleBinding.Taints; len(taints) > 0 {
p.logger.With(
"roleBinding", roleBinding.Id,
"role", roleBinding.Id,
"taints", roleBinding.Taints,
).Warn("skipping tainted role binding")
continue
}
role, err := p.store.GetRole(ctx, roleBinding.RoleReference())
if err != nil {
p.logger.With(
zap.Error(err),
"roleBinding", roleBinding.Id,
"role", roleBinding.RoleId,
).Warn("error looking up role")
continue
}
// Add explicitly-allowed clusters to the list
for _, clusterID := range role.ClusterIDs {
allowedClusters[clusterID] = struct{}{}
}
// Add any clusters to the list which match the role's label selector
filteredList, err := p.store.ListClusters(ctx, role.MatchLabels,
corev1.MatchOptions_EmptySelectorMatchesNone)
if err != nil {
return nil, fmt.Errorf("failed to list clusters: %w", err)
}
for _, cluster := range filteredList.Items {
allowedClusters[cluster.Id] = struct{}{}
}
}
sortedReferences := make([]*corev1.Reference, 0, len(allowedClusters))
for clusterID := range allowedClusters {
sortedReferences = append(sortedReferences, &corev1.Reference{
Id: clusterID,
})
}
sort.Slice(sortedReferences, func(i, j int) bool {
return sortedReferences[i].Id < sortedReferences[j].Id
})
return &corev1.ReferenceList{
Items: sortedReferences,
}, nil
}