Isolating the Argo CD repo-server from untrusted repositories

Argo CD's repo-server runs Helm and Kustomize on repository content, so a hostile chart or plugin can reach far beyond its own manifests. This page explains which controls contain that risk and what to confirm in your environment.

On this page

Why the Argo CD repo-server is the component to isolate first

The repo-server is the part of Argo CD that turns repository content into Kubernetes manifests, and it does so by running Helm, Kustomize and any configured plugins on files that someone else may have written. Isolating it means controlling three things: what it executes, what it can reach on the network and in the file system, and which source repositories each Argo CD project is allowed to use. The Argo CD security documentation names this risk directly: untrusted repositories and out-of-tree file access are the conditions to control.

You need this work first if many teams or tenants push charts and manifests into one Argo CD, if you consume third-party Helm charts you have not reviewed line by line, or if you run Config Management Plugins that receive credentials or generate output from custom scripts. In these setups, a single chart or plugin can make the repo-server read files it should not see, call internal endpoints, or produce manifests that deploy more than the owning team was approved to deploy. Each of these shifts the blast radius from one application to the whole cluster or to other tenants.

This page walks through the controls that narrow that risk: which repo-server execution paths to allow, network policies around the repo-server and Redis, manifest size limits, how plugin credentials are exposed, and per-project source repository restrictions. Before you change anything, confirm with your own inventory which charts, plugins and repositories are in use today, and whether any of them pull content from outside your control. That list determines which controls matter most in your environment.

Isolation controls and when each fits

This table compares the main controls for limiting what the repo-server can do with untrusted content, what each one limits, and when it fits your situation. Read each row as a separate layer: source allow lists stop bad inputs from being pulled in, while network policies and plugin restrictions limit what happens if one gets through. No control here removes the need to review what a chart or plugin actually executes.

ControlWhat it limitsWhen it fits
Per-project source repository allow listsRestricts which Git and Helm repositories each AppProject can pull from, so a team cannot point an application at an arbitrary chart or manifest sourceAny multi-team installation; the first control to set because it stops untrusted input before the repo-server processes it
Network policies around the repo-serverLimits which pods the repo-server can reach and which can reach it, reducing what a compromised manifest generation process can scan or call inside the clusterClusters where the repo-server shares a network with workloads that hold secrets or other sensitive services; confirm your CNI enforces NetworkPolicy
Network policies around RedisRestricts access to the Redis cache so only Argo CD components connect, since Redis holds cached manifest and application stateAny installation; Redis is a disposable cache, so the policy protects confidentiality of cached data more than recovery
Manifest size limitsCaps the size of generated manifests and chart output the repo-server will process, reducing resource exhaustion from oversized or looping templatesInstallations that render large charts or accept content from many sources; set limits after measuring normal output sizes
Restricting Config Management PluginsLimits which plugins exist and which applications may use them, because plugins run arbitrary commands on repository contentTeams that need custom rendering; keep the plugin list short and review each plugin definition before enabling it
Withholding provideGitCreds and preserveFileMode from pluginsStops a plugin from receiving the Git credentials used to clone the source repository, and limits executable files passed into itAny plugin that does not need to fetch other repositories or handle executable content; disable both unless a plugin requires them
Separate repo-server instances by trust levelIsolates sources of different trust so a compromise in one tier cannot read credentials or caches used by anotherRegulated environments or mixed internal and external content; adds operational overhead for upgrades and monitoring

How to restrict repo-server sources and network access

