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:
- Check if the kind is “Pod”
- Store the image’s name in the “image” variable.
- 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.
- “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.
- 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:
- OPA Gatekeeper Audit and Logging using EFK
- A Series of Blog Posts on using OPA Policies & Gatekeeper for Kubernetes Security
Practice here:
https://www.katacoda.com/cloudsecops/courses/opagatekeeper-policy/trustedrepos
References:
- https://github.com/open-policy-agent/gatekeeper
- https://github.com/open-policy-agent/gatekeeper-library
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