Write Custom Policies

Customize Policies with Overlays

Import an existing cnspec policy and override selected checks or policy settings without copying the base policy

A policy overlay lets you adapt an existing policy without copying and maintaining the entire policy. The overlay is a small policy that:

  1. Imports a base policy.
  2. Overrides only the checks or policy settings that your organization needs to change.

All other content continues to come from the base policy. When the base policy gains new checks or documentation, the overlay inherits those updates.

Use an overlay when you need to enforce a stricter check, put a base check into preview, deactivate a check that does not apply to your environment, or use a different scoring system.

How an overlay works

An overlay uses two types of policy groups:

  • An import group adds the base policy to the overlay.
  • An override group references checks from the imported policy and supplies the values that should change.

cnspec resolves the import and overrides into one effective policy at scan time. It does not change the base policy itself.

Create an overlay

The following self-contained bundle defines a base SSH policy and an overlay for a more restrictive production environment:

policies:
  # The policy that provides the original checks.
  - uid: example-linux-baseline
    name: Example Linux baseline
    version: 1.0.0
    scoring_system: highest impact
    tags:
      mondoo.com/category: security
      mondoo.com/platform: linux
    require:
      - provider: os
    groups:
      - title: SSH configuration
        filters:
          - mql: asset.family.contains("unix")
        checks:
          - uid: sshd-max-auth-tries
          - uid: sshd-use-pam
          - uid: sshd-port

  # The policy to assign for the production environment.
  - uid: production-linux-baseline
    name: Production Linux baseline
    version: 1.0.0
    scoring_system: highest impact
    tags:
      mondoo.com/category: security
      mondoo.com/platform: linux
    require:
      - provider: os
    groups:
      # Import every check from the base policy.
      - type: import
        policies:
          - uid: example-linux-baseline

      # Change only the checks that differ in production.
      - type: override
        title: Production requirements
        filters:
          - mql: asset.family.contains("unix")
        checks:
          - uid: sshd-max-auth-tries
            title: Limit unsuccessful SSH authentication attempts
            action: modify
            mql: sshd.config.params["MaxAuthTries"] <= 3
            impact: 90

          - uid: sshd-use-pam
            action: preview

          - uid: sshd-port
            action: deactivate

queries:
  - uid: sshd-max-auth-tries
    title: Limit unsuccessful SSH authentication attempts
    mql: sshd.config.params["MaxAuthTries"] <= 4
    impact: 70

  - uid: sshd-use-pam
    title: Enable PAM for SSH
    mql: sshd.config.params["UsePAM"] == "yes"
    impact: 60

  - uid: sshd-port
    title: Use the default SSH port
    mql: sshd.config.params["Port"] == 22
    impact: 30

The effective production-linux-baseline policy:

  • Requires no more than three authentication attempts instead of four and raises the check's impact to 90.
  • Runs and reports the PAM check without including it in the score.
  • Does not run the SSH port check.
  • Inherits every other field and any future checks from example-linux-baseline.

Assign the overlay policy instead of separately maintaining a production copy of the base policy.

Choose an override action

Each overridden check or data query references the original item by uid or mrn and uses an action to describe the change. Put scored checks under checks and data queries under queries in the override group.

ActionBehavior
modifyReplaces the fields supplied in the override and inherits fields that are omitted. Use it to change MQL or impact.
previewRuns and reports the check but excludes its result from scoring.
deactivatePrevents the check from running.
activateExplicitly activates the check.

To learn about preview behavior and remediation deadlines, read Preview Checks.

You can override check fields such as mql, impact, title, documentation, filters, properties, and variants. On a policy reference in an import group, you can override action, impact, or scoring_system:

- type: import
  policies:
    - uid: example-linux-baseline
      scoring_system: banded

When an override supplies a collection such as filters, props, tags, or variants, that collection replaces the inherited value; cnspec does not append the new entries. Include every entry that the effective check still needs.

Reference policy content outside the bundle

The first example uses UIDs because the base policy, overlay, and checks are in the same bundle. When the base policy and checks already exist outside the overlay bundle, reference their full MRNs instead. Published Mondoo policies and checks use MRNs in this form:

groups:
  - type: import
    policies:
      - mrn: //policy.api.mondoo.app/policies/POLICY_UID

  - type: override
    checks:
      - mrn: //policy.api.mondoo.app/queries/CHECK_UID
        action: modify
        impact: 90

Replace POLICY_UID and CHECK_UID with the identifiers from the base policy. Content owned by your space uses the MRNs that Mondoo Platform provides for that content. You can download the policy to inspect its policy and check MRNs.

cnspec must be able to resolve every imported policy and overridden check. For local or offline linting, keep the base content and overlay in the same bundle file. For content that is already stored in Mondoo Platform, use its full MRNs.

Limit where or how long an override applies

Add asset filters to an override group to apply it only to matching assets. Add valid.until to stop applying the override after a date:

- type: override
  title: Ubuntu exception through October 2026
  filters:
    - mql: asset.platform == "ubuntu"
  valid:
    until: 2026-10-01
  checks:
    - uid: sshd-use-pam
      action: preview

Until October 1, 2026, the PAM check is in preview for Ubuntu assets. After that date, the override no longer applies and the imported check returns to its base behavior.

Validate and scan an overlay

If the base policy and overlay are in one file, lint and scan that bundle:

cnspec policy lint production-overlay.mql.yaml
cnspec scan local --policy-bundle production-overlay.mql.yaml

You can scan a directory when a bundle is split across files:

cnspec scan local --policy-bundle ./policies

cnspec policy lint validates each file independently. To lint cross-file references locally, first combine the base content and overlay into one self-contained bundle file.

Linting reports an error if an imported policy is missing or a modify action targets a check that cnspec cannot resolve.

Keep overlays maintainable

  • Keep the overlay small. Override only fields that intentionally differ from the base policy.
  • Use stable UIDs or MRNs. If an identifier changes in the base policy, update the overlay reference.
  • Avoid multiple matching overrides for the same field. Prefer one authoritative override so the effective behavior remains clear.
  • Lint and test the overlay after updating the base policy.

Next steps

On this page