Home / Stories / Security & compliance posture
Story · Security In development

A posture report your CISO can read, that never says "compliant" without proof.

Before an audit someone asks: "are our workloads non-root, are service account tokens locked down, is there a network policy everywhere?" The usual answer is a spreadsheet and a lot of hope. The assistant answers from the manifests themselves. It says "unknown" when it cannot prove something. It also runs a set of rule-based posture checks (checks in code, with no AI model) on the systems around your clusters.

Starts fromYour GitOps repositories (repositories that hold your infrastructure as files). It also uses read-only access to Cloudflare, GitLab and the GKE recommender (Google's advice tool for GKE clusters).
Looks atEvery workload manifest, edge zone settings and DNS, forge (GitLab) settings and CI, Google's own recommendations, and chart signatures.
You getAn on-demand PDF mapped to control IDs. You also get security issues: one finding per cause, each with the evidence.
01 · Ask for it

One command, one PDF.

The assistant generates the posture report on demand. It reads every manifest in every writable repository, the same set of files that the repository scanner sees. Then it renders a PDF.

It creates no merge requests and no issues. The other agents already propose fixes for the gaps it counts. The report is the summary, not a second copy of the work.

02 · Map manifests to controls

Three controls, chosen because they can be proven.

The first version covers the controls where a manifest can carry positive evidence.

  • PSS-restricted:runAsNonRoot, every container, init and ephemeral container included
  • CIS-5.1.x:sa-token-least-privilege, service account token automount
  • NSA-hardening:NetworkPolicy-present, checked against an index of the whole repository, so a policy in a sibling file still counts
03 · Never falsely compliant

Silence is "unknown", not "satisfied".

A false "compliant" is worse than a false gap. Someone may rely on it in an audit. So a control is satisfied only when the manifest says so explicitly. No finding is not proof. The assistant counts anything that the checks cannot decide as unknown, including an error while checking.

The report says on its face: manifest-checkable subset only, not an attestation.

04 · The report

Satisfied, gap, unknown, and the denominator.

Each control shows how many workloads the assistant scanned and how they split. A reader sees at once that 140 of 212 workloads prove they run as non-root. Another 31 do not, and 41 could not be decided from the manifest alone.

ISO 27001 and SOC 2 are organisational standards. Mapping down to them is planned as a later layer.

05 · Your edge

Cloudflare zones, checked every day.

The assistant reads each zone, read-only. It checks the minimum TLS version, HSTS, SSL mode, DNSSEC, managed WAF rules and rate limiting. It also checks for dangling CNAMEs, which point at a target that no longer resolves. They are a classic takeover risk.

If a zone's plan does not include WAF or rate limiting, the check abstains and raises no finding. The assistant reports a setting that it could not read as unobserved, never as fine. A separate check catches an armed edge block that would refuse the egress IPs of your own clusters.

06 · Your forge

The GitLab instance your GitOps depends on.

If someone can force-push to the deployment repository, the rest of the chain does not matter. The assistant reviews the forge itself.

  • Access: unprotected default branches, force push allowed, merge gates off, too many owners, groups without 2FA, memberships with no expiry.
  • CI: committed secrets, debug tracing that prints variables, public job artifacts, over-broad job tokens.
  • Runners: shared runners unlocked on protected work, runners offline for months.
07 · Google's view of your GKE clusters

The recommender, quoted word for word.

The assistant reads every active GKE recommendation for each cluster. The text is Google's, never paraphrased. The assistant already covers some recommendations itself (disruption budgets, memory limits, under-provisioned workloads). It attaches those as supporting evidence. It does not file them twice.

New recommendations arrive as issues. The assistant can also turn them into a draft MR against the matching manifest. This is built but not yet switched on.

08 · Chart signatures and pinned digests

Only verify what is actually signed. Only pin what was actually read.

Before the assistant proposes a Flux spec.verify block, it checks the chart's signing with cosign (a tool that checks signatures) and caches the result. A verify block on a chart that is not cosign-signed would break the release, so the assistant refuses it.

When a proposal pins an image to a @sha256: digest, that digest needs a receipt from the registry. If nobody looked up the digest, the assistant holds it for review and never ships it.

09 · Issues by default

Posture findings describe a setting, not a diff.

Edge, forge and cloud settings mostly live outside your git repositories. So these findings are issues. There is one issue per cause, with the evidence, the risk and the fix steps. Sometimes the setting does live in git, for example in a CI file or a manifest. Then a draft MR is possible.

The full issue is below.

terminal
$ gitops-assistant compliance-report --output posture.pdf
walking 4 repositories · 1,806 manifests
212 workloads · 3 controls
PSS-restricted:runAsNonRoot            140 / 31 / 41
CIS-5.1.x:sa-token-least-privilege     96 / 88 / 28
NSA-hardening:NetworkPolicy-present    171 / 12 / 29
wrote posture.pdf · 0 proposals created
satisfied / gap / unknown · illustrative numbers
apps/shop/orders-api/deployment.yaml
spec:
  template:
    spec:
      automountServiceAccountToken: false   # CIS-5.1.x ✓
      securityContext:
        runAsNonRoot: true                 # PSS runAsNonRoot ✓
      initContainers:
        - name: migrate
          securityContext:
            runAsUser: 0                   # overrides the pod → gap
      containers:
        - name: app
  • PSS-restricted:runAsNonRoot init container migrate runs as root → gap
  • CIS-5.1.x:sa-token-least-privilege explicit false → satisfied
  • NSA-hardening:NetworkPolicy-present networkpolicy_shop-default.yaml (sibling file) → satisfied
verdict rule
  • runAsNonRoot: true present on pod and not overridden SATISFIED
  • runAsUser: 0 on any container GAP
  • field absent, image decides the user UNKNOWN
  • chart-rendered values not visible in git UNKNOWN
  • checker raised an error UNKNOWN
absence of a finding is never counted as compliance
Kubernetes manifest posture · Acme
4 repositories · 212 workloads · generated 2026-09-24
ControlStandardSatisfiedGapUnknown
runAsNonRootPSS restricted1403141
SA token least privilegeCIS 5.1.x968828
NetworkPolicy presentNSA/CISA1711229
runAsNonRoot · 212 workloads
Manifest-checkable subset only, not an attestation. "Satisfied" requires positive evidence in the manifest; anything undecidable is "Unknown".
Illustrative page from the PDF.
Cloudflare · zone shop.example · read-only
  • minimum TLS 1.0 → high
  • HSTS disabled → medium
  • SSL mode full (strict)
  • DNSSEC disabled → medium
  • managed WAF not on this plan → abstain
  • CNAME old-promo.shop.example → promo-2023.pages-host.example · NXDOMAIN → dangling
6 surfaces read · 4 findings · 1 abstention · 0 unreadable
GitLab review · group acme/deployments
  • acme/deployments/prod force push allowed on main
  • group acme 2FA not required
  • group acme 9 owners · 14 members without expiry
  • acme/platform CI CI_DEBUG_TRACE: "true" in .gitlab-ci.yml
  • acme/platform CI artifacts public on a job that dumps env
  • runner build-02 offline 94 days
  • shared runners not used by protected pipelines
GKE recommender · cluster prod-eu
  • PDB_UNPROTECTED_STATEFULSET · shop/orders-db already covered · attached as evidence
  • MEMORY_LIMIT_NOT_SET · shop/cart already covered · attached as evidence
  • new subtype · platform/ingress → issue, Google's text verbatim
# quoted, never paraphrased
"<Google's recommendation text, exactly as returned>"
unchanged recommendation (same etag) → never re-filed
signature posture · cached 7 days
  • oci://ghcr.io/acme-charts/orders cosign signed → spec.verify: {provider: cosign}
  • https://charts.example.org · redis .prov only → no verify block
  • proposed verify block on unsigned chart refused → held for review
digest receipt gate
+  image: registry.example.com/shop/cart@sha256:9c1e…
✓ receipt: resolved from registry at emission
+  image: sidecar/labeler@sha256:<digest>
✕ no registry receipt · held (NEEDS_REVIEW)
Issue · shop.example: minimum TLS version is 1.0
category:securitysource:cloud_posturerisk:high
  • Check TLS 1.0/1.1 client share in edge analytics
  • SSL/TLS → Edge Certificates → Minimum TLS Version → 1.2
↓ the full issue is below

The issue you get.

Illustrative. It has the same shape as the edge-posture issues that the assistant files today. Settings outside git become issues. The assistant changes nothing here for you.

Open issue

Cloudflare zone shop.example: minimum TLS version is 1.0

account acme-prod · zone shop.example · rule min_tls_below_1_2
category:securitysource:cloud_posturerisk:high
OverviewEvidenceFix stepsRest of the zone
Finding

Zone shop.example accepts TLS 1.0 at the edge. TLS 1.0 and 1.1 are deprecated. They fail most compliance baselines (PCI DSS requires 1.2 or later for cardholder data).

Why this is an issue and not an MR

The setting lives in Cloudflare, not in a repository. The assistant's Cloudflare access is read-only.

SurfaceReadValue
zone settings · min_tls_versionok1.0
zone settings · sslokstrict
security header · HSTSokdisabled (separate issue)

The assistant read all three surfaces successfully in this run. It would report an unreadable surface as unobserved, never as compliant.

  • Check the share of TLS 1.0/1.1 clients in edge analytics for the last 30 days. Old embedded clients are the usual blocker.
  • In Cloudflare: SSL/TLS → Edge Certificates → Minimum TLS Version → TLS 1.2.
  • The next daily scan reads the setting again. A zone at TLS 1.2 or higher no longer produces this finding.
CheckResult
HSTSdisabled · medium · own issue
DNSSECdisabled · medium · own issue
Dangling CNAMEold-promo → NXDOMAIN · own issue
Managed WAF, rate limitingnot available on this plan · abstained

What keeps it honest.

Security reports lose their value the first time they are confidently wrong. These rules prevent that.

No false "compliant"A control is satisfied only on positive evidence in the manifest. Silence and errors count as unknown. The report says it is not an attestation.
Unreadable is not cleanA denied or partial read makes a check abstain. If every read for an account is denied, you get one loud issue about that. You do not get an all-clear.
Rule-based checks, no AI modelEdge, forge, recommender and signature checks are plain code over API reads. The same state always gives the same findings.
Other people's words, verbatimThe assistant quotes Google's recommendation text and never rewrites it. It suppresses a Cloudflare finding that would echo a token, or anything token-shaped.
No double filingThe PDF creates no proposals. Recommender items that the assistant already covers become evidence on the existing finding.
Read-only everywhereThe assistant only reads Cloudflare, GitLab settings and GCP. You make the changes, guided by the issue.

Where this stands.

Live
  • Cloudflare edge posture: min TLS, HSTS, SSL mode, DNSSEC, WAF, rate limiting, dangling CNAMEs, egress allowlist
  • GitLab access, CI and runner review
  • GKE recommender ingestion, quoted verbatim, issue-only
  • Cosign-aware chart verify blocks and the digest receipt gate
In development
  • Control-mapped posture PDF (3 controls, on demand)
  • Draft MRs for GKE recommendations that map to a manifest in git
  • Resolving image digests from the registry at emission, instead of holding the pin
Roadmap
  • More controls: encryption at rest, audit policy, retention
  • Down-mapping to ISO 27001 and SOC 2
  • Container image signature verification on running workloads
  • Wider cloud posture beyond the GKE recommender
← Previous storyBackup health you can trust