Introduction

This series of blog posts is all about OPA policies to have a secure CI/CD and pods configuration. We’ll be looking at the various policies and why we’ll be needing it in our organizations. Open Policy Agent (OPA) is a policy engine that is used to implement policies and gain finer access control over our application. Each post will talk about a single use case and the Rego policy used. In this we’ll take a look at the policy deny unauthorized host paths.

Why do we need this policy?

We want to restrict pods from accessing unauthorized paths. This is very important in scenarios where our application gets compromised. This policy prevents the attackers from accessing sensitive files from the compromised pod.

Deny Unauthorized Host Paths

First, we have to make sure that the OPA Gatekeeper is set as the admission controller. This can be easily done by using the following command

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.1/deploy/gatekeeper.yaml

Once done, we can start creating and applying the policies. We need two yaml files to implement an OPA policy. One is the ConstraintTemplate file and the other one is the constraint file. The constraint template contains the rego policy along with information regarding the type of parameters that will be used. The constraint file has the “kind” to which this policy affects (example: Pod or Service) and the parameter values that we’ll provide.

template.yaml

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdenypath
  annotations:
    description: Prohibits unauthorized host paths.
spec:
  crd:
    spec:
      names:
        kind: K8sDenyPath
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            paths:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sdenypath

        violation[{"msg": msg, "details": {}}] {

        input.review.object.kind == "Pod"
        allowedpaths := input.parameters.paths
        hostpath := input.review.object.spec.volumes[_].hostPath.path
        not contains(allowedpaths,hostpath)
        msg := sprintf("%v not in allowed paths,[hostpath])
        }

        contains(allowedpaths,hostpaths) {
        hostpath == allowedpaths[_]
        }


Before explaining the rego policy, we’ll see what can be changed in our template and what should always remain the same.

These can change:

  • metadata 
  • spec.crd.spec.names.kind
  • validation.openAPIV3Schema.properties
  • targets.rego

The validation section can be skipped if our policy does not use any parameters. We’ll look into this in another use case where parameters are not needed.

Apart from the ones mentioned above, pretty much everything should remain the same.

If we look at our template, we figure out that a parameter, an array of strings, called “paths” is used. The value for this parameter will be passed in the constraint file.

Rego Policy explained:

violation[{"msg": msg, "details": {}}] {
  input.review.object.kind == "Pod"
  allowedpaths := input.parameters.paths
  hostpath := input.review.object.spec.volumes[_].hostPath.path
  not contains(allowedpaths,hostpath)
  msg := sprintf("%v not in allowed paths,[hostpath])
}

contains(allowedpaths,hostpaths) {
  hostpath == allowedpaths[_]
}
  1. We can now apply the template using kubectl.We check if it’s a pod as this policy is to restrict pods.
  2. We get the parameters and store it in the variable “allowedpaths”.
  3. Then, we store the “hostPath” used by the pod in the variable “hostpath”
  4. Our goal is to deny access if the hostpath used by the pod is not there in the allowedpaths list. So we call “contains” which checks if the hostpath is present in allowed paths and returns true. We use “not” so that it’ll return true if the hostpath is not in the allowedpaths.
  5. At last, our message gets displayed if everything returns true.

kubectl apply -f template.yaml

constraint.yaml

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyPath
metadata:
name: psp-host-network-ports
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
paths: ["/tmp", "/etc", "/usr"]

As told above, the constraint contains the values for the parameter. In our case, it’s the list of paths the pod is authorized to access. 

We can apply the constraint after we have applied the template.

kubectl apply -f constraint.yaml

Once the template and the constraint have been applied, our policy is in place.

deployment-non-violation.yaml

apiVersion: v1
kind: Pod
metadata:
  name: test-root-mount-pod
spec:
  containers:
  - image: nginx
    name: test-container
    volumeMounts:
    - mountPath: "/host-volume"
      name: host-volume
  volumes:
  - name: host-volume
    hostPath:
      path: "/tmp"

This will get created without any issues as the hostPath is allowed to be accessed by the pod.

deployment-violation.yaml

apiVersion: v1
kind: Pod
metadata:
  name: test-root-mount-pod
spec:
  containers:
  - image: nginx
    name: test-container
    volumeMounts:
    - mountPath: "/host-volume"
      name: host-volume
  volumes:
  - name: host-volume
    hostPath:
      path: "/root"

This will get denied as the pod is trying to access “/root” which is not allowed.

Conclusion

To sum things up, we have used OPA gatekeeper as our admission controller to restrict access to various resources. We have implemented a policy that restricts a pod’s access to certain files. We look into more use cases in the upcoming blog posts. These policies are not confined to the few use cases we’ll be touching upon in our blog posts. It’s up to us to get creative and write rego policies for our specific use cases and implement it through OPA gatekeeper.

Other related articles:

Practice here:

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

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: