Kubernetes validating admission policy

A Kubernetes validating admission policy uses CEL expressions inside the API server to accept or reject requests against cluster rules. This page explains when to use it, how policies, bindings and parameters fit together, and how to roll them out safely.

On this page

When a Kubernetes validating admission policy is the right control

A Kubernetes validating admission policy evaluates CEL expressions inside the API server against incoming requests and accepts or rejects them before they are persisted. Platform teams choose it when they need cluster rules, such as required labels, approved image registries or resource ceilings, enforced at admission time and the rule can be written as a condition on the request. The Kubernetes documentation describes it as an in-process alternative to validating admission webhooks, so no separate service has to be deployed, scaled and kept available to answer every admission call. Before you design around it, confirm the API version and feature status in the Kubernetes minor version you run, because maturity and default enablement can differ between releases. Check the release schedule and support windows on the Kubernetes releases page, since both move on a published cadence.

Choose a policy over a webhook when the decision depends only on the incoming object, the request context and parameters you supply. A rule that Deployments must carry an owner label, or that container images must come from an internal registry, fits this model. A ceiling on requested CPU or memory per workload also fits when the rule can be written against fields in the object. These rules are short, easy to review in source control and remove a network hop and a service failure mode from the admission path. A webhook remains the better fit when the decision needs data from outside the request, such as a lookup in an external inventory or signing service, or when you need the request mutated. Confirm the exact expression and data limits in the documentation for your version before you commit a rule set to it.

Pod Security Admission already enforces the Pod Security Standards (Privileged, Baseline and Restricted) per namespace, so do not rebuild those checks in a custom policy. Reserve validating admission policies for rules the built-in controller does not express, such as an organization-specific label contract or a registry allowlist. Write down which control owns each rule before you deploy. Two admission layers that enforce overlapping rules make a rejected request hard to trace back to its source, and that slows incident response for application teams.

Decide early who owns each rule and who can change it. Policies and their bindings are cluster-scoped, so an edit affects every namespace the binding matches. Restrict create and update rights on these objects with RBAC and record the approval path for changes. Inventory the existing workloads that a proposed rule would block, and plan to start in Warn or Audit mode before moving any rule to Deny. Set the review cadence against the Kubernetes minor versions you operate, so each upgrade includes a check of policy behavior and feature status for the new release.

Which policy building blocks fit each cluster rule

This table compares the building blocks of a ValidatingAdmissionPolicy, showing when each one fits and what it adds to ongoing maintenance. Read each row as a design choice covering the policy logic, where values come from, which requests it applies to and what happens when a rule is violated. The main takeaway is to start with inline expressions and Warn or Audit, then add parameters, narrower bindings and Deny once the impact of a rule is understood.

Building blockWhen it fitsMaintenance cost
Inline CEL expressionsA single rule with a fixed check, owned by one team and used in one placeLow for one policy, but every copy must be edited by hand, so drift grows with policy count
Parameter resourcesOne rule whose values differ by environment or team, such as allowed registries or label keysModerate: parameter objects need their own review, versioning and access control
Bindings by namespace or object selectorLimiting enforcement to production namespaces or exempting platform namespacesLow to moderate: selectors must be rechecked when namespaces are relabeled or renamed
validationActions: WarnEarly rollout, showing developers which submitted objects would fail the ruleLow, but warnings reach only the client that submitted the request, so teams must read them
validationActions: AuditMeasuring impact on existing workloads before any request is blockedLow to moderate: violations are recorded in the audit log, so someone must collect and review them
validationActions: DenyEnforcing a rule after violations are understood and exceptions are agreedOngoing: denied requests block deployments, so an owner must handle exceptions and emergency changes
failurePolicyDeciding whether a policy evaluation error rejects or admits the requestConfirm the supported values for your cluster version, then test how errors affect deployments

How policies, bindings and parameters fit together

A ValidatingAdmissionPolicy on its own enforces nothing. Enforcement starts when a ValidatingAdmissionPolicyBinding attaches that policy to a scope, names the parameter resource the policy reads and chooses what happens on a violation. Keeping these roles separate is the main design decision in this feature. The policy holds the logic, the binding holds placement and parameter references, and the parameter resource holds values that differ between environments. Teams that merge these into one object often copy policies per environment, which makes drift hard to see. Before writing manifests, map each rule to one policy, list the bindings that will apply it and mark which values belong in parameters.

