forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rest.go
135 lines (122 loc) · 5.22 KB
/
rest.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
package podsecuritypolicyreview
import (
"fmt"
"sort"
"github.com/golang/glog"
kapierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
kerrors "k8s.io/apimachinery/pkg/util/errors"
apirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
kapi "k8s.io/kubernetes/pkg/api"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
kcorelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
"k8s.io/kubernetes/pkg/serviceaccount"
securityapi "github.com/openshift/origin/pkg/security/apis/security"
securityvalidation "github.com/openshift/origin/pkg/security/apis/security/validation"
"github.com/openshift/origin/pkg/security/registry/podsecuritypolicysubjectreview"
scc "github.com/openshift/origin/pkg/security/securitycontextconstraints"
)
// REST implements the RESTStorage interface in terms of an Registry.
type REST struct {
sccMatcher scc.SCCMatcher
saCache kcorelisters.ServiceAccountLister
client clientset.Interface
}
var _ rest.Creater = &REST{}
// NewREST creates a new REST for policies..
func NewREST(m scc.SCCMatcher, saCache kcorelisters.ServiceAccountLister, c clientset.Interface) *REST {
return &REST{sccMatcher: m, saCache: saCache, client: c}
}
// New creates a new PodSecurityPolicyReview object
func (r *REST) New() runtime.Object {
return &securityapi.PodSecurityPolicyReview{}
}
// Create registers a given new PodSecurityPolicyReview instance to r.registry.
func (r *REST) Create(ctx apirequest.Context, obj runtime.Object, _ bool) (runtime.Object, error) {
pspr, ok := obj.(*securityapi.PodSecurityPolicyReview)
if !ok {
return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a PodSecurityPolicyReview: %#v", obj))
}
if errs := securityvalidation.ValidatePodSecurityPolicyReview(pspr); len(errs) > 0 {
return nil, kapierrors.NewInvalid(kapi.Kind("PodSecurityPolicyReview"), "", errs)
}
ns, ok := apirequest.NamespaceFrom(ctx)
if !ok {
return nil, kapierrors.NewBadRequest("namespace parameter required.")
}
serviceAccounts, err := getServiceAccounts(pspr.Spec, r.saCache, ns)
if err != nil {
return nil, kapierrors.NewBadRequest(err.Error())
}
if len(serviceAccounts) == 0 {
glog.Errorf("No service accounts for namespace %s", ns)
return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find ServiceAccount for namespace: %s", ns))
}
errs := []error{}
newStatus := securityapi.PodSecurityPolicyReviewStatus{}
for _, sa := range serviceAccounts {
userInfo := serviceaccount.UserInfo(ns, sa.Name, "")
saConstraints, err := r.sccMatcher.FindApplicableSCCs(userInfo)
if err != nil {
errs = append(errs, fmt.Errorf("unable to find SecurityContextConstraints for ServiceAccount %s: %v", sa.Name, err))
continue
}
scc.DeduplicateSecurityContextConstraints(saConstraints)
sort.Sort(scc.ByPriority(saConstraints))
var namespace *kapi.Namespace
for _, constraint := range saConstraints {
var (
provider scc.SecurityContextConstraintsProvider
err error
)
pspsrs := securityapi.PodSecurityPolicySubjectReviewStatus{}
if provider, namespace, err = scc.CreateProviderFromConstraint(ns, namespace, constraint, r.client); err != nil {
errs = append(errs, fmt.Errorf("unable to create provider for service account %s: %v", sa.Name, err))
continue
}
_, err = podsecuritypolicysubjectreview.FillPodSecurityPolicySubjectReviewStatus(&pspsrs, provider, pspr.Spec.Template.Spec, constraint)
if err != nil {
glog.Errorf("unable to fill PodSecurityPolicyReviewStatus from constraint %v", err)
continue
}
sapsprs := securityapi.ServiceAccountPodSecurityPolicyReviewStatus{PodSecurityPolicySubjectReviewStatus: pspsrs, Name: sa.Name}
newStatus.AllowedServiceAccounts = append(newStatus.AllowedServiceAccounts, sapsprs)
}
}
if len(errs) > 0 {
return nil, kapierrors.NewBadRequest(fmt.Sprintf("%s", kerrors.NewAggregate(errs)))
}
pspr.Status = newStatus
return pspr, nil
}
func getServiceAccounts(psprSpec securityapi.PodSecurityPolicyReviewSpec, saCache kcorelisters.ServiceAccountLister, namespace string) ([]*kapi.ServiceAccount, error) {
serviceAccounts := []*kapi.ServiceAccount{}
// TODO: express 'all service accounts'
//if serviceAccountList, err := client.Core().ServiceAccounts(namespace).List(metainternal.ListOptions{}); err == nil {
// serviceAccounts = serviceAccountList.Items
// return serviceAccounts, fmt.Errorf("unable to retrieve service accounts: %v", err)
//}
if len(psprSpec.ServiceAccountNames) > 0 {
errs := []error{}
for _, saName := range psprSpec.ServiceAccountNames {
sa, err := saCache.ServiceAccounts(namespace).Get(saName)
if err != nil {
errs = append(errs, fmt.Errorf("unable to retrieve ServiceAccount %s: %v", saName, err))
continue
}
serviceAccounts = append(serviceAccounts, sa)
}
return serviceAccounts, kerrors.NewAggregate(errs)
}
saName := "default"
if len(psprSpec.Template.Spec.ServiceAccountName) > 0 {
saName = psprSpec.Template.Spec.ServiceAccountName
}
sa, err := saCache.ServiceAccounts(namespace).Get(saName)
if err != nil {
return serviceAccounts, fmt.Errorf("unable to retrieve ServiceAccount %s: %v", saName, err)
}
serviceAccounts = append(serviceAccounts, sa)
return serviceAccounts, nil
}