Skip to content
CWS
CorovaAboutContact
Book a Call
All articles
Service Delivery

The Finding Is in GCP. The Fix Is in Terraform. The Owner Is in Neither.

The finding is raised against a live resource. That resource was produced by a pipeline from a definition held in a repository, so a change made in the console holds until the next apply, and the change that holds after it is a commit to that definition. The path from detection to a durable fix runs across three systems and two teams, each of which can finish its own half while the whole stays open.

CWSAugust 14, 20266 min read

The finding names a resource, and the resource is an output

The remediation takes four minutes. Open the console the finding came from, find the resource, change the setting, capture the evidence, close the ticket. The evidence is real. At the moment it was taken, the setting was correct.

What the evidence cannot show is where the resource came from. A pipeline created it from a definition held in a repository, and that definition still says what it said before anyone opened the console. When the pipeline puts the setting back, it is doing exactly the job it was built for. Reconciling the running estate to the definition is the reason the estate is run that way.

So the finding returns, on a schedule set by how often that repository ships. By the time it comes back the ticket has been closed for weeks and counted in a report, and the two events sit far enough apart that connecting them takes somebody going looking.

Several ordinary things keep this out of view for longer than it should be:

  • Closure is verified at the moment of the change, and that verification is the last time the process reads the resource.
  • When the pipeline recreates the resource, the returning finding carries a new identifier and gets logged as a new finding.
  • The interval between the fix and the reversion is set by the platform team's release cadence, which can be days in one repository and a quarter in another.
  • The engineer who closed the ticket and the engineer who ran the apply have no reason to be in the same conversation.
A setting changed in the console holds until the next apply. Nobody in the loop is holding that clock.

Console or code, asked before anyone touches it

One question decides where the remediation happens, who performs it, and whether it lasts. Is this resource produced from a definition. It reads like an implementation detail on a triage form, and it is the field the whole path hangs on.

There are three answers. A resource somebody created by hand is fixed by hand, and the console change is the durable one. A resource produced from a definition that sets the attribute the finding names has to be fixed in the definition, and every other route is temporary. The third answer is the one where the route is least obvious: the resource comes from a definition, and the attribute in question is absent from it. Somebody set that attribute by hand at some point, the pipeline has no opinion about it, and a console fix may survive for months, until the day the module is extended to cover it.

That third case deserves its own disposition. The change goes into the console to stop the exposure now, and into the definition so the pipeline asserts the state, which stops it depending on whoever touched the resource last.

Triage records the answer in three fields, on every finding:

  • Whether the resource is produced from a definition, and which repository holds it.
  • Whether the attribute the finding names is set in that definition or left unmanaged.
  • The route the fix takes: console, repository, or both, with the order stated.
Whether a resource is managed as code reads like an implementation detail. It is the field that decides whether the fix is permanent.

Mapping the resource back to the module that produced it

The finding arrives carrying a resource identifier. The repository holds a module, a variable and a file path. Joining the two is a named capability: Prisma Cloud and Wiz both correlate a running resource back to the definition that produced it, and where one of them is deployed and the repositories are connected to it, the mapping is there to read. The work starts where that coverage ends, in the account that sits outside the rollout and the acquired estate that has yet to be connected.

CWS runs tool agnostic posture assessment across AWS, Azure and Google Cloud, and has run the same trace in the other direction on an application security estate discovery, where running assets had to be tied back to the repositories that owned them. What follows is how CWS designs the routing, built on that experience.

Where the link has to be assembled by hand, these carry it, in descending order of how far you can trust each one:

  • A tag written by the pipeline when the resource is created, naming the repository and the module path. It is correct by construction, and it exists only where somebody decided in advance that it should.
  • The state file the pipeline maintains, which maps an address in the definition to the identifier in the cloud. Reading it needs access to wherever that file is stored, and that access sits with the platform team.
  • Naming conventions, which hold until the team that set them revises them, or until an acquisition brings in an estate that never followed them.
  • Asking an engineer, which is accurate and slow, and is the argument for building the mapping once and keeping it.

Two teams, two measures, one queue missing

Both platforms CWS implements can route a finding into the tracker the platform team already works from, and open a pull request against the module where the mapping supports it. What arrives is a ticket and a proposed change. The fix itself is a change to a repository the platform team owns, carrying the same review, testing and release risk as any other change to that module, and it has to be placed in a quarter that was planned before the finding existed. The security team's quarter is counted in findings closed. The platform team's is counted in what shipped.

Where that routing has been built, the ticket arrives cleanly and still has to be given a place in the plan. Without it, what reaches the platform team is a message in a channel, a spreadsheet row, or a person at their desk. Both teams are doing what they were asked to do, and the work falls between the two descriptions.

The measure is where this resolves. Count closure at the console and the console is where fixes get made, because that is what the number rewards. Count it at the definition and the change has to enter the platform team's planning like any other change: sized, placed in a backlog, and put ahead of something else by a person who can make that call.

The routing itself is a small piece of engineering sitting under a longer conversation. Settle these between the two teams before the first finding is routed:

  • Where the finding arrives for the platform team, in the tracker they already work from, carrying the repository, the file, and what the change has to achieve.
  • Who writes the change. A security engineer opening the pull request is faster. A platform engineer writing it is likelier to pass review. Either works, and choosing in advance is what stops the finding sitting still.
  • What counts as closed, stated once, in language both teams report against.
  • How an exception is raised when the fix cannot be scheduled this quarter, with a name and a date against it.
  • Who reviews the security relevant part of the change, given the module may deploy into several teams' estates.

The reading that proves the fix held

Closure evidence is a reading taken at the moment of the change, because that is the moment the person closing the ticket is present for. The reading that settles the question is the second one, taken after the next deployment of the repository that produces the resource. That is the one that says the estate stayed fixed.

Scheduling it is harder than taking it. The next apply happens when the platform team ships, and that date sits in their release plan. The version that works attaches the re-check to the deployment rather than to a calendar. The pipeline runs, the resource is read again, and the finding closes on that second reading.

Then there is what happens when the finding comes back anyway. Treated as the same finding reopened on the same resource, the record shows how long the estate carried the exposure and how many attempts it took to close it. Logged as a new finding, the same event becomes a fresh item with a fresh clock, and every closure metric in the program improves.

The triage fields, the tag applied at resource creation, the agreement between the security and platform teams, and the contents of a closure record are all CWS design. Any of them can be built another way. A closure record that survives a follow up question carries four things:

  • The change to the definition, identified by commit, in the repository recorded at triage.
  • The deployment that applied it, identified by its run.
  • A reading of the resource taken after that deployment, in the state the finding asked for.
  • Who accepted the closure, named on the platform side and on the security side.
A finding that returns on the same resource is the same finding. Logged as a new one, a reversion turns into evidence of activity.

Sources

  • CWS delivery corpus: tool agnostic multi-cloud posture assessment across AWS, Azure and Google Cloud
  • CWS delivery corpus: one application security estate discovery, where running assets had to be traced back to the repositories that owned them
  • The triage fields, the creation-time tag, the security and platform agreement, and the closure record: CWS design, not published guidance.