The policy spec has four parts that matter here. matchConstraints names the API groups, versions and resources the policy inspects, such as Deployments. paramKind declares the kind of parameter resource the policy expects, if it uses one. variables define named CEL expressions that are evaluated for each request, which keeps the validations short and readable. validations are the CEL expressions themselves, each returning true for a compliant object, with a message or messageExpression that the API server returns when a check fails. A policy can also set failurePolicy, which controls how the API server treats an evaluation error. Confirm exact field names and defaults in the official API reference for your Kubernetes minor version before you write manifests.

Illustrative example: the platform team wants every Deployment in a production namespace to carry an owner label. The policy, named require-owner-label, matches apps/v1 Deployments and has one validation that checks the object for the label key stored in its parameter. That key sits in a ConfigMap named owner-label-settings in a platform namespace, with a data entry such as requiredLabel set to owner. The binding, named owner-label-production, references the policy by name, points paramRef at that ConfigMap and uses a namespace selector that matches namespaces labeled environment: production. Its validationActions start with Warn and Audit, so teams see violations in client output and audit events without blocked deployments. Changing the required label later means editing the ConfigMap, and the policy stays as it is.

Scope and ownership need deliberate attention. Both ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding are cluster-scoped objects, so one binding can affect namespaces across the whole cluster, and a flawed policy applies everywhere it is bound. Who can create, edit or delete these objects is therefore an RBAC decision, separate from who can deploy workloads. Limit write access to a small platform group, and decide whether parameter resources need their own permissions so application owners can read required values without changing them. Confirm with your identity team how these roles map to groups, and make sure changes to policies and bindings appear in your audit logs so any loosened rule can be traced.

Setting up a validating admission policy in a staged way

This sequence moves a ValidatingAdmissionPolicy from one test rule to enforcement in a single namespace, with a check at each stage. Each step produces evidence that the expression behaves as intended before it can reject a live workload. Cluster owners set the scope of each stage, and the rollback path stays in place throughout.

  1. Confirm cluster version and API availability

    Platform engineers check that the cluster runs a Kubernetes minor version that includes ValidatingAdmissionPolicy and that the admissionregistration.k8s.io API group serves the policy and binding resources. Confirm the version against the release notes for your distribution, since managed and vendor builds can differ in feature gates and defaults. Done when kubectl api-resources lists the policy and binding kinds in the non-production cluster, and the same check passes on the production cluster before any policy is applied there.

  2. Set RBAC for policy authors

    Cluster administrators create a role that lets named policy authors create and update ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding objects. Binding permissions stay with a smaller group that approves enforcement, and authors hold no cluster-wide permissions beyond these resources. Parameter resources need the same review. Check the result with kubectl auth can-i while impersonating each author account, and confirm that an attempt to create a binding outside the approved scope is denied.

  3. Write one narrow policy and binding

    Write a single policy that checks one rule, such as a required label or an allowed image registry, and scope it with matchConstraints to the resources and operations it targets. Create the binding in the non-production cluster only, starting with a namespaceSelector that matches one test namespace. Store both manifests in Git and review changes through pull requests, so every change has an author and an approver. Done when the policy is configured, the binding references it, and the repository matches the cluster.

  4. Test expressions against representative manifests

    Build a small set of manifests that should pass and manifests that should fail, drawn from the workloads the rule will touch. Include edge cases such as missing optional fields, because expressions that error on absent values are easy to miss. Submit each manifest to the test namespace with a server-side dry run and record the decision returned. Done when every passing and failing manifest produces the expected result, and the test set is saved beside the policy in version control.

  5. Bind with Warn and Audit actions

    Set validationActions to Warn and Audit on the binding so the API server returns a warning to the client and records an audit annotation without rejecting anything. Apply the binding to the test namespace first, then to the wider namespaces in scope, keeping the scope identical to the one approved in review. Done when a non-compliant test manifest is accepted with a warning and the audit record appears, which confirms the binding matches the intended resources.

  6. Review audit events and warnings

    Collect the warnings shown to developers and the audit annotations recorded for requests that violated the policy, over a window the team agrees in advance. Confirm that audit logging is enabled on the API server and that the annotations reach the place where your team reads them. Sort findings into genuine violations, which owners fix, and false positives, which go back to the expression or the match scope. Done when owners have accepted the remaining violations and every false positive has an agreed change.

  7. Move one namespace to Deny

    Add Deny to the binding's validationActions and limit the binding to one namespace whose owners have agreed to enforcement, keeping Warn and Audit so the record continues. Notify the namespace owners and name the person responsible for rollback before applying the change. Done when a non-compliant test manifest is rejected in that namespace with the expected message and a compliant manifest is admitted, which confirms both sides of the rule work on the live admission path.

  8. Widen scope with a tested rollback path

    Expand the namespaceSelector in controlled increments, reviewing warnings and audit records after each change. Rollback means removing the binding or changing its validationActions back to Warn and Audit, and the team rehearses this in the non-production cluster before relying on it. Done when the rollback has been run once in a test environment with the expected effect on admission, and each scope change is recorded in version control with an approver.

