Recommendations to secure shared infrastructure in Azure Pipelines

Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2020

Protected resources in Azure Pipelines are an abstraction of real infrastructure. Follow these recommendations to protect the underlying infrastructure.

Use Microsoft-hosted pools

Microsoft-hosted pools offer isolation and a clean virtual machine for each run of a pipeline. If possible, use Microsoft-hosted pools rather than self-hosted pools.

Separate agents for each project

An agent can be bound to only one pool. You might want to share agents across projects by sharing the pool with multiple projects. In other words, multiple projects might run jobs on the same agent, one after another. Although this practice saves infrastructure costs, it can allow lateral movement.

To eliminate that form of lateral movement and to prevent one project from "poisoning" an agent for another project, keep separate agent pools with separate agents for each project.

Use low-privileged accounts to run agents

It's tempting but dangerous to run the agent under an identity that can directly access Azure DevOps resources. This problematic setup is common in organizations that use Microsoft Entra ID. If you run the agent under an identity that's backed by Microsoft Entra ID, then it can directly access Azure DevOps APIs without using the job's access token. You should instead run the agent as a non-privileged local account such as Network Service.

Azure DevOps has a group that's misleadingly named Project Collection Service Accounts. By inheritance, members of Project Collection Service Accounts are also members of Project Collection Administrators. Customers sometimes run their build agents by using an identity that's backed by Microsoft Entra ID and that's a member of Project Collection Service Accounts. If adversaries run a pipeline on one of these build agents, then they can take over the entire Azure DevOps organization.

We've also seen self-hosted agents run under highly privileged accounts. Often, these agents use privileged accounts to access secrets or production environments. But if adversaries run a compromised pipeline on one of these build agents, then they can access those secrets. Then the adversaries can move laterally through other systems that are accessible through those accounts.

To keep your systems secure, use the lowest-privileged account to run self-hosted agents. For example, use your machine account or a managed service identity. Let Azure Pipelines manage access to secrets and environments.

Minimize the scope of service connections

Service connections must be able to access only the resources that they require. If possible, use workload identity federation instead of a service principal for your Azure service connection. Workload identity federation uses an industry-standard technology, Open ID Connect (OIDC), to facilitate authentication between Azure and Azure DevOps and does not use secrets.

Your Azure service connection should be scoped to the resources that your the service connection needs to access. Users shouldn't have broad contributor rights for the entire Azure subscription.

When you create a new Azure Resource Manager service connection, always select a resource group. Ensure that your resource group contains only the VMs or resources that the build requires. Similarly, when you configure the GitHub app, grant access only to the repositories that you want to build by using Azure Pipelines.

Next steps

Consider a few general recommendations for security.