Enterprise: governance without the cutover weekend
Meridian Health has a decade of infrastructure on Google Cloud, and the usual proposal for "bringing it under control" is a migration project with a cutover weekend attached — which is exactly why it gets shelved every year. Infrastream takes the other route: your existing estate comes under management one project at a time, the data and the applications stay exactly where they are, and no project gets a scheduled outage to make it happen. What changes is not where things run, but how they change: from that point on, who can reach what is written down in one readable place, and every alteration to it is reviewed before it takes effect. The four stories below follow that arc, ending with the one that matters most to a security team — what happens when an AI agent joins the picture.
Stories 15, 16 and 17 all describe onboarding: taking infrastructure that already exists and describing it in Infrastream's manifest hierarchy — a manifest being the plain-text file that declares what you want to exist.
Be clear about which half is automatic. Writing the description is human work: Infrastream does not scan your project and generate manifests from what it finds, so mapping an existing estate onto these kinds is scoped work done with Pvotal as part of an Enterprise engagement, not a self-serve button in the portal.
Acting on the description is automatic. Once a resource is described, the engine looks for it in Google Cloud before doing anything. If it is already there under the identity the manifest implies, the engine records it as managed and reports the change as an import — it does not build a second one, and it does not restart the one you have. That is what "the application never moved" means throughout this page.
The YAML below is real and schema-valid — it is what the finished state looks like once a project has been onboarded.
15. Bring your data lake into the graph
The win: "who can read what" moves from a spreadsheet that is wrong more often than right to a reviewable change request — and the data itself never moves.
| Who this is for | A data or platform team with years of storage spread across many projects, and no single trustworthy answer to "who has access to this?" |
| Difficulty | Advanced |
| Time | A few hours to a day, depending on scope |
| What you need first | Existing Cloud Storage buckets (and BigQuery datasets); administrative access to grant permissions on them; the Enterprise plan |
| What it costs | Nothing extra for the storage — the data stays where it is and keeps its existing bill. The workloads that read it scale with use, and non-production projects can be put on an off-hours schedule so they are not billed around the clock — see Controlling Costs. |
In plain words
Meridian's analytics team has years of data spread across dozens of buckets and datasets, and the answer to "who can read this?" lives in a spreadsheet somebody stopped updating in 2023. Bringing the data lake into Infrastream does not mean copying the data anywhere — it means writing down the storage and the access to it as files that sit next to the descriptions of the applications that use the data. A researcher's access to a dataset stops being a ticket that somebody forgets to close and becomes a line in a proposed change: visible, reviewed by the people accountable for that data, and removed by deleting the line.
Bucket does not adopt an existing oneStorage is the exception to the import behaviour described above. A Bucket is matched by its full
computed label set rather than by its name, so a bucket created outside Infrastream will not match,
and declaring one creates a new, separate bucket rather than taking over the one you have.
So read this story as being about the access, not the storage. The grants below are ordinary IAM on the buckets and datasets you already own, and they become reviewable without moving or re-creating any data. Bringing the storage objects themselves under management is part of the scoped onboarding work — confirm the plan shows an import rather than a create before approving it.
What you actually write
A Bucket names the storage; the access to it is declared on the workload that needs it, never on
the person granting it. The permission and the sub-path are the two lines that decide how much of
the lake a given workload can see.
# .../project/analytics/bucket/patient-imaging.yaml
apiVersion: lowops.manifests.v1
kind: Bucket
metadata:
name: patient-imaging
project: analytics
environment: prod
organizational-unit: research
organization: meridian
spec:
description: "Imaging archive for the research analytics workloads."
region: us-central1
storageClass: STANDARD
---
# Inside the Application (or Agent) spec that consumes it:
spec:
accessControl:
buckets:
- name: patient-imaging
permission: READ_ONLY # grants roles/storage.objectViewer and nothing else
subPath: "deidentified/" # the grant stops at this prefix
additionalRoles:
- roles/bigquery.dataViewer # read-only access to the team's BigQuery datasets
There is no BigQuery manifest kind today, so a dataset itself is not declared as a manifest the way
a bucket is. What is declarable — and what the governance argument actually rests on — is the
grant: additionalRoles puts the BigQuery role a workload receives into the same reviewed file as
everything else it can reach.
What the platform handles for you
- The identity each workload runs as, which starts with zero permissions — so nothing can read the lake until a line in a manifest says it can.
- The narrow IAM binding behind each
accessControlentry, scoped to that one bucket and that one prefix, instead of a broad project-wide role that quietly covers everything. - A
CODEOWNERSrule generated from the administrators you declared, so any future change to that project's directory needs approval from the people accountable for the data. - Encryption at rest for everything the platform provisions, with no setting for anyone to forget.
- A full history of every grant in the state ledger, so "when did this person get access, and who approved it?" is a query rather than an archaeology project.
Learn more
- Bucket manifest reference — every field on the
Bucketkind. - Storage, Messaging, Cache & Secrets samples
— ready-made
accessControlblocks to adapt. - Creating a Bucket — the step-by-step guide.
- Access & Identity samples — why grants go to groups, not to individual people.
16. Move an existing app without a rewrite
The win: governance arrives without the migration project that turns into a rewrite in disguise.
| Who this is for | A team running an application that works, that nobody wants to touch, and that still has to be governed |
| Difficulty | Advanced |
| Time | Half a day to a few days, depending on complexity |
| What you need first | An application already running on Google Cloud; administrative access to its project; the Enterprise plan |
| What it costs | Nothing extra — this deploys the container image your existing pipeline already builds, onto the same kind of runtime it already uses. |
In plain words
Meridian's patient portal has been running fine for years. Nobody wants to open the code, and nobody has the appetite for a migration that quietly becomes a rewrite. Infrastream does not ask for one. Instead, the portal gets described where it already runs: someone writes down the image it already ships and the service it already is. The engine then goes looking for that service in Google Cloud, finds the one that is running, and records it as managed — rather than standing up a second copy beside it. From that day forward every change to the portal goes through the same reviewed, priced, reversible flow as a brand-new application, and the application itself never moved.
Writing that description is the part a person does; there is no button that reads your project and produces it for you. What the platform guarantees is the other half — that describing something that already exists adopts it instead of rebuilding it.
What you actually write
Two files. The first vouches for the image the existing pipeline already publishes; the second declares the running application that deploys it.
# .../external-registry/gcr-io/trusted-repository/patient-portal.yaml
apiVersion: lowops.manifests.v1
kind: TrustedRepository
metadata:
name: meridian/patient-portal
external-registry: gcr-io
organization: meridian
spec:
description: "Portal images, already built by the team's existing pipeline."
---
# .../application-set/portal/external-application/patient-portal.yaml
apiVersion: lowops.manifests.v1
kind: ExternalApplication
metadata:
name: patient-portal
application-set: portal
release-track: main-track
organizational-unit: clinical
organization: meridian
spec:
description: "Patient portal — deployed from the image it already ships."
target: CLOUD_RUN # KUBERNETES and COMPUTE are also accepted
meshStrategy: SIDECAR
trustedRepository: meridian/patient-portal # the vetted source above
image: patient-portal # the image inside that repository
project: portal-svc
# ... accessControl and jobs elided
What the platform handles for you
- The application's own cloud identity, created for it and starting with no permissions — the portal reaches nothing it has not been granted in writing.
- Enrolment in the service mesh, which encrypts and authenticates every call between services without anybody managing a certificate.
- A default-deny network position: the portal can only talk to what a manifest allows, both inbound and outbound.
- A
CODEOWNERSrule over the portal's directory, so the next change to it requires the right reviewers whether a person or an agent proposed it. - Version pinning per environment through a
DeploymentConfig, so promoting a build to production is a reviewed change rather than a console click.
Learn more
- ExternalApplication manifest reference — the kind used for images built outside the workspace.
- Registries & Trust samples — declaring an
ExternalRegistryand the repositories you trust from it. - Migrating to Cloud Run — the hands-on guide.
- The Security Framework — what "secure by default" means for an application you did not write.
17. Migrate your infrastructure without a big-bang cutover
The win: the migration that gets shelved every year, done one project at a time, with no cutover day at all.
| Who this is for | A platform team maintaining a large estate of hand-written infrastructure code that nobody wants to migrate in one go |
| Difficulty | Advanced |
| Time | A phased rollout, typically weeks |
| What you need first | An existing Terraform or gcloud-managed estate; organization-level administrative access; the Enterprise plan and an agreed migration scope |
| What it costs | Nothing extra for the projects themselves — they keep running on the resources they already have. As projects come under management, their non-production environments can be put on an off-hours schedule, which is usually where the saving shows up — see Controlling Costs. |
In plain words
Meridian's platform team maintains a decade of hand-written infrastructure code across dozens of projects. A full cutover is proposed every year and shelved every year, because the risk of a weekend outage is never worth it. So the projects move one at a time instead. Each one is described in Infrastream's hierarchy where it already runs, and because the engine adopts what it finds rather than recreating it, nothing is rebuilt and nothing is redeployed to make that description true. From the moment the description is approved, changes to that project happen through reviewed change requests. Every other project in the estate keeps running exactly as it did the day before. By the time the last one is done, nobody can name a day when anything was down for it.
This is a scoped engagement, not a self-serve button. What the customer does: agree the scope
and the order of projects with Pvotal, grant organization-level access, nominate the first project,
and review the proposed changes. What happens per project: its place in the hierarchy is written
down, its administrators are declared, a CODEOWNERS rule is generated over its directory, and
governance shifts to reviewed change requests for that project and no other.
What you actually write
The hierarchy a migrating project lands in. The administrators group on the organizational unit is
the line that decides who has to approve every future change beneath it.
# manifests/organizational-unit/clinical/clinical.yaml
apiVersion: lowops.manifests.v1
kind: OrganizationalUnit
metadata:
name: clinical
organization: meridian
spec:
displayName: Clinical Systems
permissions:
administrators:
groups:
- clinical-platform # becomes a CODEOWNER of everything under this OU
---
# .../environment/prod/project/portal-svc.yaml
apiVersion: lowops.manifests.v1
kind: Project
metadata:
name: portal-svc
environment: prod
organizational-unit: clinical
organization: meridian
spec:
displayName: Patient Portal
defaultUrlRedirect: https://meridian.health
allowedEgress:
- "*.googleapis.com" # default-deny outbound; list what it may reach
# ... maintenance window and project-level permissions elided
What the platform handles for you
- Project-by-project isolation: each project is its own blast radius, so onboarding one cannot disturb the rest of the estate.
- The
CODEOWNERSfile, written from the administrators you declared, so the separation of duties between a development team and a network team is enforced automatically rather than remembered. - A default-deny outbound policy per project, with the allowed destinations listed in the manifest instead of scattered across firewall rules.
- Hibernation schedules that can be set once on an organizational unit and inherited by every environment and project beneath it — the lever that stops non-production estates billing overnight.
- A temporal record of every change in the state ledger, which is what an auditor actually wants when they ask what the estate looked like on a given date.
Learn more
- Project manifest reference and OrganizationalUnit manifest reference — the two kinds that carry the hierarchy.
- Organization Foundation samples — the full scaffolding, top to bottom.
- The Security Framework — how
CODEOWNERSis generated and why it follows the resource. - Core Concepts — the hierarchy in one page.
18. Give an agent fine-grained access to GKE and your data lake
The win: an AI agent that is exactly as powerful as the access written down for it — and not one pod more.
| Who this is for | A team that wants an AI agent working against real data and real workloads, and a security team that needs a better answer than "we gave it a broad role and trust it" |
| Difficulty | Advanced |
| Time | Half a day to set up, ongoing after that |
| What you need first | Story 15 done (the data lake described in the hierarchy); GKE workloads already running; a customer identity tenant in place; the Enterprise plan |
| What it costs | Scales with use. The agent runtime can be held at a minimum number of instances for fast responses, or allowed to scale to zero; either way non-production projects can be put on an off-hours schedule — see Controlling Costs. |
In plain words
Meridian's research team wants an AI agent that can query their data and manage a few of their
running workloads. "Give it an account with broad permissions and trust it" is the answer that makes
a security team's stomach turn, and rightly so. There are two separate questions here, and they need
two separate answers. The first is who is asking — the agent signs in through the same identity
system as every member of staff, so it is never anonymous and never borrows somebody else's login.
The second is what that particular identity is allowed to do with one specific dataset or one
specific workload — and that is finer-grained than a handful of broad roles can express. For that,
Infrastream can run a relationship-based authorization service, built on Ory Keto, the same family
of model as Google's own internal Zanzibar system. The practical effect is the one a business owner
cares about: the analytics agent can read the appointments dataset but never payroll, and can
restart pods in the analytics workload group but never billing — not because it was told not to,
but because those are the only relationships that exist for it.
What you actually write
The Agent manifest is where the agent's own cloud permissions are declared. Every line here is a
permission visible in the change request before anyone approves it; there is no inheritance and no
implicit credential.
# .../project/analytics/agent/research-analyst.yaml
apiVersion: lowops.manifests.v1
kind: Agent
metadata:
name: research-analyst
project: analytics
environment: prod
organizational-unit: research
organization: meridian
spec:
description: "Read-only research analyst over the de-identified lake."
target: AGENT_ENGINE
project: analytics
buildDefinition: research-analyst-build
accessControl:
additionalRoles:
- roles/bigquery.dataViewer # read datasets; no write role is granted
buckets:
- name: patient-imaging
permission: READ_ONLY
subPath: "deidentified/" # the grant stops at this prefix
secrets:
analysis-api-key:
envVar: ANALYSIS_API_KEY
The relationship layer, and where it actually lives
The accessControl block above is a cloud-permissions boundary: it decides which buckets, topics,
databases and secrets the agent's identity can reach at all. It is deliberately coarse, and it is
not where "the appointments dataset but never payroll" is expressed.
That finer decision belongs to the relationship-based authorization service. A PublicIngress
manifest provisions one by naming a sibling Database in its authorizationDatabase field; the
platform then stands up two Cloud Run services — a read-only external authorizer that checks
incoming requests against the stored policies, and an Ory Keto read-write service that the project's
own applications use to manage those policies. The relationships themselves — this agent may read
that dataset, this agent may restart pods in that namespace — are written into that service by
the applications that own them at runtime. There is no manifest field for an individual
relationship today, so do not expect to find one in the YAML above.
The same caveat applies to the GKE half of the story. Agent.spec.target accepts only
AGENT_ENGINE, and accessControl covers buckets, Pub/Sub, databases, secrets and additional IAM
roles — none of which can express "this namespace but not that one". Namespace-level authorization
over a GKE cluster is exactly the kind of decision the relationship layer is designed for, and it
has to be modeled there rather than in the agent manifest.
Ask the pvot agent to draft this one — see Using Pvot.
The Agent and AgentDeploymentConfig kinds ship today and their permissions are genuinely
PR-gated and CODEOWNERS-reviewed. The runtime is ADK-only, BuildDefinition with type: AGENT
has no CI workflow builder yet (plan to build and publish the agent package manually until that
lands), and broader policy controls are still in progress. Read
Agentic Governance before committing an agent to a
production path.
What the platform handles for you
- The agent's own runtime identity — the narrow IAM roles it needs and the token refresh that keeps a long-running session from silently losing access — provisioned automatically, with no field for anyone to get wrong.
- Consent for actions taken as a specific person: if a tool needs to open a pull request as a named developer, that developer is asked at the moment of the action, and the agent never holds a standing credential on their behalf.
- The same review gate as everything else — widening what an agent may reach means editing its manifest, which means a change request the right people have to approve.
- A hard boundary the agent cannot argue its way past: it cannot create permissions outside its
declared project, change the project's outbound rules, or reach a secret that is not listed in
accessControl. - A full record in the state ledger of every permission the agent was ever granted and when — the audit answer for "what could it do on the day of the incident?"
Learn more
- Agent manifest reference — the full
accessControlschema and the least-privilege best practices. - Agentic Governance — the model in full, including managed identity and delegated user consent.
- The Security Framework — the
authorizationDatabaselayer in the context of the whole security posture. - Security Guardrails — the shared responsibility model, in plain language.
Where to go next
That is the enterprise arc: a data lake described rather than moved, an application governed rather
than rewritten, an estate migrated one project at a time, and an agent whose power is exactly the
access written down for it. If you want to see the shape of these manifests in full rather than in
excerpts, the ready-made samples walk the whole hierarchy from an
Organization down to a single bucket, and the manifest reference documents every field on every
kind — start with Project and follow the links.
If you are evaluating rather than migrating, Getting Started is the shortest path from nothing to a first reviewed change, and it uses the same flow the stories above describe at enterprise scale.