Rolling out with Warn and Audit before Deny

Teams start with Warn and Audit because they reveal which objects would fail a new rule before any request is blocked. Warn sends a message back to the client that submitted an object, so a developer running kubectl apply sees the policy's message in the response while the request still succeeds. Audit records each violation in the API server audit log, which gives owners a durable record they can query later, including for workloads nobody is changing today. In a ValidatingAdmissionPolicyBinding, the validationActions list controls this behavior. A first binding usually lists Warn and Audit and leaves Deny out, so the policy observes the cluster without changing what it accepts. Confirm the action names and their behavior against the Kubernetes version you run, since you will depend on that field's exact semantics.

Warnings and audit events answer different questions, so read them separately. Warnings fire only when an object is created or updated, which makes them a signal about change traffic: which teams still ship non-compliant manifests and through which pipelines. Audit events describe requests that reached the API server, so they are the better source for objects that already exist and for controllers that recreate pods. Audit events are only as complete as your audit policy. Confirm which resources, verbs and stages your policy records and at what level, because a policy that omits the relevant resources will show a quiet signal that means nothing. The Kubernetes audit logging topic covers writing that policy. Also confirm that events carry the policy and binding names so you can attribute each violation to a specific rule.

Existing objects are not changed when a new policy is bound, so the rollout plan needs a remediation list before Deny is considered. Build it from audit events for the policy and, to catch objects the audit window missed, from a read-only evaluation of current workloads in each namespace. For each violation, record the namespace, owning team, resource kind and name, the rule it breaks, the planned fix and who verifies it. Deployments, StatefulSets, DaemonSets and Jobs own their pods, so fix the pod template in the parent resource. A pod patched by hand will be recreated from the unchanged template on its next rollout, and the violation will return.

Notify the people who can act on each signal: application owners for namespaces with violations, the platform team that owns the policy and its bindings, security approvers who grant any exceptions, and the on-call rota for workloads likely to restart during fixes. Decide readiness per namespace, not for the whole cluster. A namespace is ready when its audit signal has stayed clean for an observation period the owners agreed in writing, every remediation item is closed or has an approved exception, and a rollback path exists that removes Deny from that binding. Set the length of the observation period against your own change process, and confirm it with your internal change owner before the window opens. Scope bindings so each namespace can move to Deny independently.

Security and operational considerations for admission rules

A validating admission policy can block every matching request in the cluster, so its risks reach beyond the policy itself. The cards cover who can change policies and bindings, how expressions can fail, where policy state lives, how the policies interact with Pod Security Admission, how parameters handle sensitive values, and how to map the rules to a recognized benchmark.

Who can change policies and bindings

Policies are cluster-scoped objects, and a binding decides where a policy takes effect. Anyone with create, update or delete rights on either object can add a check, remove one, or widen the namespaces it covers. Review which roles hold these verbs in your RBAC configuration, and confirm that a team which only owns an application namespace cannot create a binding that reaches other namespaces. Limit write access to the platform team and audit every change to these objects.

Broken or overly broad expressions

Each validation is a CEL expression, and a syntax or logic error can reject every request it matches. An expression or binding that matches more resources than intended can block system components, controllers or workloads outside the target group. Test expressions against representative objects before enforcement, roll out with the Warn and Audit actions first, and confirm that the match criteria in each binding limit scope to the namespaces you intend.

