Platform Engineering

Infrastructure as Code Is No Longer Enough: From IaC to Policy, Configuration and Platform as Code

Infrastructure as Code is the start, not the finish. See how policy, configuration, GitOps and platform engineering combine into a versioned enterprise platform product.

Infrastructure as Code changed cloud delivery by making infrastructure declarative, reviewable and repeatable. Teams could define networks, identities, compute and shared services in source control, then deploy the same intent through controlled pipelines. That is a major capability. But an enterprise platform is more than the resources it creates.

Developers also need safe defaults, policy decisions, application and environment configuration, deployment workflows, operational signals and a clear way to request capabilities. When these remain scattered across tickets, wiki pages, shell scripts and team-specific pipelines, the organization has automated infrastructure without making the platform coherent.

The evolution is often described as IaC → Policy as Code → Configuration as Code → GitOps → Platform Engineering. This is a useful way to understand the expanding scope, not a strict maturity ladder. These practices overlap and can be introduced incrementally. Together, they make the enterprise platform a versioned software product with an explicit interface, owners and a roadmap.

Each layer answers a different operational question; they complement one another.
LayerQuestionTypical artifact
Infrastructure as CodeWhat resources should exist?Versioned Terraform or Bicep definitions.
Policy as CodeWhich constraints must a change satisfy?Testable policy rules and assignments.
Configuration as CodeHow should services behave in each environment?Reviewed manifests, settings and secret references.
GitOpsHow is desired state applied and reconciled?Versioned declarations and a reconciliation controller.
Platform EngineeringHow do teams discover and safely use these capabilities?Supported self-service workflows and a product contract.

1. Infrastructure as Code: define the resources

IaC describes the cloud and infrastructure resources a workload needs: accounts or subscriptions, networks, clusters, identity bindings, databases, queues and monitoring components. The definitions live in version control, are reviewed, and are applied through repeatable automation. That gives teams a history of changes and a practical way to create consistent environments.

IaC answers an essential question: What resources should exist? It does not, by itself, answer whether a deployment follows organizational rules, how an application should be configured, how drift is corrected, or how a developer discovers and safely consumes the capability.

Microsoft’s landing-zone IaC guidance describes versioned definitions, pipelines and repeatable deployments as part of operating cloud foundations. That remains the base layer of the approach.

2. Policy as Code: make guardrails testable

Policy as Code expresses organizational constraints as rules that can be reviewed, tested and evaluated consistently. Examples include which regions or resource types are permitted, which identity patterns are required, whether a workload needs private access, or what metadata must be present. Policy can run during pull requests and deployments, and some policies can also make decisions at runtime.

This moves governance closer to the change being made. Teams can see a failed rule before it becomes a production exception, and platform owners can update a centrally maintained rule with a traceable change. Good policy explains the required outcome and, where possible, points the developer to a compliant path.

Policy is not automatically a replacement for human review. High-impact changes may still need an approval gate, and rules need owners, tests, exception paths and a process for communicating changes. The Open Policy Agent documentation describes policy as code as a way to separate policy decision-making from enforcement, so the same policy logic can be used at different points in a system. For a step-by-step workflow, see the Engineering Library’s How to Implement policy-as-code guide.

3. Configuration as Code: describe how workloads should run

Infrastructure creates the runtime environment; configuration defines how applications and platform components behave in that environment. It can include deployment manifests, service settings, feature flags, environment-specific parameters, monitoring rules and references to secrets. Managed declarative configuration gives teams a reviewable desired state instead of relying on manual edits and undocumented defaults.

Configuration as Code needs boundaries. Secret values should be stored and delivered through an appropriate secret-management system, not committed as plaintext. Environment differences should be explicit and constrained, and a configuration change should have a clear owner and rollback path. The objective is to make the running system explainable and reproducible.

4. GitOps: continuously reconcile the declared state

GitOps extends version-controlled desired state into an operating model. A controller observes the declared configuration, compares it with the live environment and works to reconcile differences. This makes drift visible and provides a consistent path for applying changes, including application and platform configuration—not only the underlying infrastructure.

The OpenGitOps principles describe desired state as declarative, versioned and immutable, automatically pulled, and continuously reconciled. Those principles clarify why simply storing YAML in Git is not, by itself, GitOps. Teams also need to decide how secrets, emergency changes, approvals and reconciliation failures are handled.

5. Platform Engineering: provide a usable product interface

Even a well-automated repository can leave every application team responsible for learning the underlying cloud, policy engine, configuration format, cluster and deployment toolchain. Platform engineering packages the supported capabilities into self-service workflows: a service template, API, portal, CLI or documented path that lets teams make common changes safely and understand what the platform will do.