This sequence narrows what the Argo CD repo-server can fetch, run and reach, so a malicious chart, Kustomize file or plugin has fewer paths to Git credentials, cluster state and Redis. Each step ends with a check you can rerun after changes.

  1. Inventory every repository and chart source

    Platform engineering lists every Git repository, Helm chart repository, OCI registry and plugin source that Argo CD currently reads, along with the Application or ApplicationSet that uses each one and the team that owns it. Query the cluster for Application and ApplicationSet objects and record each spec.source and spec.sources entry, since a single application can pull from several places. Confirm the list with the application owners, because undocumented sources are the most common surprise at this step. The step is done when every source has an owner, a purpose and an approval decision, and anything unowned is marked for removal.

  2. Define projects with explicit source repositories

    Platform engineers create or tighten AppProject resources so that each project's spec.sourceRepos lists only the approved repository URLs and chart repositories for that team. Avoid wildcard entries unless the reader has a documented reason, and move each application into the project that matches its owner. Confirm the project also limits destination clusters and namespaces, because a permitted source deployed to the wrong target is still a problem. The check is to apply the projects and confirm that an Application pointing at an unlisted repository is rejected with a permission error rather than syncing.

  3. Remove plugins you do not need

    Platform engineers review the Config Management Plugin definitions in the cluster, including sidecar plugins in the repo-server, and remove any plugin that no current application uses. Each remaining plugin should have an owner, a pinned image and a documented purpose, and the team should confirm that the plugin's commands read only the files they need. Check whether any plugin reads files outside the application path, since the security documentation identifies out-of-tree file access as a risk to control. The step is done when the plugin inventory matches the application inventory from the first step and every plugin has a named owner.

  4. Disable provideGitCreds and preserveFileMode unless required

    For each plugin that remains, the platform team checks the settings provideGitCreds and preserveFileMode in the plugin configuration. The Config Management Plugins guide states that provideGitCreds gives the plugin the Git credentials used to clone the source repository, and that preserveFileMode can pass executable files to it. Set both to false by default and enable either only for a plugin that cannot work without it, recording the reason in the plugin's documentation. The check is to render an application through the plugin with both settings off and confirm the output is unchanged for the approved use case.

  5. Apply network policies to repo-server and Redis

    The cluster administrator writes Kubernetes NetworkPolicy resources that restrict ingress to the repo-server so that only the application controller and API server can reach it on its gRPC port. Restrict egress from the repo-server to the Git hosts, chart registries and DNS that the inventory identified, and deny everything else. Apply a separate policy to Redis so that only the Argo CD components that need the cache can connect. Confirm that your CNI plugin enforces NetworkPolicy before relying on the result, and check the deployed component names against your installation. The check is a connectivity test from a pod outside the approved set that fails to reach both services.

  6. Set manifest size limits

    Platform engineers set the limits that Argo CD exposes for generated manifests and for the size of the payloads it accepts, so that an oversized chart or rendered output cannot exhaust repo-server memory. Confirm the configuration keys and their defaults in the installed release's documentation before changing them, because names and behavior vary between versions. Test a rendered manifest slightly above the limit and confirm the sync fails with a clear error instead of hanging the repo-server. The check is a recorded test result for both the accepted and rejected cases.

  7. Verify each control with an unapproved source

    The team creates a test Application, in a non-production cluster, that points at a repository deliberately outside the approved sourceRepos list, and confirms Argo CD refuses to sync it. Repeat the test with a chart source that is not on the inventory, a plugin invoked against a path outside the application, and a request from a pod that the network policies should block. Record each result, including the error text, and keep the test manifests in version control so they can be rerun after upgrades or policy changes. The step is complete when every control has a passing test and a documented owner who reruns the suite on each change.

Risks that remain after isolation

Isolation narrows what a malicious repository can do, but it does not remove every path. The cards below cover the risks that stay open after projects, network policy and size limits are in place, and what to check for each one in your own cluster.

Plugins that receive Git credentials

A Config Management Plugin with provideGitCreds: true receives the credentials used to clone the source repository. Any code the plugin runs can read those credentials and reuse them against other repositories the account can reach. Review each plugin's definition, limit which teams can register plugins, and scope the Git credentials to the minimum set of repositories. Confirm that the plugin only needs the credential for the clone it performs.

Out-of-tree file references

Kustomize and Helm can reference files outside the directory Argo CD expects, which can pull local files from the repo-server into rendered output. Check which repositories can contain such references, and whether any plugin sets preserveFileMode: true, which passes executable files into the plugin. Ask each team to review references that point above the application path before enabling sync.

Charts that render unwanted resources

A Helm chart can render cluster-scoped objects, admission webhooks, or workloads in namespaces the project should not reach. Project destination and resource allow lists limit what Argo CD applies, but they depend on correct configuration. Test each project with a chart that attempts a disallowed kind, and confirm the sync is refused rather than partially applied.

Shared repo-server across tenants

A single repo-server process renders manifests for every project it serves, so a rendering flaw in one tenant's content can affect the workspace of another. Ask whether tenants with different trust levels need separate Argo CD instances. Where they share one, document the accepted risk, review who can add repositories, and confirm which controls separate tenant content during rendering.

