Last active
April 24, 2019 04:05
-
-
Save mikedanese/03361c9bb634008bd6a0a0c31db6d555 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// pseudo-code sketch of condition support in Kubernetes authorization | |
package conditions | |
// authorization.k8s.io changes | |
type SubjectAccessReviewSpec struct { | |
// ... | |
ExtraAttributes map[string]string | |
} | |
type SubjectAccessReviewStatus struct { | |
// ... | |
Condition *Condition | |
} | |
type Condition struct { | |
Expression string | |
} | |
// new attribute calculator API | |
// Environment holds bindings to attributes required to evaluate a conditional | |
// expression. It is expected to be created per invocation of a condition | |
// program. | |
type Environment struct { | |
Bindings map[string]interface{} | |
} | |
type AttributeCalculator interface { | |
// Bind binds calcluated attributes to a conditional expression. | |
// | |
// TODO: explain how lazy evaluation works. | |
Bind(context.Context, admission.Attributes, Environment) error | |
} | |
// new condition evaluater | |
type condEvaler struct { | |
calculators []AttributeCalculator | |
} | |
func (a *condEvaler) Prepare(ctx context.Context, attrs admission.Attributes, cond Condition) (Condition, error) { | |
// create a new environment | |
env := NewEnvironment() | |
// bind derived attributes to the environment by querying all registered | |
// attribute calculators | |
for _, c := range ca.calculators { | |
c.Bind(ctx, attrs, env) | |
} | |
// partially evalulate the condition | |
EvalPartial(&cond, env) | |
// return a pruned/simplified equivalent condition | |
return cond, nil | |
} | |
// Example usage | |
// | |
// There are two obvious places where condition evaluation occurs: | |
// * somewhere near the authorization filter. This is a complete evaluation of | |
// the condition that gate's the request's admission. | |
// * in the SubjectAccessReview registry. This is a partial evaluation of the | |
// condition. | |
// | |
// This example covers the first. | |
type filter struct { | |
authz authorizer.Authorizer | |
ce *condEvaler | |
next Filter | |
} | |
func (f *filter) Do(ctx context.Context, req http.Request) (http.Response, error) { | |
// first query the authorizers | |
resp := f.authz.Authorize(ctx, authorizer.MakeAttributes(req)) | |
// if the authorizers do not return a conditional yes, return immediately | |
if !resp.Denied || resp.Condition == nil { | |
return resp, nil | |
} | |
// partially evaluate the condition | |
resp.Condition = ca.Prepare(ctx, admission.MakeAttributes(req), resp.Condition) | |
// attempt to fully evaluate the condition. if successful, return an | |
// unconditional yes. | |
if err := EvalFull(resp.Condition); err { | |
// else return the simplified condition | |
return fmt.Errorf("authz failed: %v", err) | |
} | |
return f.next.Do(ctx, req) | |
} | |
// Example RBAC binding. | |
// | |
// This RBAC role grants cluster admin to | |
// | |
// apiVersion: rbac.authorization.k8s.io/v1 | |
// kind: ClusterRoleBinding | |
// metadata: | |
// name: node-scoped | |
// roleRef: | |
// apiGroup: rbac.authorization.k8s.io | |
// kind: ClusterRole | |
// name: cluster-admin | |
// subjects: | |
// - apiGroup: rbac.authorization.k8s.io | |
// kind: ServiceAccount | |
// namespace: kube-system | |
// name: thingy | |
// condition: | |
// # isRechable doesn't need any arguments here because the attribute | |
// # calcluator binds a function to isReachable that captures required state | |
// # from request attributes. | |
// expression: "nodeGraph.isReachable()" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment