mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-25 20:29:56 +00:00
Propagate context to Authorize() calls
This commit is contained in:
@@ -112,7 +112,7 @@ func (a *gcPermissionsEnforcement) Validate(ctx context.Context, attributes admi
|
||||
ResourceRequest: true,
|
||||
Path: "",
|
||||
}
|
||||
decision, reason, err := a.authorizer.Authorize(deleteAttributes)
|
||||
decision, reason, err := a.authorizer.Authorize(ctx, deleteAttributes)
|
||||
if decision != authorizer.DecisionAllow {
|
||||
return admission.NewForbidden(attributes, fmt.Errorf("cannot set an ownerRef on a resource you can't delete: %v, %v", reason, err))
|
||||
}
|
||||
@@ -131,7 +131,7 @@ func (a *gcPermissionsEnforcement) Validate(ctx context.Context, attributes admi
|
||||
// resources. User needs to have delete permission on all the
|
||||
// matched Resources.
|
||||
for _, record := range records {
|
||||
decision, reason, err := a.authorizer.Authorize(record)
|
||||
decision, reason, err := a.authorizer.Authorize(ctx, record)
|
||||
if decision != authorizer.DecisionAllow {
|
||||
return admission.NewForbidden(attributes, fmt.Errorf("cannot set blockOwnerDeletion if an ownerReference refers to a resource you can't set finalizers on: %v, %v", reason, err))
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ import (
|
||||
|
||||
type fakeAuthorizer struct{}
|
||||
|
||||
func (fakeAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
func (fakeAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
username := a.GetUser().GetName()
|
||||
|
||||
if username == "non-deleter" {
|
||||
|
@@ -126,7 +126,7 @@ func (p *Plugin) Admit(ctx context.Context, a admission.Attributes, o admission.
|
||||
pod := a.GetObject().(*api.Pod)
|
||||
|
||||
// compute the context. Mutation is allowed. ValidatedPSPAnnotation is not taken into account.
|
||||
allowedPod, pspName, validationErrs, err := p.computeSecurityContext(a, pod, true, "")
|
||||
allowedPod, pspName, validationErrs, err := p.computeSecurityContext(ctx, a, pod, true, "")
|
||||
if err != nil {
|
||||
return admission.NewForbidden(a, err)
|
||||
}
|
||||
@@ -161,7 +161,7 @@ func (p *Plugin) Validate(ctx context.Context, a admission.Attributes, o admissi
|
||||
pod := a.GetObject().(*api.Pod)
|
||||
|
||||
// compute the context. Mutation is not allowed. ValidatedPSPAnnotation is used as a hint to gain same speed-up.
|
||||
allowedPod, pspName, validationErrs, err := p.computeSecurityContext(a, pod, false, pod.ObjectMeta.Annotations[psputil.ValidatedPSPAnnotation])
|
||||
allowedPod, pspName, validationErrs, err := p.computeSecurityContext(ctx, a, pod, false, pod.ObjectMeta.Annotations[psputil.ValidatedPSPAnnotation])
|
||||
if err != nil {
|
||||
return admission.NewForbidden(a, err)
|
||||
}
|
||||
@@ -207,7 +207,7 @@ func shouldIgnore(a admission.Attributes) (bool, error) {
|
||||
// if there is a matching policy with the same security context as given, it will be reused. If there is no
|
||||
// matching policy the returned pod will be nil and the pspName empty. validatedPSPHint is the validated psp name
|
||||
// saved in kubernetes.io/psp annotation. This psp is usually the one we are looking for.
|
||||
func (p *Plugin) computeSecurityContext(a admission.Attributes, pod *api.Pod, specMutationAllowed bool, validatedPSPHint string) (*api.Pod, string, field.ErrorList, error) {
|
||||
func (p *Plugin) computeSecurityContext(ctx context.Context, a admission.Attributes, pod *api.Pod, specMutationAllowed bool, validatedPSPHint string) (*api.Pod, string, field.ErrorList, error) {
|
||||
// get all constraints that are usable by the user
|
||||
klog.V(4).Infof("getting pod security policies for pod %s (generate: %s)", pod.Name, pod.GenerateName)
|
||||
var saInfo user.Info
|
||||
@@ -271,7 +271,7 @@ func (p *Plugin) computeSecurityContext(a admission.Attributes, pod *api.Pod, sp
|
||||
continue
|
||||
}
|
||||
|
||||
if !isAuthorizedForPolicy(a.GetUserInfo(), saInfo, a.GetNamespace(), provider.GetPSPName(), p.authz) {
|
||||
if !isAuthorizedForPolicy(ctx, a.GetUserInfo(), saInfo, a.GetNamespace(), provider.GetPSPName(), p.authz) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ func (p *Plugin) computeSecurityContext(a admission.Attributes, pod *api.Pod, sp
|
||||
// Pod is rejected. Filter the validation errors to only include errors from authorized PSPs.
|
||||
aggregate := field.ErrorList{}
|
||||
for psp, errs := range validationErrs {
|
||||
if isAuthorizedForPolicy(a.GetUserInfo(), saInfo, a.GetNamespace(), psp, p.authz) {
|
||||
if isAuthorizedForPolicy(ctx, a.GetUserInfo(), saInfo, a.GetNamespace(), psp, p.authz) {
|
||||
aggregate = append(aggregate, errs...)
|
||||
}
|
||||
}
|
||||
@@ -338,27 +338,27 @@ func (p *Plugin) createProvidersFromPolicies(psps []*policyv1beta1.PodSecurityPo
|
||||
return providers, errs
|
||||
}
|
||||
|
||||
func isAuthorizedForPolicy(user, sa user.Info, namespace, policyName string, authz authorizer.Authorizer) bool {
|
||||
func isAuthorizedForPolicy(ctx context.Context, user, sa user.Info, namespace, policyName string, authz authorizer.Authorizer) bool {
|
||||
// Check the service account first, as that is the more common use case.
|
||||
return authorizedForPolicy(sa, namespace, policyName, authz) ||
|
||||
authorizedForPolicy(user, namespace, policyName, authz)
|
||||
return authorizedForPolicy(ctx, sa, namespace, policyName, authz) ||
|
||||
authorizedForPolicy(ctx, user, namespace, policyName, authz)
|
||||
}
|
||||
|
||||
// authorizedForPolicy returns true if info is authorized to perform the "use" verb on the policy resource.
|
||||
// TODO: check against only the policy group when PSP will be completely moved out of the extensions
|
||||
func authorizedForPolicy(info user.Info, namespace string, policyName string, authz authorizer.Authorizer) bool {
|
||||
func authorizedForPolicy(ctx context.Context, info user.Info, namespace string, policyName string, authz authorizer.Authorizer) bool {
|
||||
// Check against extensions API group for backward compatibility
|
||||
return authorizedForPolicyInAPIGroup(info, namespace, policyName, policy.GroupName, authz) ||
|
||||
authorizedForPolicyInAPIGroup(info, namespace, policyName, extensions.GroupName, authz)
|
||||
return authorizedForPolicyInAPIGroup(ctx, info, namespace, policyName, policy.GroupName, authz) ||
|
||||
authorizedForPolicyInAPIGroup(ctx, info, namespace, policyName, extensions.GroupName, authz)
|
||||
}
|
||||
|
||||
// authorizedForPolicyInAPIGroup returns true if info is authorized to perform the "use" verb on the policy resource in the specified API group.
|
||||
func authorizedForPolicyInAPIGroup(info user.Info, namespace, policyName, apiGroupName string, authz authorizer.Authorizer) bool {
|
||||
func authorizedForPolicyInAPIGroup(ctx context.Context, info user.Info, namespace, policyName, apiGroupName string, authz authorizer.Authorizer) bool {
|
||||
if info == nil {
|
||||
return false
|
||||
}
|
||||
attr := buildAttributes(info, namespace, policyName, apiGroupName)
|
||||
decision, reason, err := authz.Authorize(attr)
|
||||
decision, reason, err := authz.Authorize(ctx, attr)
|
||||
if err != nil {
|
||||
klog.V(5).Infof("cannot authorize for policy: %v,%v", reason, err)
|
||||
}
|
||||
|
@@ -84,7 +84,7 @@ type TestAuthorizer struct {
|
||||
allowedAPIGroupName string
|
||||
}
|
||||
|
||||
func (t *TestAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
func (t *TestAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
if t.usernameToNamespaceToAllowedPSPs == nil {
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
@@ -2249,7 +2249,7 @@ func TestPolicyAuthorizationErrors(t *testing.T) {
|
||||
plugin := NewTestAdmission(tc.inPolicies, authz)
|
||||
attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), ns, "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &metav1.CreateOptions{}, false, &user.DefaultInfo{Name: userName})
|
||||
|
||||
allowedPod, _, validationErrs, err := plugin.computeSecurityContext(attrs, pod, true, "")
|
||||
allowedPod, _, validationErrs, err := plugin.computeSecurityContext(context.Background(), attrs, pod, true, "")
|
||||
assert.Nil(t, allowedPod)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, validationErrs, tc.expectValidationErrs)
|
||||
@@ -2342,7 +2342,7 @@ func TestPreferValidatedPSP(t *testing.T) {
|
||||
plugin := NewTestAdmission(tc.inPolicies, authz)
|
||||
attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "ns", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Update, &metav1.UpdateOptions{}, false, &user.DefaultInfo{Name: "test"})
|
||||
|
||||
_, pspName, validationErrs, err := plugin.computeSecurityContext(attrs, pod, false, tc.validatedPSPHint)
|
||||
_, pspName, validationErrs, err := plugin.computeSecurityContext(context.Background(), attrs, pod, false, tc.validatedPSPHint)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, validationErrs, tc.expectValidationErrs)
|
||||
assert.Equal(t, tc.expectedPSP, pspName)
|
||||
|
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/klog"
|
||||
@@ -78,7 +79,7 @@ var (
|
||||
csiNodeResource = storageapi.Resource("csinodes")
|
||||
)
|
||||
|
||||
func (r *NodeAuthorizer) Authorize(attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
func (r *NodeAuthorizer) Authorize(ctx context.Context, attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
nodeName, isNode := r.identifier.NodeIdentity(attrs.GetUser())
|
||||
if !isNode {
|
||||
// reject requests from non-nodes
|
||||
|
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
@@ -414,7 +415,7 @@ func TestAuthorizer(t *testing.T) {
|
||||
} else {
|
||||
authz.features = tc.features
|
||||
}
|
||||
decision, _, _ := authz.Authorize(tc.attrs)
|
||||
decision, _, _ := authz.Authorize(context.Background(), tc.attrs)
|
||||
if decision != tc.expect {
|
||||
t.Errorf("expected %v, got %v", tc.expect, decision)
|
||||
}
|
||||
@@ -504,13 +505,13 @@ func TestAuthorizerSharedResources(t *testing.T) {
|
||||
)
|
||||
|
||||
if len(tc.Secret) > 0 {
|
||||
decision, _, err = authz.Authorize(authorizer.AttributesRecord{User: tc.User, ResourceRequest: true, Verb: "get", Resource: "secrets", Namespace: "ns1", Name: tc.Secret})
|
||||
decision, _, err = authz.Authorize(context.Background(), authorizer.AttributesRecord{User: tc.User, ResourceRequest: true, Verb: "get", Resource: "secrets", Namespace: "ns1", Name: tc.Secret})
|
||||
if err != nil {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
} else if len(tc.ConfigMap) > 0 {
|
||||
decision, _, err = authz.Authorize(authorizer.AttributesRecord{User: tc.User, ResourceRequest: true, Verb: "get", Resource: "configmaps", Namespace: "ns1", Name: tc.ConfigMap})
|
||||
decision, _, err = authz.Authorize(context.Background(), authorizer.AttributesRecord{User: tc.User, ResourceRequest: true, Verb: "get", Resource: "configmaps", Namespace: "ns1", Name: tc.ConfigMap})
|
||||
if err != nil {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
continue
|
||||
@@ -527,7 +528,7 @@ func TestAuthorizerSharedResources(t *testing.T) {
|
||||
{
|
||||
node3SharedSecretGet := authorizer.AttributesRecord{User: node3, ResourceRequest: true, Verb: "get", Resource: "secrets", Namespace: "ns1", Name: "shared-all"}
|
||||
|
||||
decision, _, err := authz.Authorize(node3SharedSecretGet)
|
||||
decision, _, err := authz.Authorize(context.Background(), node3SharedSecretGet)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -539,7 +540,7 @@ func TestAuthorizerSharedResources(t *testing.T) {
|
||||
pod3.Spec.Volumes = nil
|
||||
g.AddPod(pod3)
|
||||
|
||||
decision, _, err = authz.Authorize(node3SharedSecretGet)
|
||||
decision, _, err = authz.Authorize(context.Background(), node3SharedSecretGet)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -833,7 +834,7 @@ func BenchmarkAuthorization(b *testing.B) {
|
||||
b.SetParallelism(5000)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
decision, _, _ := authz.Authorize(tc.attrs)
|
||||
decision, _, _ := authz.Authorize(context.Background(), tc.attrs)
|
||||
if decision != tc.expect {
|
||||
b.Errorf("expected %v, got %v", tc.expect, decision)
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ package rbac
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/klog"
|
||||
@@ -71,7 +72,7 @@ func (v *authorizingVisitor) visit(source fmt.Stringer, rule *rbacv1.PolicyRule,
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
func (r *RBACAuthorizer) Authorize(ctx context.Context, requestAttributes authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
ruleCheckingVisitor := &authorizingVisitor{requestAttributes: requestAttributes}
|
||||
|
||||
r.authorizationRuleResolver.VisitRulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit)
|
||||
|
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -248,13 +249,13 @@ func TestAuthorizer(t *testing.T) {
|
||||
ruleResolver, _ := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
||||
a := RBACAuthorizer{ruleResolver}
|
||||
for _, attr := range tt.shouldPass {
|
||||
if decision, _, _ := a.Authorize(attr); decision != authorizer.DecisionAllow {
|
||||
if decision, _, _ := a.Authorize(context.Background(), attr); decision != authorizer.DecisionAllow {
|
||||
t.Errorf("case %d: incorrectly restricted %s", i, attr)
|
||||
}
|
||||
}
|
||||
|
||||
for _, attr := range tt.shouldFail {
|
||||
if decision, _, _ := a.Authorize(attr); decision == authorizer.DecisionAllow {
|
||||
if decision, _, _ := a.Authorize(context.Background(), attr); decision == authorizer.DecisionAllow {
|
||||
t.Errorf("case %d: incorrectly passed %s", i, attr)
|
||||
}
|
||||
}
|
||||
@@ -516,7 +517,7 @@ func BenchmarkAuthorize(b *testing.B) {
|
||||
for _, request := range requests {
|
||||
b.Run(request.name, func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
authz.Authorize(request.attrs)
|
||||
authz.Authorize(context.Background(), request.attrs)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user