Policy objects in etcd and backups

Policies, bindings and parameter resources are stored in etcd like other API objects, so they are included in etcd snapshots. Restoring an older snapshot can bring back a previous policy set or remove a recent enforcement change, which may reopen a control you believed was active. Confirm that your etcd backup schedule covers these objects, and document how policy state is reconciled after a restore, for example from version-controlled manifests.

Interaction with Pod Security Admission

Pod Security Admission enforces the Privileged, Baseline and Restricted Pod Security Standards on each namespace. A validating policy can overlap with those levels, so a pod may be evaluated twice with different outcomes, or a custom rule may allow a configuration that a Restricted namespace forbids. Decide which mechanism owns each pod constraint, map each namespace label to one intended level, and test both mechanisms together before tightening either one.

Sensitive values in parameters

Parameter resources supply values that a policy reads, such as allowed registries or required labels. Teams may be tempted to place credentials or tokens in a Secret that a policy references. Secrets are stored unencrypted in etcd by default, so confirm that encryption at rest is configured before any sensitive value is referenced. Keep parameters to non-sensitive values where possible, and restrict read access to the parameter objects and the Secrets behind them.

CIS Benchmark as a control reference

The CIS Kubernetes Benchmark is a consensus configuration guide covering upstream Kubernetes and several managed services. Use its recommendations as a checklist for mapping your admission rules, and record which controls each rule enforces, which rules are supplementary, and which controls need another mechanism such as audit logging or network policy. Confirm that the benchmark version matches your cluster version, and review its terms of use before sharing copies internally.

When a validating webhook still makes sense

A validating webhook still makes sense when the admission decision needs something a CEL expression cannot reach or cannot express cleanly. Before choosing, confirm two things. First, the minor version your clusters run and whether the ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding APIs are served and enabled there, using the releases documentation for that version. Second, what your existing webhook actually does. Many webhooks only compare fields in the incoming object against fixed values or simple rules, and those are the easiest to move. Others do considerably more, and that difference decides the answer. Write out the list of checks each webhook performs before reading further, because that list is the basis for every other decision in this section.

CEL runs inside the API server against the admission request, the object and the old object, plus parameter resources and a limited set of variables. It has no general network access, so a rule that asks an external inventory, a licensing service, a secrets manager or a ticketing system whether a change is approved cannot be expressed as a policy. The same applies to logic that depends on state the request does not carry, such as the count of objects in another namespace at a given moment, unless you can model that state as a parameter resource that someone keeps current. Long chains of conditional logic, lookups across many objects, or rules that change often can also become hard to read and test as CEL. In these cases, a webhook that your team owns, versions and tests is the more suitable tool, provided you accept the operational cost described below.

A webhook is a service in the admission path. You run it as its own deployment, with its own TLS certificates for the API server connection and a process for rotating them. Its failure policy decides what happens when it is unreachable: fail closed blocks matching requests, and fail open admits them without the check. Both choices have consequences you should document before deployment. Its timeout adds latency to every matching API call. Its availability has to match the clusters it guards, which usually means redundant replicas, disruption budgets, careful ordering during upgrades, and excluding its own namespace from the rules it enforces to avoid deadlocks. Each of these recurs for as long as the webhook exists, and your team carries them in addition to the rule itself. Ask any partner quoting webhook work to list these recurring items separately from the build.

If the webhook's checks fit CEL, the migration usually runs in stages. Translate each rule into a ValidatingAdmissionPolicy with a binding that starts with the Warn or Audit action, so requests that would fail are reported without being rejected. Compare what the policy would have blocked with what the webhook blocked over a period your change process can support, and resolve the differences in either direction. Once they match, move the binding to Deny for the same scope, then remove the webhook's registration before removing its deployment. Keep the webhook running until the policy has been the only enforcer in every environment, since the two can disagree during the transition. Record each rule's old and new owner so no check disappears silently.

Some teams keep both. A policy handles the fixed rules, which run inside the API server, version with the cluster and need no extra service, while a narrow webhook handles the few checks that need external data. That split can be sensible, but it adds a second place to look when a request is denied, so document which mechanism owns each rule. Whatever you choose, confirm the decision against your own cluster version and the webhook's current code, not against this summary. A reviewer who can name each rule, its enforcer, its failure behavior and its owner has enough information to make the call.

