Coverage as Code and the Open Coverage Agent
8 mins read

Coverage as Code and the Open Coverage Agent


Coverage as code is the pure evolution of infrastructure as code. When you begin to handle your infrastructure as code, you quickly notice that the method wants stable governance and enforcement of insurance policies at scale. The standard strategy of defining and imposing insurance policies with guide processes or cumbersome GUIs gained’t reduce it.

Coverage as code implies that you outline insurance policies declaratively utilizing textual content information which can be checked into supply management and could be reviewed and audited. Then, a coverage engine is accountable for imposing the insurance policies.

On this article, we are going to deal with how coverage as code performs out in Kubernetes. We’ll take a look at what comes built-in with Kubernetes and the way the Open Coverage Agent—with Gatekeeper—helps Kubernetes operators take coverage enforcement additional.

The coverage as code mannequin matches Kubernetes like a glove, since Kubernetes is about declarative definitions at each stage. An administrator or developer defines assets, sometimes as YAML information, and Kubernetes shops them in its state retailer, etcd. Then, the Kubernetes controllers watch these assets and reconcile the state of the world with these assets.

For instance, for those who create a Deployment useful resource with a picture and a sure variety of replicas, then Kubernetes will create pods that run the picture and make sure the appropriate variety of replicas is working.

Insurance policies are simply one other sort of useful resource

Kubernetes itself defines some insurance policies similar to pod safety insurance policies and community insurance policies. Nevertheless, the extensible nature of Kubernetes permits using third-party insurance policies and coverage engines.

Admission controllers as coverage enforcers

In Kubernetes, the lifecycle of a request goes by authentication, authorization, and admission. When a request comes  in, Kubernetes first authenticates it to see who’s making the request. Then, the request goes by authorization to see if the requesting entity is permitted to make this request. The request could be rejected at this level. If the request is permitted, then it goes by admission, which checks extra dynamic situations. A certified request can also be rejected at this stage.

Admission is the stage the place coverage enforcement is available in. Coverage engines could be carried out as admission controllers that may flag, alert, and/or reject requests that violate insurance policies.

Pod safety insurance policies

Kubernetes had pod safety insurance policies, however they had been deprecated in Kubernetes 1.21 and will probably be changed by a more recent design. Implementing safety settings on a pod is a vital concern that may’t be finished utilizing present mechanisms like authentication, authorization, or pod safety context. An excellent instance of such a coverage is forbidding pods in a sure namespace to run with root privileges.

Community insurance policies

Controlling community ingress and egress is one other important functionality. Kubernetes offers built-in community insurance policies. The community coverage operates on the pod stage (utilizing label selectors) and may management entry (ingress and egress) on the namespace, pod, or IP block stage. Be aware that Kubernetes doesn’t present a controller to implement the coverage. To make use of community insurance policies, the cluster should have a community plugin that helps community insurance policies.

Whereas Kubernetes’ built-in insurance policies are a very good begin, they’re inadequate for a lot of organizations with superior governance necessities. That is the place third-party coverage engines are available in. The Open Coverage Agent, which is a CNCF undertaking, is a cloud-native coverage engine that may implement insurance policies for a lot of completely different targets, together with Kubernetes, Envoy, Terraform, HTTP APIs, SQL databases, Plain functions, Kafka, and extra.

On this article, we focus on Gatekeeper,  a Kubernetes admission controller that evaluates OPA insurance policies primarily based on Kubernetes customized useful resource definitions (CRD).

Gatekeeper parts

Gatekeeper consists of three major parts:

  1. The controller, accountable for creating Constraint customized assets.
  2. The auditor, which scans the cluster and detects coverage violations.
  3. The validating webhook, which is accountable for denying requests that violate insurance policies.

Gatekeeper additionally has a CLI known as Gator that may assist with testing constraints and constraint templates domestically. 

The coverage library

You’ll be able to outline your individual insurance policies, however Gatekeeper already comes with a considerable library of insurance policies. The library has a big part of normal insurance policies that cowl many subjects. Some examples embrace:

One of many causes Kubernetes deprecated its authentic PodSecurityPolicy is that the similar impact could be achieved by Gatekeeper constraints from the coverage library.