A golden path should remove avoidable work while preserving the context teams need to operate their service. It is a paved route with sensible defaults and supported options, not a locked box. Teams with legitimate requirements should be able to extend or leave the default path through a visible, governed process.

The CNCF overview of platform engineering describes the platform-as-product mindset: internal teams are users, and the platform team develops and maintains capabilities around their needs. A portal can be one interface to the product, but the product is the workflows, APIs, documentation, standards and operations that make delivery easier.

Treat the enterprise platform as versioned software

Build platform capabilities in connected layers
  1. Infrastructure as CodeCreate repeatable cloud resources from reviewed definitions.
  2. Policy as CodeValidate guardrails and enforce requirements at the right scope.
  3. Configuration and GitOpsDeclare workload configuration and reconcile the desired state.
  4. Platform interfaceExpose supported capabilities through documented self-service workflows.
  5. Product feedbackUse adoption, reliability and delivery friction to improve the platform.

Once developers depend on platform capabilities, changes to templates, policies, modules, cluster defaults and deployment pipelines can affect many services. Treating the platform as software makes those changes more predictable. The platform needs a clear owner, an interface, supported versions, a release process, change communication and feedback from the teams that use it.

  • Define a contract: document what a path provisions, what it expects from a workload team, its security and service boundaries, and how to get support.
  • Version reusable capabilities: publish modules, templates, policies and APIs with compatibility expectations. Make breaking changes deliberate and provide migration guidance.
  • Release through environments: validate changes with automated checks and representative workloads, roll out progressively where practical, and make rollback or recovery steps clear.
  • Measure the product: track onboarding time, adoption, deployment friction, change failure, policy exceptions, service reliability and developer feedback. Use measures to find friction, not to reward teams for using a portal.
  • Plan the lifecycle: communicate deprecations, patch dependencies, maintain documentation, publish changes and retire capabilities that no longer serve users.
  • Keep humans in the loop where needed: automation can standardize routine changes, while sensitive or high-impact decisions retain appropriate review and accountable owners.

This does not mean turning every internal tool into a large product organization. Start with a real user problem, a small supported workflow and a named owner. Expand when adoption and feedback show that the capability is worth maintaining.

One example: a service team needs a new workload environment

In an IaC-only model, a developer may open a ticket and wait for someone to assemble a subscription, network, cluster namespace and pipeline. With the fuller model, the team selects a supported workload template. IaC provisions approved resources; policy checks required boundaries; configuration sets environment-specific behavior; the GitOps controller applies and reconciles the declared state; and the platform gives the team documentation, deployment status and an escalation path.

The workflow is valuable because the pieces have a common contract and are operated together—not because it uses the newest tool. If teams cannot understand the path, change it safely or get help when it fails, the platform product is unfinished.

Build the next layer around a real delivery bottleneck

Organizations do not need to adopt every layer at once. Start by identifying repeated delays or risks: inconsistent infrastructure, recurring policy exceptions, manual configuration, deployment drift, or too many handoffs to provision a routine service. Add the capability that addresses that bottleneck, then measure whether delivery became safer and simpler.

That progression connects Cloud Foundation—governed environments and shared controls—to Platform Engineering—repeatable self-service workflows and a supported platform product. Tongtech’s Infrastructure as Code case study and platform engineering reference architecture show related patterns.

Policy as Code is the implementation layer; the broader ownership, exception and compliance model is covered in Why Cloud Governance Must Be Designed Into the Platform, Not Added Later.

For the broader progression from cloud foundations into production AI, see From Cloud Landing Zones to AI Landing Zones and Why Enterprise AI Is an Infrastructure Problem Before It Is an AI Problem. A usable platform is part of the foundation that lets teams operate those workloads consistently.

Give platform interfaces a compatibility policy

Reusable modules, templates and workflow APIs become dependencies for their consumers. Before changing an input, output, default or generated resource name, identify which teams and deployed environments use the current version. Test upgrades against representative consumer configurations, publish migration guidance and allow a transition period when an immediate change would break existing deployments. Keep a clear support window for released versions and remove obsolete paths only after their owners have migrated. Versioning does not require elaborate release machinery; it requires the platform team to make the effect and timing of a change visible to the teams relying on it. A compatibility policy should also say how long old module versions remain supported and how teams can pin a version while they plan an upgrade. That avoids coupling every workload release to a platform release and lets owners adopt improvements at a reviewable pace. Publish a deprecation window and a migration example with each breaking change. Consumers can then test the new contract in a branch, while platform owners can see which versions remain in use before removing an old interface.

Continue reading

References

Modernizing your delivery platform?

Start with a platform engineering assessment.

Identify the repeated delivery bottlenecks, governance gaps and self-service capabilities that should shape your platform roadmap.

Plan a platform review