Patching within supported versions

Repo-server fixes arrive in Argo CD patch releases, and only the three most recent minor versions receive them. A version that falls out of support keeps its isolation settings but loses fixes to the code that runs untrusted content. Track release notes for the version you run, schedule patch windows, and confirm the upgrade path before the minor line you depend on reaches end of support.

Questions teams ask before isolating the repo-server

What does isolating the Argo CD repo-server cost, and what drives the cost?

Cost depends on how many repositories, projects, Helm charts, Kustomize overlays and custom plugins the repo-server renders, and on how much of that content your team already controls. The work splits into one-time items (reviewing current sources, restricting repositories per project, writing network policies, setting plugin credential boundaries and testing) and recurring items (reviewing new repositories and plugins, and re-checking policies after each Argo CD upgrade). Each cost is driven up by unmanaged plugins, many chart sources from public registries, and a large monorepo that needs careful path scoping. Ask any partner for a written scope that lists each project, plugin and network path covered, and for the tests that will show each control works. DeployOpen does not publish prices, so a quote follows from that written scope.

How long does a repo-server hardening pass take?

The duration depends mainly on the number of Argo CD projects, the number of source repositories and charts, and the number and complexity of Config Management Plugins. A pass covering a few projects with standard Helm and Kustomize sources is shorter than one covering many projects, custom plugins and multiple clusters that share one Argo CD. Plan time for an inventory of sources, a review of each plugin's access to Git credentials, policy changes, a staged rollout and verification. Ask for a timeline tied to the agreed scope and to the number of environments that must be tested before production changes. No fixed duration is given here because none has been researched for this work.

What do we need from our own team for this work?

The work needs people who know your repositories and who can approve changes to production sync behavior. Expect to provide a list of Git repositories and Helm chart sources in use, the Argo CD projects and their destination clusters, any Config Management Plugins and the tools they call, and the current network policy and ingress layout. You will also need a named owner who can accept the restricted source list, because some teams will lose access to charts they depend on. Access to a non-production Argo CD instance is needed for testing before any policy reaches production.

Can our own platform team do the isolation work without a partner?

Yes, a capable platform team can do this work if it has Kubernetes network policy experience, access to the Argo CD configuration, and time to review plugins and sources. The main skills are reading how the repo-server runs Helm and Kustomize against repository content, writing restrictive network policies that keep the repo-server and Redis reachable only where needed, and restricting source repositories per project. Teams often bring in a partner for an independent review of the plugin credential exposure and for a test plan that the security team can rely on. Decide early which parts your team will own after the engagement, such as policy changes, plugin reviews and retesting after each upgrade.

Can one Argo CD instance safely serve untrusted tenants?

Treat a single shared Argo CD as a boundary that needs strong controls, not as a safe default for untrusted tenants. The repo-server executes Helm and Kustomize on repository content, so a tenant who can point an application at a malicious source may influence what runs in that component. Controls that reduce this risk include restricting source repositories per project, limiting which namespaces and clusters each project can target, keeping plugin credentials away from tenant-controlled paths, and placing network policies around the repo-server and Redis. Where tenants do not trust each other, many organizations separate Argo CD instances by trust level. Confirm your tenancy model against the project and RBAC controls in your Argo CD version before deciding.

How do we test that the repo-server isolation controls work?

Test each control with a case that should fail and a case that should pass. Examples include an application pointed at a repository not listed in its project, which Argo CD should reject; a chart or Kustomize file that tries to read a path outside its source directory; a plugin that should not see Git credentials when provideGitCreds is not set to true; and a pod in another namespace that should not reach the repo-server or Redis under your network policy. Keep the results as evidence and rerun the same tests after each Argo CD minor or patch upgrade. Run these tests in a non-production instance first, then repeat them in production with the same configuration.

Which Argo CD settings change the repo-server risk the most?

Four settings have the largest effect on what the repo-server can reach. The first is the list of source repositories allowed in each project, which limits where manifests can come from. The second is plugin configuration, where provideGitCreds: true gives a plugin the Git credentials used to clone the source repository, and preserveFileMode: true can pass executable files to it. The third is network reachability to the repo-server and Redis, controlled by network policies around those components. The fourth is manifest size and generation limits, which bound how much work a single source can force. Review each one on every project and confirm the values against your Argo CD version's documentation.

