Introduction

This post is about the policy that we’ll use to restrict the use of images only from trusted repositories and the reason to require trusted image repos in an organization.

Why do we need this policy?

One reason to use an image from a trusted repository is because all the images in our repository will be scanned for known vulnerabilities and will be hardened. Another reason to impose this restriction is to prevent attackers from replacing our images with malicious images from their own repositories.

Require Trusted Image Repositories

template.yaml

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sallowedrepos
  annotations:
    description: Requires container images to begin with a repo string from a specified list.
spec:
  crd:
    spec:
      names:
        kind: K8sAllowedRepos
      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}] {
          input.review.spec.kind == “Pod”
          image:= input.review.object.spec.containers[_].image
          satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(image, repo)]
          not any(satisfied)
          msg := sprintf("Invalid image repo: <%v>, allowed repos are %v", [image, input.parameters.repos])
        }

Rego Policy explained:

  1. Check if the kind is “Pod”
  2. Store the image’s name in the “image” variable.
  3. The names of the allowed repos from the parameter are stored in the “repo” variable. The “satisfied” variable’s value is the value of the “good” variable. Hence, the value of “satisfied” will be set to true if the image’s name starts with any of the allowed repo names that is stored in the “repo” variable.
  4. “any(satisfied)” returns true if any of the  values of “satisfied” is true. So “not any(satisfied)” returns true only when all the values of “satisfied” are false.  
  5. The message gets printed if all the above returns true.

constraint.yaml

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: repo-is-openpolicyagent
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces:
      - "default"
  parameters:
    repos: ["071460744267.dkr.ecr.us-east-1.amazonaws.com/test/snyk"]

All the images from the “repos” parameter are allowed. 

deployment-non-violation.yaml

apiVersion: v1
kind: Pod
metadata:
  name: opa-allowed
spec:
  containers:
    - name: opa
      image: 071460744267.dkr.ecr.us-east-1.amazonaws.com/test/snyk:latest
      args:
        - "run"
        - "--server"
        - "--addr=localhost:8080"

We will face no issues in creating as this repo is allowed.

deployment-violation.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx-disallowed
spec:
  containers:
    - name: nginx
      image: nginx

This will be denied as the use of this repo is not allowed.

Conclusion

The key points to keep in mind:

  • Always include security scans and harden the images before pushing the images to the repository. 
  • Always accept images only from trusted image repositories.

Other related articles:

Practice here:

https://www.katacoda.com/cloudsecops/courses/opagatekeeper-policy/trustedrepos

References:

Thank you for reading! – Vishal Pranav and Setu Parimi

Sign up for the blog directly here.

Check out our professional services here.

Feedback is welcome! For professional services, fan mail, hate mail, or whatever else, contact [email protected]


0 Comments

Leave a Reply

%d bloggers like this: