19
AWS service sources tagged from creation events, across 36 event types
30s
Scanner-to-tracker reconciliation, down from roughly 15 minutes
The finding was never the bottleneck
Cloud security tooling is good at producing findings. A scanner reports a vulnerable container image, a policy engine reports a resource that violates a rule, an inventory reports something with no owner. None of that is scarce. What is scarce is the step after: someone specific, on a specific team, with a specific deadline, who is accountable for the fix.
That step was manual, and it degraded in the predictable ways. Findings were copied into tickets inconsistently or not at all. The same finding produced a second ticket next week because nothing tied the two together. Tickets stayed open long after the underlying issue had cleared, so the backlog stopped meaning anything. And a resource created without ownership metadata could not be routed to anybody at all — there was no team to send it to.
What the design had to live with
- No shared identifier. The scanner and the issue tracker have no common key. Anything that matched a finding to a ticket had to derive an identity both systems could agree on.
- Findings recur. The same vulnerability can clear and come back. Deduplication had to distinguish "this again" from "this still", or it would either spam duplicates or silently swallow a genuine reappearance.
- Regulated environment. This sits inside a FedRAMP boundary, so ticket records are audit evidence rather than convenience — consistency of fields and dates matters as much as coverage.
- A multi-account organisation. Resources are created continuously across many accounts by teams the security account has no direct write access into.
Three joins, each closing a different gap
- Attribution at creation. Rather than sweeping for untagged resources on a schedule, member accounts forward resource-creation events to a central security account, which assumes a scoped role back into the originating account and applies ownership metadata through service-native APIs. Coverage spans 19 service sources and 36 creation event names. Reacting to the creation event rather than a later scan shrinks the window in which a resource exists with nobody attached to it.
- Policy findings into tickets. Cloud policy-as-code results are read by a Lambda that translates violating resources into security issues carrying the account, region, policy, resource, and detection dates — with stable identity, so a recurring result updates the existing ticket instead of opening another, and lifecycle handling that closes a ticket once the violation stops being observed.
- Scanner and tracker reconciliation. A scheduled job reconciles container vulnerability findings against security tickets in both directions: open what is missing, sync what has drifted, reopen what has resurfaced, and close what the scanner no longer reports. Severity maps to priority and to a remediation deadline, so a ticket arrives already triaged.
- Deployment identity, not deployment secrets. The infrastructure ships through CI that assumes cloud roles via OIDC rather than holding long-lived access keys.
Tradeoffs worth naming
- Derive identity rather than store a mapping. Matching findings to tickets by a deterministic identity computed from the finding itself means there is no mapping table to fall out of sync, migrate, or lose. The identity is stable across runs because it is a function of the finding, not of when the automation happened to see it.
- Centralise policy, execute locally. The security account owns event routing and decides what happens; the action runs through a scoped role in the account that owns the resource. That avoids the security account holding broad write access everywhere, and keeps the blast radius of a mistake inside one account.
- Constrain cross-account trust to the organisation. Event submission into the central bus is scoped to the AWS Organization rather than opened to arbitrary accounts — a smaller decision that stops the routing layer becoming its own attack surface.
- Reconcile in both directions. Creating tickets from findings is the easy half and the less useful one. Closing tickets whose findings have cleared is what keeps the backlog trustworthy enough that anyone acts on it.
Where it stands
- Newly created resources pick up ownership metadata from the creation event, across 19 service sources and 36 event types, through one architecture rather than per-team convention.
- Policy violations arrive as security tickets with cloud context, deduplicated identity, and automatic closure once the violation clears — a retained export verifies both the creation and the automatic stale-finding closure paths running in production.
- Scanner findings and tracker state stay in agreement daily, with severity-derived priorities and remediation deadlines applied without manual triage.
- Reconciliation runs in roughly 30 seconds rather than roughly 15 minutes, which is the difference between a job that can run as a routine control and one that cannot.
What I learned
The performance work taught me the most, and not for the reason I expected. Taking the reconciliation from about fifteen minutes to about thirty seconds was mostly a data-structures problem — repeated linear scans replaced with set membership, and independent API calls run concurrently instead of in sequence. But the reason it mattered was operational, not technical: a job that takes fifteen minutes is one you run occasionally and eventually stop running. Speed is what let it become something that runs every day without anyone thinking about it.
The broader lesson is that detection and ownership are different problems, and security tooling is much better at the first. Most of the value in this work was not finding anything new. It was making sure the things already found ended up in front of a person who could fix them, with a date attached.
Details here are limited to what is approved for public disclosure. Happy to go deeper in conversation.
More selected work
Building an enterprise AI security program from zero
Enterprise AI adoption arrives team by team. I own the program that makes it safe at MasterControl — the gateway, the guardrails, the policy, and the training that makes people actually follow it.
Detecting prompt injection, data leakage, and shadow AI
Three threat classes that do not look like anything in a traditional SIEM. Building coverage means deciding what an attack even looks like when the payload is ordinary English.
Embedding security into the delivery pipeline
Security review that happens after the code is written is advice. Moving the checks into the pipeline — static analysis at the merge, signature verification at the cluster — turns them into constraints.