Skip to content

Part 2: Policy

What Will You Do

In this part of the self-paced exercise, you will create and enforce a "policy" comprised of two OPA Gatekeeper contraints. Ensure that

  1. Container resource limits to requests does not surpass a specified ratio
  2. Only container images from authorized/approved repositories are allowed to operate on clusters

OPA Constraint Framework

Gatekeeper uses the OPA Constraint Framework to describe and enforce policy. Look there for more detailed information on their semantics and advanced usage.

Constraint

A constraint is a declaration that its author wants a system to meet a given set of requirements. Each Constraint is written with Rego, a declarative query language used by OPA to enumerate instances of data that violate the expected state of the system. All Constraints are evaluated as a Logical AND. If one Constraint is not satisfied, then the whole request is rejected.

In the example below, the constraint requires users to specify labels for k8s namespaces.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-label-owner
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["owner"]

Constraint Template

Before defining a Constraint, you need to create a Constraint Template that allows people to declare new Constraints. Each template describes both the Rego logic that enforces the Constraint and the schema for the Constraint, which includes the schema of the CRD and the parameters that can be passed into a Constraint, much like arguments to a function.

Example:

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
        listKind: K8sRequiredLabelsList
        plural: k8srequiredlabels
        singular: k8srequiredlabels
      validation:
        # Schema for the `parameters` field
        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])
        }

Step 1: Create Constraint Templates

In this step, we will create two "custom" constraint templates. The constraint templates will control the allowed repositories where images can be obtained from and sets the maximum ratio for container resource limits to requests.

  • Open Terminal (on macOS/Linux) or Command Prompt (Windows) and navigate to the folder where you forked the Git repository
  • Navigate to the folder "/getstarted/opa_gatekeeper/constraint_templates"

The "constraint-template-1.yaml" and "constraint-template-2.yaml" files contain the declarative specifications for our two constraint templates. These specification files point to the constraint template definitions located in the "rafay-gatekeeper-allowedrepos-constraint-template.yaml" and "rafay-request-limit-ratio-constraint-template.yaml" files.

The below YAML shows the declarative specification details found in the "constraint-template-1.yaml" file.

Important

Ensure you update the "project: defaultproject" with the name of the project in your Org

apiVersion: opa.k8smgmt.io/v3
kind: OPAConstraintTemplate
metadata:
  labels:
    rafay.dev/opa: template
  name: rafay-gatekeeper-allowedrepos-constraint-template
  project: defaultproject
spec:
  artifact:
    artifact:
      paths:
      - name: file://rafay-gatekeeper-allowedrepos-constraint-template.yaml
    options: {}
    type: Yaml

The below YAML shows the constraint template definition found in the "rafay-gatekeeper-allowedrepos-constraint-template.yaml" file

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: opak8sallowedrepos
  annotations:
    description: Requires container images to begin with a repo string from a specified
      list.
spec:
  crd:
    spec:
      names:
        kind: OPAK8sAllowedRepos
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            repos:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sallowedrepos

        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          satisfied := [good | repo = input.parameters.repos[_] ; good = re_match(repo, container.image)]
          not any(satisfied)
          msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
        }

        violation[{"msg": msg}] {
          container := input.review.object.spec.initContainers[_]
          satisfied := [good | repo = input.parameters.repos[_] ; good = re_match(repo, container.image)]
          not any(satisfied)
          msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
        }
  • Type the commands below to create the constraint templates
rctl create opaconstrainttemplate -f constraint-template-1.yaml
rctl create opaconstrainttemplate -f constraint-template-2.yaml

If you did not encounter any errors, you can optionally verify if everything was created correctly on the controller.

  • Navigate to the "defaultproject" project in your Org
  • Select OPA Gatekepper -> Constraint Templates

Constraint Templates


Step 2: Create Constraints

In this step, we will create two constraints that are assocaited with the previously created constraint templates.

  • Open Terminal (on macOS/Linux) or Command Prompt (Windows) and navigate to the folder where you forked the Git repository
  • Navigate to the folder "/getstarted/opa_gatekeeper/constraints"

The "constraint-1.yaml" and "constraint-2.yaml" files contain the declarative specification for our two constraints. These specification files point to the constraint definitions located in the "rafay-gatekeeper-allowedrepos-constraint.yaml" and "rafay-request-limit-ratio-constraint.yaml" files.

The below YAML shows the declarative specification details found in the "constraint-1.yaml" file

Important

Ensure you update the "project: defaultproject" with the name of the project in your Org

apiVersion: opa.k8smgmt.io/v3
kind: OPAConstraint
metadata:
  labels:
    rafay.dev/opa: constraint
  name: rafay-gatekeeper-allowedrepos-constraint
  project: defaultproject
spec:
  artifact:
    artifact:
      paths:
      - name: file://rafay-gatekeeper-allowedrepos-constraint.yaml
    options: {}
    type: Yaml
  templateName: rafay-gatekeeper-allowedrepos-constraint-template

The below YAML shows the constraint template definition found in the "rafay-gatekeeper-allowedrepos-constraint.yaml" file

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: OPAK8sAllowedRepos
metadata:
  name: opa-allowed-repos
spec:
  enforcementAction: deny
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    repos:
      - "amazonaws.com" # ECR registry for EKS cluster
      - "k8s.gcr.io" # Kubernetes registry
      - "docker.io" # bitnami registry
  • Type the commands below to create the constraints
rctl create opaconstraint -f constraint-1.yaml
rctl create opaconstraint -f constraint-2.yaml

If you did not encounter any errors, you can optionally verify if everything was created correctly on the controller.

  • Navigate to the "defaultproject" project in your Org
  • Select OPA Gatekepper -> Constraints

Constraints


Step 3: Create Policy

In this step, we will create a policy which will assemble together multiple constraints that were created in the prior steps.

  • Open Terminal (on macOS/Linux) or Command Prompt (Windows) and navigate to the folder where you forked the Git repository
  • Navigate to the folder "/getstarted/opa_gatekeeper/policy"

The "policy.yaml" file contains the declarative specification for the policy. This specification file refers to the previously created constraints as part of the defintition of the policy.

The below YAML shows the declarative specification details found in the "policy.yaml" file

Important

Ensure you update the "project: defaultproject" with the name of the project in your Org

apiVersion: opa.k8smgmt.io/v3
kind: OPAPolicy
metadata:
  name: opa-gs-policy
  project: defaultproject
spec:
  constraintList:
  - name: rafay-request-limit-ratio-constraint
  - name: rafay-gatekeeper-allowedrepos-constraint
  excludedNamespaces:
  - namespaces:
    - name: namespace-1
    processes:
    - '*'
  installationParams:
    auditFromCache: false
    auditInterval: 60
    auditMatchKindOnly: false
    constraintViolationsLimit: 20
    enableDeleteOperations: false
  sharing:
    enabled: true
    projects:
    - name: defaultproject
  syncObjects:
  - group: extentions
    kind: Pod
    version: v1
  version: opa-gs-policy-version
  • Type the command below to create the policy
rctl create opapolicy -f policy.yaml

If you did not encounter any errors, you can optionally verify if everything was created correctly on the controller.

  • Navigate to the "defaultproject" project in your Org
  • Select OPA Gatekepper -> Policies

Policy


Recap

Congratulations! At this point, you have successfully created a policy with two custom constraints. In the next step, you will add this policy to a cluster blueprint and deploy it on a fleet of managed clusters.