apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdepsecuritycontext
spec:
  crd:
    spec:
      names:
        kind: K8sDepSecurityContext
        listKind: K8sDepSecurityContextList
        plural: k8sdepsecuritycontext
        singular: k8sdepsecuritycontext
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            allowedOps:
              type: array
              items:
                type: string
            errMsg:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      libs: 
        - |
          package lib.k8s.helpers

          allowed_operations = value {
            value := {"CREATE", "UPDATE"}
          }

          review_operation = value {
            value := input.review.operation
          }

          review_metadata_labels = value {
            value := input.review.object.metadata.labels
          }

          review_spec_template_metadata_labels = value {
            value := input.review.object.spec.template.metadata.labels
          }

          deployment_error = value {
            value := "DEPLOYMENT_INVALID"
          }

          deployment_containers = value {
            value := input.review.object.spec.template.spec.containers
          }

          deployment_role = value {
            value := input.review.object.spec.template.metadata.annotations["iam.amazonaws.com/role"]
          }

          # readonly_filesystem = value {
          #   container := deployment_containers[_]
          #   x := container.
          # }

          review_id = value {
            value := sprintf("%v/%v/%v", [
              review_namespace,
              review_name,
              review_kind
            ])
          }

          review_name = value {
            value := input.review.object.metadata.name
          }

          else = value {
            value := "NOT_FOUND"
          }

          review_namespace = value {
            value := input.review.object.metadata.namespace
          }

          else = value {
            value := "NOT_FOUND"
          }

          review_kind = value {
            value := input.review.kind.kind
          }

          else = value {
            value := "NOT_FOUND"
          }
      rego: |
        package k8sdepsecuritycontext

        import data.lib.k8s.helpers as helpers

        violation[{"msg": msg, "details": {}}] {
          helpers.review_operation = input.parameters.allowedOps[_]
          container = helpers.deployment_containers[_]
          not container.securityContext
          msg := sprintf("%v: Valid securityContext element not found. Resource ID (ns/name/kind): %v", [input.parameters.errMsg,helpers.review_id])
        }

        violation[{"msg": msg, "details": {}}] {
          helpers.review_operation = input.parameters.allowedOps[_]
          container = helpers.deployment_containers[_]
          container.securityContext.privileged
          msg := sprintf("%v: securityContext is privileged. Resource ID (ns/name/kind): %v", [input.parameters.errMsg,helpers.review_id])
        }

        violation[{"msg": msg, "details": {}}] {
          helpers.review_operation = input.parameters.allowedOps[_]
          container = helpers.deployment_containers[_]
          container.securityContext.allowPrivilegeEscalation
          msg := sprintf("%v: securityContext allows privilege escalation. Resource ID (ns/name/kind): %v", [input.parameters.errMsg,helpers.review_id])
        }

        violation[{"msg": msg, "details": {}}] {
          helpers.review_operation = input.parameters.allowedOps[_]
          container = helpers.deployment_containers[_]
          not container.securityContext.runAsUser
          msg := sprintf("%v: securityContext does not contain runAsUser element. Resource ID (ns/name/kind): %v", [input.parameters.errMsg,helpers.review_id])
        }

        violation[{"msg": msg, "details": {}}] {
          helpers.review_operation = input.parameters.allowedOps[_]
          container = helpers.deployment_containers[_]
          not container.securityContext.runAsUser > 0
          msg := sprintf("%v: securityContext is set to run as UID 0. Resource ID (ns/name/kind): %v", [input.parameters.errMsg,helpers.review_id])
        }

        violation[{"msg": msg, "details": {}}] {
          helpers.review_operation = input.parameters.allowedOps[_]
          container = helpers.deployment_containers[_]
          not container.securityContext.readOnlyRootFilesystem
          msg := sprintf("%v: securityContext does not have a readonly root filesystem. Resource ID (ns/name/kind): %v", [input.parameters.errMsg,helpers.review_id])
        }

        # violation[{"msg": msg, "details": {}}] {
        #   helpers.review_operation = input.parameters.allowedOps[_]
        #   container = helpers.deployment_containers[_]
        #   container.securityContext.readOnlyRootFilesystem == false
        #   msg := sprintf("%v: securityContext does not have a readonly root filesystem. Resource ID (ns/name/kind): %v", [input.parameters.errMsg,helpers.review_id])
        # }
