All pages
Powered by GitBook
1 of 1

Loading...

Ruleset Policies

Published: April 29, 2024

What are Ruleset Policies

Ruleset Policies are a way of defining a set of allow or deny rules for a given scope. Currently, ruleset policies are supported for the following scope(s):

  • Kubernetes Clusters

Ruleset Policies, themselves are very simple. They define a scope with a selector, and they contain a list of pointers to reusable rulesets. And they also define a set of response actions when deviations occur.

The Rulesets used by a Ruleset Policy are policy-agnostic and as such can be defined once and used across multiple policies. Rulesets contain a set of allow or deny rules. Each rule contains a target, verb, list of values, and optional selectors (for additional scoping).

  • Target: what the rule is referring to within the scope of the policy.

    • ex. container::image this means that we are allowing or denying containers using images specified in the values field.

  • Verb: The currently available verbs for ruleset rules are allow or deny. Any object matching a deny rule will generate a Deviation.

The following is an example rule that allows containers with the images docker.io/guyduchatelet/spyderbat-demo:1 and docker.io/library/mongo:latest in the namespaces rsvp-svc-dev and rsvp-svc-prod.

The following rule denies the image docker.io/guyduchatelet/spyderbat-demo:2 globally.

The following is an example ruleset automatically generated from a demo cluster:

How rules are evaluated

Rules are evaluated based on a specific hierarchy. Scoped rules take precedence over global rules, explicit rules take precedence over wildcarded rules, deny rules are evaluated first, and anything that matches no rules is denied by default.

Evaluation Order

  1. Scoped explicit deny

  2. Scoped explicit allow

  3. Scoped wildcarded deny

  4. Scoped wildcarded allow

Examples

Scenario 1 (Global Explicit Allow):

Image: docker.io/guyduchatelet/spyderbat-demo:1

A container with the image docker.io/guyduchatelet/spyderbat-demo:1 would be allowed globally.

Scenario 2 (Default Deny)

Image: docker.io/guyduchatelet/spyderbat-demo:bad-tag

A container with the image docker.io/guyduchatelet/spyderbat-demo:bad-tag would be denied by default.

Scenario 3 (Global Explicit Allow with Global Wildcard Deny):

Image 1: docker.io/guyduchatelet/spyderbat-demo:1 Image 2: docker.io/guyduchatelet/spyderbat-demo:bad-tag

Global explicit allow is evaluated before global wildcarded deny so Image 1 is allowed. Image 2 is denied by the global wildcarded deny.

Scenario 3 (Scoped Wildcarded Allow with Global Explicit Deny):

Image 1: docker.io/guyduchatelet/spyderbat-demo:1 Namespace labels: {kubernetes.io/metadata.name: rsvp-demo-prod} Image 2: docker.io/guyduchatelet/spyderbat-demo:bad-tag Namespace labels: {kubernetes.io/metadata.name: rsvp-demo-prod} Image 3: docker.io/guyduchatelet/spyderbat-demo:bad-tag Namespace labels: {kubernetes.io/metadata.name: rsvp-demo-dev}

Since the first rule has a namespace selector, that rule is scoped. Scoped wildcarded allow rules are evaluated before global explicit deny rules so Image 1 and Image 2 are allowed. Image 3 is denied by the global explicit deny rule.

Scenario 4 (Scoped Explicit Allow with Scoped Wildcarded Deny)

Image 1: docker.io/guyduchatelet/spyderbat-demo:1 Namespace labels: {kubernetes.io/metadata.name: rsvp-demo-prod} Image 2: docker.io/guyduchatelet/spyderbat-demo:bad-tag Namespace labels: {kubernetes.io/metadata.name: rsvp-demo-prod} Image 3: docker.io/guyduchatelet/spyderbat-demo:bad-tag Namespace labels: {kubernetes.io/metadata.name: rsvp-demo-dev}

Both rules are scoped because they have a namespace selector. Scoped explicit allow rules are evaluated before scoped wildcarded deny rules so Image 1 is allowed. Image 2 is denied by the scope wildcarded deny rule. Image 3 does not match the scope of any rule so it is denied by default.

Scenario 5 (Scoped Explicit Allow with Scoped Explicit Deny)

Image: docker.io/guyduchatelet/spyderbat-demo:1 Namespace labels: {kubernetes.io/metadata.name: rsvp-demo-prod}

Scoped explicit deny rules are evaluated before scope explicit allow rules, so the image is denied by scoped explicit allow.

