Skip to main content

Writing Policies & Policy Logic

Writing policies for jsPolicy generally means that you need to define two things:

  1. Policy Settings: JsPolicy specifies the type of policy and defines when this policy should apply
  2. Policy Logic: Put the logic into the spec.javascript of a JsPolicy or use a separate JsPolicyBundle that contains the policy logic in the form of base64 encoded, compressed JavaScript code

Configure Policy Settings#

The settings of a policy are store inside the JsPolicy custom resource and has three types of options:

Policy Type#

The type of the policy tells jsPolicy what the policy is supposed to do:

Learn more about the different Policy Types

The policy type is defined via spec.type and Validating is the default value and may be omitted.

apiVersion: policy.jspolicy.com/v1beta1
kind: JsPolicy
metadata:
name: "policy-name.company.tld"
spec:
type: Validating # other options: Mutating | Controller

Policy Trigger#

Since you do not want all your policies to be executed every time for all interactions with all the objects in your Kubernetes cluster, you can limit for which objects a particular policy should trigger.

The following options may be configured to specify when a particular policy should be triggered:

  • operations: An array of strings containing Kubernetes CRUD operations, i.e. any combination of CREATE, UPDATE, DELETE
  • resources: An array of strings stating Kubernetes resources, e.g. pods, deployments, services etc.
  • scope: A string stating if the operation is Namespaced or Cluster-wide (default value: * (means Namespaced || Cluster))
  • namespaceSelector: A Kubernetes namespace selector which defines that a policy should only trigger for operations in namespaces with specific attributes (e.g. only namespaces with certain labels)
  • objectSelector: A Kubernetes object selector which defines that a policy should only trigger for objects with specific attributes (e.g. only objects with certain labels)
  • matchPolicy: A string stating the Kubernetes match policy which tells Kubernetes how fuzzy the objectSelector shall be applied (either Exact or Equivalent(default))
  • apiGroups: An array of strings stating Kubernetes API groups (default: * matching any API group)
  • apiVersions: An array of strings stating Kubernetes API versions (default: * matching any API version)
apiVersion: policy.jspolicy.com/v1beta1
kind: JsPolicy
metadata:
name: "mutate-images.company.tld"
spec:
type: Mutating
operations: ["CREATE", "UPDATE"]
resources: ["pods", "deployments"]
scope: Namespaced
namespaceSelector:
matchExpressions: # only trigger for namespaces with label "environment: prod" and/or label "environment: staging"
- key: environment
operator: In
values: ["prod","staging"]
objectSelector: # all trigger for objects with label "live: true"
matchLabels:
live: "true"
matchPolicy: "Equivalent"
apiGroups: ["*"]
apiVersions: ["*"]
# Optional javascript here
# javascript: if ...

Runtime Settings#

Within the spec of a JsPolicy object, you can also define certain settings that are relevant during the execution of a policy:

  • violationPolicy: deny (default) or warn (for testing) when the policy logic calls the deny() function
  • failurePolicy: Fail (default) or Ignore when jsPolicy fails to execute the policy or it aborts with a runtime error
  • auditPolicy: Log (default) or Skip logging any policy violations (requests that lead to deny()) in the status of this policy
  • auditLogSize: Maximum number of violations that should be stored in the status of this policy (default: 10 violations)
  • timeoutSeconds: Maximum number of seconds that the execution of the policy logic may take before jsPolicy aborts the policy execution (default: 10 seconds, maximum is 30)
apiVersion: policy.jspolicy.com/v1beta1
kind: JsPolicy
metadata:
name: "validate-images.company.tld"
spec:
operations: ["CREATE", "UPDATE"]
resources: ["pods", "deployments"]
violationPolicy: warn
failurePolicy: Ignore
auditPolicy: Skip
timeoutSeconds: 30

Write Policy Logic#

There are different ways to write policy logic for JsPolicy. The following table compares three common workflows:

Embedded spec.javascriptSeparate JavaScriptTypeScript
LanguageJavaScriptJavaScriptTypeScript (modern)
Type Safetynonoyes
IDE Supportbad (JavaScript in YAML)goodgreat (auto-completion, warnings, types)
Testingonly end-to-end via test kubectl requestsunit, functional and end-to-end testsunit, functional and end-to-end tests
Publishingonly via JsPolicy YAML filesvia npm packagesvia npm packages
JsBundle Generationautomatic by JsPolicymanual or via dev tools (SDK)manual or via dev tools (SDK)
SDK-JsPolicy SDKJsPolicy SDK

Embdedded spec.javascript#

The most trivial option to write policy code in JsPolicy is to embed JavaScript ES5 (vanilla JS) code into the JsPolicy object:

apiVersion: policy.jspolicy.com/v1beta1
kind: JsPolicy
metadata:
name: "deny-default-namespace.company.tld"
spec:
operations: ["CREATE"]
resources: ["*"]
scope: Namespaced
javascript: |
if (request.namespace === "default") {
deny("Creation of resources within the default namespace is not allowed!");
}

spec.dependencies#

With this option you can define dependencies that you want to load for this policy. You can specify any CommonJS package from the npm registry here or import your own packages.

Separate JavaScript#

You can use a separate JavaScript project to build, test and deploy your policies. Any language that can get cross-compiled to Javascript is supported. Take a look at our TypeScript example to see how to cross compile TypeScript to JavaScript and use this in a JsPolicy.

TypeScript#

Please take a look at our Policy SDK or TypeScript example on how to write policies in typescript.