Limits to confirm in your cluster before you commit

ValidatingAdmissionPolicy behavior depends on the Kubernetes minor version, the API version your cluster serves and how your control plane is provided. The checks below cover what to verify before you write policies, and each one should be confirmed against the official documentation for your exact version.

Minor version and support end date

Start by identifying the exact Kubernetes minor version your clusters run and its end-of-life date on the official releases page. The project maintains only the three most recent minor releases, so a version that is close to retirement may force an upgrade before your policy rollout is finished. Record the date next to the cluster so the upgrade plan and the policy plan are scheduled together.

API version and feature status

Confirm which admissionregistration.k8s.io API version your cluster serves for ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding, and whether the feature is enabled by default or behind a feature gate in your version. Check whether the stage is alpha, beta or stable, because manifests written for one API version may not apply to another. Verify this with kubectl api-resources and the release notes for your version.

Managed and distribution control planes

Managed services and vendor distributions decide which API groups and feature gates are exposed, and they may lag or change defaults relative to upstream. Ask your provider whether the resource is served, which version exposes it, and whether any admission features are disabled or altered. Test the exact manifests on a non-production cluster from the same provider and version before relying on them.

Expression cost and evaluation limits

CEL expressions in a policy are evaluated during every matching request, so the API server enforces cost estimates and runtime limits. Review the cost and limit rules in the documentation for your version and check how large resource lists or complex string operations behave under them. Also confirm the effect of the failure policy, since an expression that exceeds limits can block or allow requests depending on that setting.

Supported CEL functions and messages

The set of CEL functions, variables and macros available to validation expressions, and the wording of error messages, can change between Kubernetes versions. Confirm which library extensions your version provides, such as string, list and quantity helpers, and which fields are accessible in the admission request object. Write tests that assert the exact deny messages your teams will see, and update them when you change version.

Interaction with webhooks and Pod Security

Policies run alongside validating and mutating admission webhooks and the built-in Pod Security Admission controller, so a request may pass one check and fail another. Map which rules already exist in webhook configurations and namespace Pod Security labels, decide which system owns each rule, and confirm the order of evaluation in your version's admission documentation. Avoid duplicate rules that produce conflicting messages for the same request.

What validating admission policy work costs and what it needs from your team

What drives the effort of a validating admission policy project?

The effort rises with the number of rules, the number of clusters they apply to, and how much existing admission control must be reviewed. Each rule needs a CEL expression, a binding that decides where it applies, and parameters when thresholds or allowed lists vary by environment. Teams with existing validating or mutating webhooks need an inventory of what those webhooks already enforce, so overlaps and conflicts are resolved before anything blocks a deployment. Audit and RBAC design also count: who can read policy results, who can change bindings, and where Audit and Warn events are collected. The largest variable is usually testing against real workloads, because a rule that passes a sample manifest can still reject legitimate charts or operators. Ask any quote to list these drivers separately so you can see which ones your environment triggers.

Is validating admission policy work a one-time project or ongoing?

Part of it is one-time and part of it recurs. The initial build covers rule design, policy and binding manifests, test suites, the rollout from Warn and Audit to Deny, and the documentation your reviewers need. After that, policies need maintenance as your rules change, as workloads introduce new fields or resource types, and as Kubernetes minor releases change the APIs and behavior your expressions depend on. Kubernetes ships approximately three minor releases per year, so a policy set reviewed once will drift. Recurring work usually includes reviewing audit events for false positives, updating parameters when approved lists change, and retesting after each cluster upgrade. Whether that maintenance continues under a retainer or moves to your team is a scope decision. Ask the quote to separate the one-time build from recurring maintenance and to state what triggers each recurring task.

What does the work need from our team to get started?

Cluster access: credentials or a delivery path that lets the implementation team read and apply policy objects in each cluster in scope, usually starting in non-production. A rule list: written requirements owned by security or compliance, with the intent behind each rule, the resources it covers and the person who approves exceptions. Workload owners: named contacts for each application team who will fix violations and confirm when a rule is too broad. Current state: exports of existing admission webhooks, Pod Security Admission labels and API audit configuration. A change path: a way to deploy policy objects through your normal review process. Without the rule list and workload owners, the project tends to stall at the Deny step because nobody can decide what should be blocked. Confirm during scoping who on your side can make those decisions in the time you have.

