Systems

  • Landing zone
  • Health insurance
  • Cigna
  • superseded
  • Principal engineer — 50% allocated to the security team
  • a year plus to production
  • 2024–2025
  • petabytes of data
  • Immuta, Databricks, Teradata, PostgreSQL, Amazon EKS, K3s, Amazon EC2, Amazon RDS for PostgreSQL, Helm, Terraform
  • 7 min read

Put the state outside the cluster, and moving clusters is a connection string.

What was on fire

The security team had already bought the product. It had nowhere it was allowed to run.

Cigna has a whole lot of database platforms — Databricks, Teradata, Postgres, pretty much every kind you’d want — and a whole lot of users, and the security team wanted one way to secure all of it. Not just row-level security: column-level too, with policies behind it. The way it had always been done was views — a view over the raw tables for each audience, and a grant on each view. That is cumbersome, and very difficult to maintain over petabytes of data.

Immuta was the answer they had bought — author a policy once and have it hold across the platforms. One example of dozens: some of our clients don’t want anyone offshore reading their data. An offshore employee logs in, their own metadata says they’re offshore, and their query in Databricks comes back with none of those clients’ rows.

The old way — a view for every audience Raw tables petabytes of them A view per audience over the raw tables A grant per view who may read which one The user sees what their views allow The model the security team bought — one policy on who the user is Raw tables the same data One policy authored once A query in Databricks filtered as it runs An offshore user none of those clients' rows User metadata says who is offshore
Fig. 01 — The old way was a view for every audience over the raw tables, and a grant for every view. The model the security team bought keys one policy on who the user is — an offshore user's query in Databricks comes back without the restricted clients' rows.

Fig. 01 · pinch or scroll to zoom · drag to pan

I was 50% allocated to the security team. My piece was to get it deployed in AWS: the Terraform around it, the integration with our other platforms, and everything the path to prod asks for — IAM roles from the internal service that vends them, our in-house monitoring and metrics.

Constraint set

The SaaS couldn’t get in. Letting an outside vendor through our external firewalls and every layer after them, down to the database side, is a tough sell. Before the hole there’s legal, networking, and everyone else, and the vendor goes through security reviews and audits of its own. That process exists for a reason — a vendor with a line into your core databases should be reviewed. But we weren’t going to get legal authorization inside the timeframe we needed. For a proof of concept, the process was insane.

The vendor’s documented approach was EKS. The EKS we were allowed to use was a shared enterprise cluster that doesn’t allow persistent volume claims, and Immuta runs a database of its own. A cluster of our own was possible, through a lot of hoops.

And the platforms weren’t ours. We didn’t own Databricks, or any of the other databases. We were a security team that was supposed to help secure them, so every database team had to let us in the front door. None of us was proficient in Kubernetes, either, and with limited access to our own AWS accounts, everything went through Terraform.

System diagram

Where it could run, and the one piece that never moved.

ruled out ran, with the database outside the cluster The vendor's SaaS a vendor hole through the firewall to the database zone EKS, as the vendor documents it its database needs a volume, the shared cluster allows none K3s on one EC2 instance lower environment, while the EKS approvals crawled Shared EKS production, early 2025 nothing on it needs a volume changed the connection string same database, data intact Amazon RDS for PostgreSQL the vendor's database — the one thing that never moved
Fig. 02 — Two ways in were ruled out before anything ran. Everything that ran kept the vendor's database on RDS, so the proof of concept on one EC2 instance and production on the shared EKS were one system pointed at one database — the lower environment moved by changing a connection string.

Fig. 02 · pinch or scroll to zoom · drag to pan