Quick Start Tutorial

To quickly get started using using Cluster Ruleset Policies follow our tutorial using spyctl.

Values: This is the set of values that are allowed or denied. If the target is container::image then the values should be container images that are either allowed or denied.

  • Selectors: Optional selectors that further define the scope of a single rule. For instance you may want a rule that defines allowed activity in a specific namespace within a cluster.

  • Global explicit deny
  • Global explicit allow

  • Global wildcarded deny

  • Global wildcarded allow

  • Default deny

  • *Scoped

    the rule contains a selector

    *Explicit

    the matched value contains no wildcard characters

    *Wildcarded

    the matched value contains a wildcard character *

    How to Put Guardrails Around Your K8s Cluster
    apiVersion: spyderbat/v1
    kind: SpyderbatPolicy
    metadata:
      createdBy: [email protected]
      creationTimestamp: 1712787973
      lastUpdatedBy: [email protected]
      lastUpdatedTimestamp: 1714417836
      name: demo-cluster-policy
      selectorHash: 66e45259eba6ed4365e28e7e673a18cf
      type: cluster
      uid: pol:xxxxxxxxxxxxxxxxxxxx
      version: 1
    spec:
      clusterSelector:
        matchFields:
          name: demo-cluster
      enabled: true
      mode: audit
      rulesets:
      - demo-cluster-ruleset
      response:
        default:
        - makeRedFlag:
            severity: high
        actions: []
    namespaceSelector:
      matchExpressions:
      - {key: kubernetes.io/metadata.name, operator: In, values: [rsvp-svc-dev, rsvp-svc-prod]}
    target: container::image
    values:
    - docker.io/guyduchatelet/spyderbat-demo:1
    - docker.io/library/mongo:latest
    verb: allow
    target: container::image
    values:
    - docker.io/guyduchatelet/spyderbat-demo:2
    verb: deny
    apiVersion: spyderbat/v1
    kind: SpyderbatRuleset
    metadata:
      createdBy: [email protected]
      creationTimestamp: 1712787972
      lastUpdatedBy: [email protected]
      lastUpdatedTimestamp: 1714162618
      name: demo-cluster-ruleset
      type: cluster
      uid: rs:xxxxxxxxxxxxxxxxxxxx
      version: 1
    spec:
      rules:
      - namespaceSelector:
          matchExpressions:
          - {key: kubernetes.io/metadata.name, operator: In, values: [rsvp-svc-dev, rsvp-svc-prod]}
        target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:1
        - docker.io/library/mongo:latest
        verb: allow
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: kube-system
        target: container::image
        values:
        - 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni-init:v1.10.1-eksbuild.1
        - 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.10.1-eksbuild.1
        - 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/coredns:v1.8.7-eksbuild.1
        - 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/kube-proxy:v1.22.6-eksbuild.1
        - public.ecr.aws/aws-secrets-manager/secrets-store-csi-driver-provider-aws:1.0.r2-58-g4ddce6a-2024.01.31.21.42
        - registry.k8s.io/csi-secrets-store/driver:v1.4.2
        - registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.10.0
        - registry.k8s.io/sig-storage/livenessprobe:v2.12.0
        verb: allow
      - target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:2
        verb: deny
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: prometheus
        target: container::image
        values:
        - quay.io/prometheus/node-exporter:v1.7.0
        - quay.io/prometheus/pushgateway:v1.7.0
        - registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.10.1
        verb: allow
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: spyderbat
        target: container::image
        values:
        - public.ecr.aws/a6j2k0g1/aws-agent:latest
        - public.ecr.aws/a6j2k0g1/nano-agent:latest
        verb: allow
    spec:
      rules:
      - target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:1
        verb: allow
    spec:
      rules:
      - target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:1
        verb: allow
    spec:
      rules:
      - target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:1
        verb: allow
      - target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:*
        verb: deny
    spec:
      rules:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: rsvp-demo-prod
        target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:*
        verb: allow
      - target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:bad-tag
        verb: deny
    spec:
      rules:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: rsvp-demo-prod
        target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:1
        verb: allow
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: rsvp-demo-prod
        target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:*
        verb: deny
    spec:
      rules:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: rsvp-demo-prod
        target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:1
        verb: allow
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: rsvp-demo-prod
        target: container::image
        values:
        - docker.io/guyduchatelet/spyderbat-demo:1
        verb: deny