Can our internal platform team build validating admission policies without outside help?

Often yes, if the team already runs Kubernetes in production, reads the API documentation comfortably, and has someone who owns security rules. The mechanics of ValidatingAdmissionPolicy are learnable: expressions, bindings and parameters are declarative objects, and Warn and Audit actions let you observe impact before blocking. The harder parts are usually deciding which rules are worth enforcing, building test workloads that reflect your actual charts and operators, coordinating exceptions across teams, and keeping the set current through upgrades. Teams that work alone often underestimate the conversations with workload owners. A useful self-check: can you name the owner of each rule, run a test suite on every change, and schedule a Deny rollout without an incident? If the answer is unclear, an outside review of the design and rollout plan can be a narrower engagement than a full build.

How do we get a fixed-scope quote for validating admission policy work?

Start with a written scope, because that scope is the basis for the quote. DeployOpen agrees scope, deliverables and timelines in writing before work starts, and most engagements are fixed-scope. To prepare the request, send the number of clusters, the Kubernetes minor versions they run, your list of rules with their owners, a summary of existing webhooks and admission configuration, and the environments that need Deny enforcement. Describe which workloads must be tested, including third-party charts and operators. State whether you want the design only, the full build and rollout, or a retainer for later maintenance. The written scope then lists what is in and out, the test approach, the handover material and the client responsibilities. DeployOpen does not publish a price list, so the quote follows from that scope. Compare quotes line by line against the same scope items.

What happens to our existing admission webhooks during the project?

They are inventoried, compared with the new policies, and then retired or kept on a planned schedule. Many clusters run validating or mutating webhooks from security tools, service meshes or internal platforms. Each one may already enforce checks that overlap with the new policies, and removing one without a replacement can open a gap. The work maps what each webhook checks, which resources it intercepts, its failure behavior and who owns it. Overlapping checks are then migrated into CEL expressions where the policy can express the same logic, or left in place where it cannot. Webhooks maintained by a vendor generally stay in place unless the owner agrees to change them. The quote should name which webhooks are in scope, and your team should confirm the vendor's support position before any change is scheduled.

How long does a safe Warn, Audit and Deny rollout take?

The duration depends on how many workloads must be observed and how quickly owners can fix violations, so no timeline is given here. Each rule should move through Warn, then Audit, then Deny. Warn shows developers the violation during apply, Audit records it in the API audit trail for review, and Deny blocks it only after false positives are cleared. The schedule should be set by evidence: how many events each rule produced, whether exceptions were approved, and whether test workloads passed. Ask for the observation period in each environment to be written into the scope, with exit criteria for every stage. That makes the rollout measurable and lets your change board see what will be enforced and when.

How DeployOpen scopes, builds and supports admission policies

DeployOpen scopes each admission policy rollout from the cluster rules your teams must enforce, then builds the CEL-based ValidatingAdmissionPolicy, bindings and parameters in your own clusters. Engagements are fixed-scope, with the scope, deliverables and timeline agreed in writing before work starts. Ongoing policy maintenance is available as a retainer.

How we scope

  • The written scope lists each rule, the resources it applies to and the namespaces or clusters in scope.
  • We confirm the Kubernetes version of each target cluster and its enabled admission features with your platform team.
  • Scope includes a rollout plan that moves each policy through Warn and Audit before any Deny action is enabled.

How we build

  • Policies are written in CEL and tested against sample objects that cover allowed and rejected manifests.
  • Parameter resources hold values such as allowed registries or label keys, so rules change without rewriting expressions.
  • Bindings are scoped by namespace selectors and parameter references, and each binding is reviewed before it goes live.

How we hand over

  • Handover includes the policy manifests, bindings, parameter files and test cases in a Git repository you own.
  • Documentation records each rule's intent, its enforcement stage, and the audit events a team should review.
  • Your team walks through the Deny switchover runbook, including how to roll back a policy binding.

How we support

  • Ongoing support covers policy checks before and after each Kubernetes upgrade, against the release notes for that version.
  • Retainers cover adjustments to rules, new bindings and periodic review of audit events as clusters change.
  • Retainer terms are agreed in writing, the same way as the initial fixed scope.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.