Gatekeeper constraint templates

A constraint template is a CRD that defines the schema and the definition of the constraint within the Rego language. The template could be custom-made by an administrator to create concrete constraints to be enforced later.

Here’s a snippet from the requiredprobes constraint template:

apiVersion: templates.gatekeeper.sh/v1beta1
variety: ConstraintTemplate
metadata:
  identify: k8srequiredprobes
  annotations:
    description: Requires Pods to have readiness and/or liveness probes.
spec:
  crd:
    spec:
      names:
        variety: K8sRequiredProbes
      validation:
        openAPIV3Schema:
          sort: object
          properties:
            probes:
              description: "An inventory of probes which can be required (ex: `readinessProbe`)"
              sort: array
              objects:
                sort: string
            probeTypes:
              description: "The probe should outline a discipline listed in `probeType` in an effort to fulfill the constraint (ex. `tcpSocket` satisfies `['tcpSocket', 'exec']`)"
              sort: array
              objects:
                sort: string

Gatekeeper constraints

As soon as a constraint template is put in on the cluster, you may outline constraints that use the templates. Gatekeeper enforces insurance policies specified by constraints.

That is an instance of a constraint primarily based on the requiredprobes template:

apiVersion: constraints.gatekeeper.sh/v1beta1
variety: K8sRequiredProbes
metadata:
  identify: must-have-probes
spec:
  match:
    varieties:
      - apiGroups: [""]
        varieties: ["Pod"]
  parameters:
    probes: ["readinessProbe", "livenessProbe"]
    probeTypes: ["tcpSocket", "httpGet", "exec"]

This constraint requires each pod to have readiness and liveness probes of the desired probe varieties.

Rego: the declarative coverage language

The Rego language used to outline the coverage builds on high of a question language known as Datalog, extending Datalog to assist structured paperwork. Rego may be very highly effective, and its declarative nature makes it an ideal match for coverage administration. Right here is an instance from the requiredprobes constraint template:

targets:
    - goal: admission.k8s.gatekeeper.sh
      rego: |
        package deal k8srequiredprobes
        probe_type_set = probe_types {
          probe_types :=  sort := enter.parameters.probeTypes[_]
        }
        violation[{"msg": msg}] {
          container := enter.overview.object.spec.containers[_]
          probe := enter.parameters.probes[_]
          probe_is_missing(container, probe)
          msg := get_violation_message(container, enter.overview, probe)
        }
        probe_is_missing(ctr, probe) = true {
          not ctr[probe]
        }
        probe_is_missing(ctr, probe) = true {
          probe_field_empty(ctr, probe)
        }
        probe_field_empty(ctr, probe) = true {
          probe_fields :=  ctr[probe][field]
          diff_fields := probe_type_set - probe_fields
          depend(diff_fields) == depend(probe_type_set)
        }
        get_violation_message(container, overview, probe) = msg {
          msg := sprintf("Container <%v> in your <%v> <%v> has no <%v>", [container.name, review.kind.kind, review.object.metadata.name, probe])
        }

OPA/Gatekeeper is just not the one sport on the town. There are different Kubernetes-specific coverage engines with shallower studying curves: 

Kyverno is a Kubernetes-native coverage engine. Insurance policies are outlined as YAML utilizing Kubernetes CRDs. There isn’t a particular language like Rego. Kyverno has insurance policies to generate configuration, mutate present assets, and validate assets.

Ok-Rail is one other open-source coverage engine. It’s also Kubernetes-specific and comes with many built-in insurance policies. New insurance policies are outlined in Go and have to be added to the engine.

Coverage as code is a vital finest observe for giant programs. Kubernetes is the go-to platform for giant distributed programs. There are a number of stable options for coverage as code on Kubernetes. OPA/Gatekeeper has a robust coverage definition language. Kyverno and Ok-Rail are Kubernetes-specific and could also be easier to make use of. Consider your wants and select the fitting answer in your use case.


We’d love to listen to what you assume. Ask a query or go away a remark under.
And keep related with Cisco DevNet on social!

LinkedIn | Twitter @CiscoDevNet | Fb Developer Video Channel

Share:



Leave a Reply

Your email address will not be published. Required fields are marked *