/
rest.go
127 lines (108 loc) · 4.42 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
package podsecuritypolicysubjectreview
import (
"context"
"fmt"
"k8s.io/klog"
corev1 "k8s.io/api/core/v1"
kapierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/authentication/user"
apirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/api/legacyscheme"
kapiref "k8s.io/kubernetes/pkg/api/ref"
coreapi "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/serviceaccount"
securityapi "github.com/openshift/origin/pkg/security/apis/security"
securityvalidation "github.com/openshift/origin/pkg/security/apis/security/validation"
scc "github.com/openshift/origin/pkg/security/apiserver/securitycontextconstraints"
)
// REST implements the RESTStorage interface in terms of an Registry.
type REST struct {
sccMatcher scc.SCCMatcher
client kubernetes.Interface
}
var _ rest.Creater = &REST{}
var _ rest.Scoper = &REST{}
// NewREST creates a new REST for policies..
func NewREST(m scc.SCCMatcher, c kubernetes.Interface) *REST {
return &REST{sccMatcher: m, client: c}
}
// New creates a new PodSecurityPolicySubjectReview object
func (r *REST) New() runtime.Object {
return &securityapi.PodSecurityPolicySubjectReview{}
}
func (s *REST) NamespaceScoped() bool {
return true
}
// Create registers a given new PodSecurityPolicySubjectReview instance to r.registry.
func (r *REST) Create(ctx context.Context, obj runtime.Object, _ rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
pspsr, ok := obj.(*securityapi.PodSecurityPolicySubjectReview)
if !ok {
return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a PodSecurityPolicySubjectReview: %#v", obj))
}
ns, ok := apirequest.NamespaceFrom(ctx)
if !ok {
return nil, kapierrors.NewBadRequest("namespace parameter required.")
}
if errs := securityvalidation.ValidatePodSecurityPolicySubjectReview(pspsr); len(errs) > 0 {
return nil, kapierrors.NewInvalid(coreapi.Kind("PodSecurityPolicySubjectReview"), "", errs)
}
var users []user.Info
specUser := &user.DefaultInfo{Name: pspsr.Spec.User, Groups: pspsr.Spec.Groups}
if len(specUser.Name) > 0 || len(specUser.Groups) > 0 {
users = append(users, specUser)
}
saName := pspsr.Spec.Template.Spec.ServiceAccountName
if len(saName) > 0 {
users = append(users, serviceaccount.UserInfo(ns, saName, ""))
}
matchedConstraints, err := r.sccMatcher.FindApplicableSCCs(ns, users...)
if err != nil {
return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find SecurityContextConstraints: %v", err))
}
var namespace *corev1.Namespace
for _, constraint := range matchedConstraints {
var (
provider scc.SecurityContextConstraintsProvider
err error
)
if provider, namespace, err = scc.CreateProviderFromConstraint(ns, namespace, constraint, r.client); err != nil {
klog.Errorf("Unable to create provider for constraint: %v", err)
continue
}
filled, err := FillPodSecurityPolicySubjectReviewStatus(&pspsr.Status, provider, pspsr.Spec.Template.Spec, constraint)
if err != nil {
klog.Errorf("unable to fill PodSecurityPolicySubjectReviewStatus from constraint %v", err)
continue
}
if filled {
return pspsr, nil
}
}
return pspsr, nil
}
// FillPodSecurityPolicySubjectReviewStatus fills PodSecurityPolicySubjectReviewStatus assigning SecurityContectConstraint to the PodSpec
func FillPodSecurityPolicySubjectReviewStatus(s *securityapi.PodSecurityPolicySubjectReviewStatus, provider scc.SecurityContextConstraintsProvider, spec coreapi.PodSpec, constraint *securityapi.SecurityContextConstraints) (bool, error) {
pod := &coreapi.Pod{
Spec: spec,
}
if errs := scc.AssignSecurityContext(provider, pod, field.NewPath(fmt.Sprintf("provider %s: ", provider.GetSCCName()))); len(errs) > 0 {
klog.Errorf("unable to assign SecurityContextConstraints provider: %v", errs)
s.Reason = "CantAssignSecurityContextConstraintProvider"
return false, fmt.Errorf("unable to assign SecurityContextConstraints provider: %v", errs.ToAggregate())
}
ref, err := kapiref.GetReference(legacyscheme.Scheme, constraint)
if err != nil {
s.Reason = "CantObtainReference"
return false, fmt.Errorf("unable to get SecurityContextConstraints reference: %v", err)
}
s.AllowedBy = ref
if len(spec.ServiceAccountName) > 0 {
s.Template.Spec = pod.Spec
}
return true, nil
}