How to prove the repo-server controls work

The point of this section is that each control in the repo-server design needs a test that can fail. Write the tests before go-live and run them again after every Argo CD upgrade, Helm or Kustomize version change, and change to a project's source repository list. Start with the source repository allow list: create a test Application in a project whose sourceRepos does not include a repository you control, and attempt a sync. The sync must be rejected with a permission error that names the project. Repeat the test with a repository that is allowed but a path or chart outside the expected scope, and confirm the decision matches your written policy. Also confirm that a deliberately malformed or oversized manifest fails within the limits you configured, not after the repo-server has consumed the resources.

Next, test what a Config Management Plugin can see. Deploy a harmless test plugin that prints its environment and the files it can read, and confirm that Git credentials are absent unless provideGitCreds: true is intentionally set for that plugin. Check that preserveFileMode: true is only enabled where executable files are required. Then confirm that the repo-server cannot read files outside the repository path by placing a sentinel file in another location on the repo-server volume and verifying that a manifest referencing it fails. For network isolation, run a pod from an unrelated namespace and attempt connections to the repo-server and Redis service ports. Both should time out or be refused under your NetworkPolicy set. Confirm the same from a namespace that should be allowed, so you know the policy works in both directions.

Keep the outputs as change evidence. Store each test's command, the Argo CD version, the project definition, the NetworkPolicy manifests, the observed result and the date in your change system, and link them to the change request for the upgrade or policy edit. Ask your auditor or internal control owner which format they accept before you start, because the evidence you need for change and configuration management is often different from what engineers find useful. Re-run the suite on a schedule and whenever the Argo CD security documentation or release notes change the repo-server behavior, and treat any test that starts passing unexpectedly as a finding to investigate.

Who does what in an isolation engagement

Your platform team owns the Argo CD installation and the clusters it deploys into, so it supplies the facts the engagement depends on. Most of the early work is inventory: which repositories feed Argo CD, which Helm charts and Kustomize bases they pull, which Config Management Plugins are registered, and which projects can reach which sources. The team also decides cluster policy, such as network policy support, node pools for the repo-server and whether egress from it is allowed at all.

  • Source inventory: a list of every repository, chart registry and remote base referenced by an Application or ApplicationSet, with owners.
  • Plugin inventory: each Config Management Plugin, its command, and whether it receives Git credentials or executable file modes.
  • Cluster policy: whether your CNI enforces NetworkPolicy and which namespaces and labels identify Argo CD components.
  • Approvals: who signs off on changes to project source lists and on any new plugin before it is registered.
  • Access to the environment: named accounts and change windows for the staging and production Argo CD instances.

Check that the inventory is complete before the engagement starts, because a missing repository is a source that stays unrestricted.

How DeployOpen scopes and delivers repo-server isolation

DeployOpen plans, implements, hardens and documents self-hosted Argo CD inside your own infrastructure, including the repo-server isolation controls described on this page. The work covers the repo-server and Redis network policies, the plugin and Helm or Kustomize execution path, per-project source repository restrictions, manifest size limits and the verification that each control blocks what it is meant to block. Security testing of the resulting setup is available as a separate scope, and ongoing support, upgrades and continuous testing can be contracted as retainers once the initial work is complete.

Engagements are fixed-scope. Before work starts, the written scope names the clusters and Argo CD instances in play, the repositories and plugins to be reviewed, the projects that will receive restricted source lists, the network segments involved and the deliverables, such as tested policies, a configuration baseline and an operations runbook. A quote follows from that written scope, so the inputs that move cost most are the number of repositories and plugins, how many Argo CD projects need separate rules, and whether your network controls must be changed or only documented. Ask for these items explicitly when you compare proposals.

Before you engage any partner, confirm what the controls will look like in your environment. Ask which Argo CD minor version you run and whether it is still inside the supported window, since that determines which settings and upgrade steps apply. Ask who in your organization owns the Git hosts, the cluster network policies and the plugin images, because those owners must approve the changes. DeployOpen does not hold vendor partner status or issue certifications, and it does not produce audit reports. It prepares the configuration, evidence and documentation that your independent assessors will review.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.