Build Agent

A build agent is the machine or container that executes pipeline steps. Runner, agent, node, and executor are product-specific terms; the operational questions are what isolation boundary is provided, who maintains it, and which state survives between jobs.

An agent supplies compute capacity and forms part of a trust boundary. Jenkinsโ€™ controller-isolation documentation identifies job configurators, build-script authors, and test-code authors as people who can influence executed commands. Evaluate that code against the credentials, files, and network available to the job.

Two independent choices

These get conflated, and separating them is most of the value of thinking about agents at all.

Hosted by the vendorSelf-managed
Ephemeral โ€” destroyed after each jobThe usual hosted arrangement. The vendor operates and discards the environment; the isolation you get depends on the runner typeAchievable and a sound target: agents created per job from an image, then discarded. Isolation, permissions, and credential lifetime still need separate attention
Persistent โ€” reused across jobsUnusualThe common default, and the riskiest combination when untrusted code can run on it or jobs of different trust levels share it

GitHubโ€™s secure-use guidance describes disposable hosted environments as protection against persistence within the runner. Do not interpret disposal as a limit to information present at bootstrap: a running job may obtain more credentials, read remote data, or affect shared services. Those access paths remain part of its exposure.

Read “virtual machines” as specific to the runner type rather than as a property of hosted runners generally. The runner reference states that “with the exception of single-CPU runners, each GitHub-hosted runner is a new virtual machine (VM) hosted by GitHub,” and that “single-CPU runners are hosted in a container on a shared VM” โ€” the ubuntu-slim label as of this reading. The execution boundary therefore follows the label in your workflow. That is not a reason to treat the container-based type as unsafe; it is a reason to check the isolation and feature support documented for the type you actually selected, since those are what you are relying on.

Self-hosted runners can retain a compromise when their execution environment is reused. The risk depends on cleanup and isolation: later jobs may inherit malicious files or processes, while external caches and credentials need separate treatment even when the runner is replaced.

What persistence costs

A reused agent accumulates three problems, and each is easy to miss because the symptom is a confusing build rather than an alarm.

  • Cache and tool pollution. A dependency left behind makes a later build succeed that would fail on a clean machine, which is the classic “works on the build server” failure โ€” and the reverse, where stale state makes a correct change appear broken.
  • Credential residue. Tokens, key material, and logged-in tool sessions from a previous job may still be on disk or in an agent process when the next job starts.
  • Interference between jobs. Two concurrent jobs sharing ports, temporary paths, or a container daemon fail in ways that look intermittent and cost days to diagnose.

Which is why “ephemeral” is worth the effort even when self-managing โ€” with the qualification that it converts these into non-problems only to the extent that the discarded thing is where the problem lived. Three residues survive a discarded agent.

  • Anything outside the agent. A remote build cache, a mounted volume, a shared package proxy, a container daemon on the host. Poisoned content there is still there for the next job, so a cache your jobs write to is a trust boundary of its own.
  • Credentials the job obtained. Destroying the machine does not recall a token already exfiltrated. What limits that exposure is the credential’s own lifetime and your ability to revoke it โ€” not the agent lifecycle.
  • Shared resources. Separate containers or processes may still contend for host CPU, memory, or a shared daemon; namespace settings determine whether ports are shared. Separate VMs strengthen some boundaries but do not eliminate contention in shared physical infrastructure or downstream services.

Per-job lifetime, isolation, cache trust, least privilege, and credential revocation address different properties. Destroying a cleanly provisioned job environment reduces its local cache and credential residue. It neither establishes every isolation boundary nor invalidates an exfiltrated credential or poisoned remote cache.

The public-repository trap

GitHub strongly discourages self-hosted runners for public repositories because untrusted pull-request code can compromise the execution environment. Review whether a contributor can trigger execution and what the selected runner exposes.

Private or internal visibility does not remove this risk. Contributors who can cause code to run may reach the self-hosted runnerโ€™s files, credentials, and network. Restrict execution and separate trust levels instead of relying only on repository visibility.

Read that as a general principle rather than a product quirk: the population that can cause code to run on your agent is the population that can compromise it, and on most platforms that population is larger than the team. The question to ask about your own setup is who is in that population and what the agent would give them โ€” which is least privilege applied to build execution rather than to application access.

What you take on by self-managing

There are legitimate reasons to run your own agents โ€” network placement, specialized hardware, regulatory constraints, cost at scale. The point is to plan the obligations rather than discover them.

  1. Patching and image maintenance. The agent is a server with a toolchain on it, and it ages.
  2. Isolation design. One job per agent instance, and a network position that assumes the agent may be hostile rather than trusted.
  3. Capacity and queueing. Too few agents makes the pipeline slow in a way that shows up as people batching changes; too many is idle cost.
  4. Configuration decay. Jenkins’ documentation names it for self-managed systems generally: “most Jenkins environments grow over time requiring their trust models to evolve as the environment grows.” Exceptions granted during an incident become permanent unless someone reviews them on a schedule.

Jenkins defaults to allowing builds on its built-in node, where they have the Jenkins processโ€™s controller-filesystem access. Its documentation recommends running builds on separate agents. Verify their privileges and controller access; moving a job alone does not establish the full boundary.

Whatever the agent’s shape, keep the credentials it can reach separate from the agent itself โ€” the reason a job should fetch what it needs at run time rather than have it sitting on disk is the subject of secrets management. How the four common delivery systems differ on isolation and on the identity a job carries is worked through in Who Runs Your Build, and What Can It Reach.

References


Discover more from Insightful Data Lab

Subscribe to get the latest posts sent to your email.

Similar Posts

Questions, corrections, or additional insights?

This site uses Akismet to reduce spam. Learn how your comment data is processed.