DevSecOps

Migrating From Ansible to GitOps: A Supply Chain Perspective

Move from Ansible to GitOps with supply chain security intact. Pattern-by-pattern migration, trust boundary changes, and pitfalls to avoid in the transition.

Shadab Khan
Security Engineer
7 min read

The conversation about moving from Ansible to GitOps tends to focus on operator ergonomics, pull-versus-push reconciliation models, and the cleanliness of declarative state. The supply chain angle gets less attention, even though the migration fundamentally rewrites the trust boundaries, the audit trails, and the set of principals that can change production.

Done thoughtfully, a GitOps migration improves supply chain posture. Done mechanically, it can regress it, because patterns that were implicit and secure in Ansible — a bastion host, a vetted set of playbooks, a human operator — disappear without being replaced by explicit equivalents.

This is a working perspective on how to make the migration without leaving supply chain security on the old side of the line.

What Ansible actually secured

Before talking about what GitOps changes, it is worth being honest about what an Ansible-based workflow actually secured, because the answer varies.

A disciplined Ansible setup typically centralizes execution on a controller host, restricts who can trigger playbooks, requires review of playbook changes through a git workflow, and uses secrets storage with audit trails. The trust model is that a small number of humans, operating from a known system with known credentials, make changes to production. The playbook itself is a codified runbook, and the runbook's authenticity is vouched for by the fact that it ran from a trusted controller.

A less disciplined Ansible setup gives developers the ability to run playbooks from laptops, stores secrets in multiple places, and treats the playbooks as mutable scripts rather than versioned artifacts. The trust model in that case is essentially "whatever the operator did, we trust," which is not so much a trust model as a hope.

GitOps does not improve or regress security uniformly. It makes the first kind of Ansible setup more rigorous and the second kind dramatically more accountable, because Git becomes the single control point.

The shift from push to pull

GitOps replaces Ansible's push model — a controller reaches out to targets and applies changes — with a pull model — an agent on each target reaches out to Git and applies the declared state. The security implications are substantial.

The push model requires network access from the controller to every target, usually with elevated credentials. That network path is a target in its own right, and credential rotation is a nontrivial operation. The pull model inverts this: targets reach out to Git, Git is read-only from the target's perspective, and the credentials on the target are limited to what is needed to read the relevant configuration.

The inversion moves the trust boundary. The Git repository and the CI pipeline that validates changes to it become the most sensitive components in the path. A compromise of the Git repository or the CI pipeline is now a compromise of production, in a way that was not as direct in the push model.

This is not a bug. It is a deliberate tradeoff that simplifies the network model and concentrates the trust in a place where it can be defended more effectively. But the defense has to actually be implemented; otherwise the concentration of trust becomes a concentration of risk.

Protecting the Git repository

The Git repository that holds GitOps manifests needs protections that are often weaker on traditional application repositories. Branch protection must be enforced with required reviews from a specific set of approvers. CODEOWNERS must be respected, and bypass must be audited. Signed commits should be required for the manifests directory, with signature verification performed by the GitOps agent before applying.

The review bar for manifest changes is higher than for application code, because a manifest change can alter production state in seconds without going through a build. Reviews should check the diff against policy — are any privileged containers being added, are any new namespaces being created, are any secrets being referenced — not just for syntactic correctness.

Attribution matters. Every change to the manifest repository should be traceable to an individual, not a shared account. If automation writes to the repository — a common pattern for image updates — it should use a dedicated principal with the minimum necessary scope and its activity should be auditable.

The CI pipeline that governs the repository

Changes to the GitOps repository flow through a CI pipeline that typically lints the manifests, runs policy checks, and optionally stages the change in a test environment. That pipeline is now part of the production change path.

The pipeline must be tightly governed. Its configuration should be version-controlled and reviewed. Its runners should be ephemeral and isolated from other workloads. Its tokens and credentials should be scoped narrowly and rotated frequently. A compromise of the CI pipeline is a compromise of the manifest repository, which is a compromise of production.

Many teams under-invest in pipeline security because the pipeline feels like tooling rather than production. In a GitOps world, the pipeline is production. Treat it accordingly.

Image references and supply chain

GitOps manifests reference container images by tag or digest. Tag references are convenient but fragile — the same tag can point to different image contents over time — and they erode the audit trail because a manifest that has not changed can still produce a different deployment.

The better practice is to reference images by digest, either directly in manifests or through a controller that pins digests at the point of reconciliation. Digest references are immutable. A manifest that has not changed produces the same deployment forever, and the reconciler can verify that the image in the registry matches the digest in the manifest.

The same discipline extends to Helm charts, Kustomize bases, and any other dependency referenced by the manifest repository. Unpinned references are supply chain vulnerabilities; pinned references with signature verification are supply chain controls.

Secrets management

Ansible Vault is one pattern for managing secrets in an Ansible workflow. GitOps creates a more explicit problem: manifests in Git should not contain plaintext secrets, which means secrets must live somewhere else — a secrets manager, a sealed-secrets controller, or an operator-injected mechanism.

Each option has tradeoffs. External secrets managers are operationally simple but add a runtime dependency. Sealed secrets are self-contained but require key management discipline. Operator-injected secrets are flexible but can be opaque in audits.

The important property is that the manifest repository never contains readable secrets and that the mechanism producing the running secrets in the cluster is itself auditable. Several GitOps deployments have been undermined by well-intended patterns that moved secrets into Git in an encrypted form and then lost the keys, or worse, stored the keys alongside.

The audit trail

One of the genuine advantages of GitOps is that every production change is a commit. The audit trail is cleaner than most Ansible workflows ever produced, because the commit includes author, reviewers, signatures, and exact diff. An investigation that reconstructs what changed in production in the last ninety days is straightforward.

That advantage is real, and it is worth preserving. Direct cluster modifications that bypass the manifest repository destroy the audit trail and should be monitored for and alerted on. A reconciler that reports drift back to Git — or that refuses to proceed when drift exists — closes the loop.

Migrating incrementally

A full cutover from Ansible to GitOps in a single step is rarely advisable. The incremental path is to migrate one application domain at a time, validate the GitOps setup in production, and retire the corresponding Ansible playbooks only after the new path has proven itself. During the overlap, the auditability of both systems matters; a team that lets one become untrusted while the other is still in use inherits both sets of risks.

How Safeguard Helps

Safeguard's API integrates with the CI pipelines and GitOps controllers that sit at the new trust boundary. Every manifest change, image reference, and Helm chart is evaluated against SBOM, CVE, license, and provenance data before it reaches the cluster. Teams migrating from Ansible to GitOps get policy gates that make the supply chain implications of each change visible and enforceable. The platform's audit trail joins neatly with Git history so that investigators can move from a cluster state to the commit, the policy evaluation, and the full software composition in a single workflow.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.