Architecture decisions

  1. Self-host the proof of concept instead of waiting on the SaaS. Immuta can run outside its SaaS, so the question became where. Rejected: the SaaS path, which needed a firewall hole, a vendor review, and legal sign-off before we’d learned anything.
  2. Move the state out first. The vendor’s install ran its database inside the cluster, on a persistent volume the shared cluster wouldn’t give us. I separated the database out onto Amazon RDS for PostgreSQL, changed the configuration to point at a Postgres the charts didn’t ship, and worked out how authentication would reach it. The idea was never to keep the proof-of-concept box forever. With the state outside, any cluster was a connection string away. Rejected: fighting the shared cluster for volumes, or standing up an EKS cluster of our own through the hoops.
  3. Run two tracks. While the EKS approvals crawled, I put K3s on a single large EC2 instance, which I could spin up with no problem. Then I worked backward from the vendor’s Helm charts to see how they wired everything for EKS, and rebuilt it for ours. I spent a lot of time with the vendor’s engineers, and they didn’t have a great solution for a cluster that allows no volumes. Their next major Helm chart, in May 2024, stopped shipping a database at all and told customers to bring a managed PostgreSQL such as RDS. The older chart could already point at an outside database. The new one made it the only way.
  4. Prove it on their own filtering before asking them to switch. The database teams wanted to know the performance implications and how it behaved in different scenarios. I wrote test scripts that ran their existing row- and column-level filtering side by side with Immuta’s. In some of those tests Immuta was significantly faster. One case was a lot slower: a SELECT * with no WHERE clause, where Immuta evaluated every row behind the scenes to see whether it hit a policy — on databases our size, a very real problem. Their answer was that their reporting users run exactly that and have to keep running it. Mine was to find the reports doing it and bring them up to best practice. They still didn’t like it.

Not again: don’t bring a new control to platforms you don’t own until someone above those teams can make the call.

Recovery / operate path

We started at the beginning of 2024, and the year that followed went to red tape and a learning curve, not to the product. Kubernetes first, then Kubernetes inside AWS, then all the Terraform around it. Then the EKS approvals, and the path to prod. There’s always a feedback loop: an architecture review comes back with “we need X, Y, and Z,” and by the time you’ve made the change and gotten back on their schedule, one cycle runs 3–6 weeks. The Databricks integration was the easy part.

The plan held. The lower environment moved from the K3s box to EKS by changing the connection string — same database, data intact — and it worked exactly as planned. Production went up on the shared EKS, its database on RDS, around the beginning of 2025.

Where it reached in production, as far as I know:

Platform Enforcing in prod What the vendor’s own docs show
Databricks Yes — the one I know for sure Policies compile into Databricks’ own row filters and column masks
Teradata I’m not sure A legacy database in the 2025.1 release. The new connector (November 2025) governed access to whole views, and row filtering and masking came in March 2026
PostgreSQL I’m not sure Listed among the legacy databases in the 2025.1 release

Teradata does row-level security on its own — what lagged was the connector, not the platform.

No count of policies, users, or queries. No numbers from the performance tests — only which way each case went.

What changed after

The database teams dragged their feet for months: “we’re waiting for performance testing,” then “we’re waiting for validations.” They still do. We were doing what the organization wanted, and there was no one in leadership above those teams who could force the decision. There’s a lot of inertia in how things used to be done.

Then the reversal. Once it was in production, leadership wanted the features the vendor ships to its SaaS customers first — Immuta’s own documentation says SaaS deployments “get features first.” So the self-hosted deployment is being converted to the SaaS that couldn’t get through the firewall for a proof of concept. I’m no longer on that team, and I can’t tell you how it’s going.

At the time, self-hosting was the right call. We didn’t really have any options. You don’t move mountains to punch a hole in a firewall for a proof of concept. Once it was in production it wasn’t a proof of concept anymore, and asking for the SaaS was asking for the same functionality, not for an experiment.

Anonymization notes

The client ships by name; the people do not. The security team, the database teams, my leadership, and the vendor’s engineers appear as roles. No client of Cigna’s is named — the offshore rule is described by what it does. Immuta, Databricks, and Teradata are named because the story turns on them. What this page says about Immuta’s Helm charts, its connectors, and its SaaS comes from Immuta’s own public documentation, not from inside the engagement. The internal service that vends IAM roles is described by what it does. Withheld: team and cluster names, the number of policies, users, and queries, and the test results beyond which way each case went. The dates are my own recollection. Stack footnote: Immuta self-hosted from its Helm charts — K3s on one EC2 instance for the lower environment, then Amazon EKS — its database on Amazon RDS for PostgreSQL, Terraform throughout, policies enforced in Databricks.

Who this is for

  • A security team that bought a control for platforms it doesn’t own.
  • A vendor install that assumes a cluster your platform team won’t give you.
  • A proof of concept that can’t justify a firewall hole into the database zone.
  • A leader whose new control is being waited out by the teams it’s meant to cover.

Related systems

More systems

Start

Tell me what’s stuck

I’ll tell you in about a day whether I’m the right person. The first conversation is fit, not a free architecture review.