Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Your cluster, your rules

Piotr Janik
September 09, 2019

Your cluster, your rules

Piotr Janik

September 09, 2019
Tweet

Other Decks in Technology

Transcript

  1. What’s in it for you? #1 Define rules for your

    kubernetes cluster to ensure: - resource naming strategy - required properties are always set - images come from approved repositories #2 Build an authorization mechanism for Microservices which: - delegated - scalable - flexible
  2. “OPA is a full-featured policy engine that offloads policy decisions

    from your service.” Source: openpolicyagent.org What is OPA?
  3. How does OPA work? ▪ Golang binary - small &

    fast ▪ Uses its two main components: ◦ Policies - written in OPA built-in language REGO ◦ Data - just json documents ▪ Exposes easy to integrate with REST Api To run: ▪ You need a single binary or a docker image ▪ Put your rego and data files in ./policies directory docker run -ti -p 8181:8181 \ -v $(pwd)/policies:/policies \ openpolicyagent/opa:latest run -w -s /policies
  4. Policies sample.rego package sample default allow = false allow =

    true { input.name = "John" input.city = "Warsaw" } allow = true { input.name = "Mark" input.city = "Cracow" } Input.json {"input":{"name":"John","city":"Cracow"}} • Organized in packages • Input - context to make a decision • Rules: ◦ Can have default values ◦ Are defined as a set of assertions ◦ Can be repeated with the same name • At least one rule has to be true
  5. Data data.json { "employees": [ {"name": "John","city": "Warsaw"}, {"name": "Mark","city":

    "Cracow"} ] } policy.rego package sample default allow = false allow = true { data.employees[e].name = input.name data.employees[e].city = input.city } • Simple JSON that can be loaded from: ◦ from file ◦ via Rest API • You can refer to it by data.[field]
  6. Rest API To evaluate policy send input json object with

    a POST request to: http://{opa_host}/v1/data/{package}/{rule_name} # curl -XPOST \ http://localhost:8181/v1/data/sample/allow \ -d '{"input":{"name":"John","city":"Warsaw"}}' {"result":true} # curl -XPOST \ http://localhost:8181/v1/data/sample/allow \ -d '{"input":{"name":"John","city":"Cracow"}}' {"result":false} data.json { "employees": [ {"name": "John","city": "Warsaw"}, {"name": "Mark","city": "Cracow"} ] } policy.rego package sample default allow = false allow = true { data.employees[e].name = input.name data.employees[e].city = input.city }
  7. Testing, testing... • Prefixed with “test” rego policies are used

    for testing • Test should share same package • You can mock input data # opa test ./path/to/policies test_policy.rego package sample test_john_from_warsaw_is_approved { allow with input as {"name":"John", "city":"Warsaw"} } test_john_from_moon_is_rejected { not allow with input as {"name":"John", "city":"Moon"} } policy.rego package sample default allow = false allow = true { data.employees[e].name = input.name data.employees[e].city = input.city }
  8. #1 I want everyone to follow my rules when working

    with my kubernetes cluster. Key takeaways: • How can I enforce rules in my cluster? • How do I work with Gatekeeper? • How do I write Constraint?
  9. I want everyone to follow my rules when working with

    my kubernetes cluster. 1. I really like the idea of recommended labels, so should you. https://kubernetes.io/docs/concepts/overview/working-with-o bjects/common-labels/ 2. I don't trust images from unknown sources, so I will whitelist those I trust(or like more...). 3. Because I like naming strategy all hosts in your Ingress controller should contain namespace name. 4. Oh, and don't dare to create Pods without resource limits
  10. The Gatekeeper Policy enforcement in Kubernetes 1. Detects and reject

    non-compliant resource with an immediate feedback. 2. Allows to define Constraints as Native Kubernetes CRDs. 3. Works with Admission Controller Webhooks 4. Uses Open Policy Agent :)
  11. The Gatekeeper | Installation This will create: ▪ Gatekeeper itself

    as a StatefulSet ▪ ClusterRole and ClusterRoleBinding for Gatekeeper ▪ Custom Resource Definitions - ConstraintTemplates ▪ Default config ▪ Service # kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yaml
  12. Constraint Template ▪ Cluster scope template for constraints. ▪ Parameters

    defined in Open API Schema. ▪ Contains a policy written in REGO. ▪ Creates a CRD for its implementation. apiVersion: templates.gatekeeper.sh/v1beta1 kind: ConstraintTemplate metadata: name: requiredlabels spec: crd: spec: names: kind: RequiredLabels listKind: RequiredLabels plural: requiredlabels singular: requiredlabels validation: openAPIV3Schema: properties: labels: type: array items: string targets: - target: admission.k8s.gatekeeper.sh rego: | package k8srequiredlabels violation[{"msg": msg, "details": {"missing_labels": missing}}] { provided := {label | input.review.object.metadata.labels[label]} required := {label | label := input.parameters.labels[_]} missing := required - provided count(missing) > 0 msg := sprintf("you must provide labels: %v", [missing]) }
  13. Constraint ▪ A Custom Resource Definition ▪ Actual implementation of

    a template. ▪ Allows to select resources it should be applied to. ▪ Provides parameters values. apiVersion: constraints.gatekeeper.sh/v1beta1 kind: RequiredLabels metadata: name: recommendedlabels spec: match: kinds: - apiGroups: ["extensions","apps"] kinds: ["Deployment"] parameters: labels: - "app.kubernetes.io/name" - "app.kubernetes.io/instance" - "app.kubernetes.io/version" - "app.kubernetes.io/component" - "app.kubernetes.io/part-of" - "app.kubernetes.io/managed-by"
  14. Test it! ▪ Just like regular rego policy ▪ You

    can mock input like ◦ review object ◦ parameters test_required_labels.rego package k8srequiredlabels test_missing_labels { count(violation) > 0 with input as {"review": {"object": {"metadata":{"labels":{ "wrong":"label" }}}}, "parameters": { "labels": [ "correct" ]}} } required_labels.rego package k8srequiredlabels violation[{"msg": msg, "details": {"missing_labels": missing}}]{ provided := {label | input.review.object.metadata.labels[label]} required := {label | label := input.parameters.labels[_]} missing := required - provided count(missing) > 0 msg := sprintf("you must provide labels: %v", [missing]) }
  15. #2 The never ending story of Microservices... ... so let's

    create another one to rule them all! Key takeaways: • How to build fine-grained, scalable access control mechanism for microservice? • How do I run OPA as a sidecar? • How can we build IAM-like policies?
  16. How we used to make access decisions? ▪ Hardcoded rules?

    ▪ Lack of scalability? ▪ What about tests? Java/Spring @Service public class FooService { @PreAuthorize("hasRole('ROLE_ADMIN')") public List<Foo> findAll() { ... } ... } NodeJS app.get('/blog/create', function (req, res, next) { if(!req.session.hasRole('writer')) { res.sendStatus(403); return; } res.send('Blog edit'); });
  17. How can OPA help? ▪ Run OPA as a sidecar

    ▪ Delegate decisions to OPA by calling it whenever user performs some action ▪ Send required context to make decisions as an input ▪ Maintain policies in a central place What could Sample Input look like? ▪ Principal - Who is performing an action? ◦ Name of a user? ◦ Group user is part of? ◦ Json Web Token? ▪ Resource - What kind of resource action refers to? ◦ Name of a service? ◦ Name of REST resource? ▪ Action - How actually user wants to do? ◦ Get some data? ◦ List some objects? ◦ Update? Sounds familiar?
  18. Microservices | OPA as a sidecar OPA Sidecar available to

    pod on localhost updates policies and data Microservice Microservice Microservice
  19. Microservices | Policy Repository HTTP Server serving: bundle.tar.gz compressed archived

    with: • policies(rego) and • data Microservice Microservice Microservice Policy Repository
  20. Microservices | OPA and JWT External user authentication and authorization

    over OpenID Microservice Microservice Microservice Identity Provider (JWT) Resource Server
  21. Synchronise policies ▪ All OPA instances can periodically poll policies

    and data file from http location ▪ OPA instance (sidecar) keep its own copy of policies ▪ Policies and data file should be archived and compressed as tar.gz file ▪ You can enable it by providing configuration file OPA config file services: - name: demo url: http://hostname bundles: authz: service: demo resource: bundle.tar.gz polling: min_delay_seconds: 10 max_delay_seconds: 20
  22. Let’s build custom JSON policies (IAM-like) ▪ Standardise policies in

    a JSON format ▪ Write Rego files once to check JSON policies with an input from microservice ▪ Maintain easy to update JSON policies Sample implementation: https://github.com/piotrjanik/opa-iam-like-policies [ { "effect": "Allow", "principal": "*", "resources": "*", "action": ["GetAll" ] }, { "effect": "Allow", "principal": { "name": "John", "email_verified": true }, "resources": [ {"name": "enquiries","id": 1}, {"name": "enquiries","id": 2}, {"name": "enquiries","id": 3} ], "action": ["Update"] }, { "effect": "Allow", "principal": { "email_verified": true }, "resources": [ {"name": "orders","status": "CANCELLED"} ], "action": ["Update"] } ]
  23. Thanks! Demo available here: https://github.com/piotrjanik/opa-warsaw-cloud-native-conf IAM-Like policies: https://github.com/piotrjanik/opa-iam-like-policies Open Policy

    Agent Blog: https://blog.openpolicyagent.org/ Let’s stay in touch: Piotr Janik https://github.com/piotrjanik https://www.linkedin.com/in/piotrjanik