forked from rancher/rancher
-
Notifications
You must be signed in to change notification settings - Fork 0
/
binding.go
186 lines (156 loc) · 6.27 KB
/
binding.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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package podsecuritypolicy
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/runtime"
"github.com/rancher/types/apis/core/v1"
"github.com/rancher/types/apis/extensions/v1beta1"
"github.com/rancher/types/apis/management.cattle.io/v3"
v12 "github.com/rancher/types/apis/rbac.authorization.k8s.io/v1"
"github.com/rancher/types/config"
"github.com/sirupsen/logrus"
v13 "k8s.io/api/core/v1"
v1beta13 "k8s.io/api/extensions/v1beta1"
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
)
const namespaceByProjectNameIndex = "podsecuritypolicy.rbac.user.cattle.io/by-project-name"
// RegisterBindings updates the pod security policy for this binding if it has been changed. Also resync service
// accounts so they pick up the change. If no policy exists then exits without doing anything.
func RegisterBindings(ctx context.Context, context *config.UserContext) {
logrus.Infof("registering podsecuritypolicy project handler for cluster %v", context.ClusterName)
namespaceInformer := context.Core.Namespaces("").Controller().Informer()
namespaceIndexers := map[string]cache.IndexFunc{
namespaceByProjectNameIndex: namespaceByProjectName,
}
namespaceInformer.AddIndexers(namespaceIndexers)
lifecycle := &lifecycle{
policyLister: context.Extensions.PodSecurityPolicies("").Controller().Lister(),
policies: context.Extensions.PodSecurityPolicies(""),
psptLister: context.Management.Management.PodSecurityPolicyTemplates("").Controller().Lister(),
clusterRoleLister: context.RBAC.ClusterRoles("").Controller().Lister(),
clusterRoles: context.RBAC.ClusterRoles(""),
serviceAccountLister: context.Core.ServiceAccounts("").Controller().Lister(),
serviceAccounts: context.Core.ServiceAccounts("").Controller(),
namespaces: context.Core.Namespaces(""),
namespaceIndexer: namespaceInformer.GetIndexer(),
}
context.Management.Management.PodSecurityPolicyTemplateProjectBindings("").
AddLifecycle(ctx, "PodSecurityPolicyTemplateProjectBindingsLifecycleHandler", lifecycle)
}
func namespaceByProjectName(obj interface{}) ([]string, error) {
namespace, ok := obj.(*v13.Namespace)
if !ok || namespace.Annotations[projectIDAnnotation] == "" {
return []string{}, nil
}
return []string{namespace.Annotations[projectIDAnnotation]}, nil
}
type lifecycle struct {
policyLister v1beta1.PodSecurityPolicyLister
policies v1beta1.PodSecurityPolicyInterface
psptLister v3.PodSecurityPolicyTemplateLister
clusterRoleLister v12.ClusterRoleLister
clusterRoles v12.ClusterRoleInterface
serviceAccountLister v1.ServiceAccountLister
serviceAccounts v1.ServiceAccountController
namespaces v1.NamespaceInterface
namespaceIndexer cache.Indexer
}
func (l *lifecycle) Create(obj *v3.PodSecurityPolicyTemplateProjectBinding) (runtime.Object, error) {
return l.sync(obj)
}
func (l *lifecycle) Updated(obj *v3.PodSecurityPolicyTemplateProjectBinding) (runtime.Object, error) {
return l.sync(obj)
}
func (l *lifecycle) Remove(obj *v3.PodSecurityPolicyTemplateProjectBinding) (runtime.Object, error) {
return obj, l.syncNamespacesInProject(obj.TargetProjectName)
}
func (l *lifecycle) sync(obj *v3.PodSecurityPolicyTemplateProjectBinding) (runtime.Object, error) {
if obj.PodSecurityPolicyTemplateName == "" {
return obj, nil
}
podSecurityPolicyName := fmt.Sprintf("%v-psp", obj.PodSecurityPolicyTemplateName)
_, err := l.policyLister.Get("", podSecurityPolicyName)
if err != nil {
if errors.IsNotFound(err) {
_, err = l.createPolicy(obj, podSecurityPolicyName)
if err != nil {
return nil, fmt.Errorf("error creating policy: %v", err)
}
} else {
return nil, fmt.Errorf("error getting policy: %v", err)
}
}
clusterRoleName := fmt.Sprintf("%v-clusterrole", obj.PodSecurityPolicyTemplateName)
_, err = l.clusterRoleLister.Get("", clusterRoleName)
if err != nil {
if errors.IsNotFound(err) {
_, err = l.createClusterRole(clusterRoleName, podSecurityPolicyName, obj)
if err != nil {
return nil, fmt.Errorf("error creating cluster role: %v", err)
}
} else {
return nil, fmt.Errorf("error getting cluster role: %v", err)
}
}
return obj, l.syncNamespacesInProject(obj.TargetProjectName)
}
func (l *lifecycle) createPolicy(obj *v3.PodSecurityPolicyTemplateProjectBinding,
podSecurityPolicyName string) (*v1beta13.PodSecurityPolicy, error) {
template, err := l.psptLister.Get("", obj.PodSecurityPolicyTemplateName)
if err != nil {
return nil, fmt.Errorf("error getting pspt: %v", err)
}
objectMeta := metav1.ObjectMeta{}
objectMeta.Name = podSecurityPolicyName
objectMeta.Annotations = make(map[string]string)
objectMeta.Annotations[podSecurityPolicyTemplateParentAnnotation] = template.Name
objectMeta.Annotations[podSecurityPolicyTemplateVersionAnnotation] = template.ResourceVersion
psp := &v1beta13.PodSecurityPolicy{
TypeMeta: metav1.TypeMeta{
Kind: podSecurityPolicy,
APIVersion: apiVersion,
},
ObjectMeta: objectMeta,
Spec: template.Spec,
}
return l.policies.Create(psp)
}
func (l *lifecycle) createClusterRole(clusterRoleName string, podSecurityPolicyName string,
obj *v3.PodSecurityPolicyTemplateProjectBinding) (*rbac.ClusterRole, error) {
newRole := &rbac.ClusterRole{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{},
Name: clusterRoleName,
},
TypeMeta: metav1.TypeMeta{
Kind: "ClusterRole",
},
Rules: []rbac.PolicyRule{
{
APIGroups: []string{"extensions"},
Resources: []string{"podsecuritypolicies"},
Verbs: []string{"use"},
ResourceNames: []string{podSecurityPolicyName},
},
},
}
newRole.Annotations[podSecurityPolicyTemplateParentAnnotation] = obj.PodSecurityPolicyTemplateName
return l.clusterRoles.Create(newRole)
}
func (l *lifecycle) syncNamespacesInProject(projectName string) error {
namespaces, err := l.namespaceIndexer.ByIndex(namespaceByProjectNameIndex, projectName)
if err != nil {
return fmt.Errorf("error getting namespaces")
}
for _, rawNamespace := range namespaces {
namespace, ok := rawNamespace.(*v13.Namespace)
if !ok {
return fmt.Errorf("error converting to namespace: %v", rawNamespace)
}
l.namespaces.Controller().Enqueue("", namespace.Name)
}
return nil
}