Network isolation and permissions
Network Isolation (AWF)
Section titled “Network Isolation (AWF)”Network isolation is provided by AWF (Agentic Workflow Firewall), which provides L7 (HTTP/HTTPS) egress control using Squid proxy and Docker containers. AWF restricts network access to a whitelist of approved domains.
The ado-aw compiler binary is distributed via GitHub Releases with SHA256 checksum verification. The AWF binary is distributed via GitHub Releases with SHA256 checksum verification. Docker is sourced via the DockerInstaller@0 ADO task.
Default Allowed Domains
Section titled “Default Allowed Domains”The following domains are always allowed. Most are defined in CORE_ALLOWED_HOSTS in allowed_hosts.rs; host.docker.internal is the exception — it is added by generate_allowed_domains (src/compile/common.rs) for any target that uses AWF (standalone and 1es targets), but not for job or stage targets. AWF-sandboxed agents need host.docker.internal to reach MCPG and SafeOutputs MCP servers running on the host:
| Host Pattern | Purpose |
|---|---|
dev.azure.com, *.dev.azure.com | Azure DevOps |
vstoken.dev.azure.com | Azure DevOps tokens |
vssps.dev.azure.com | Azure DevOps identity |
*.visualstudio.com | Visual Studio services |
*.vsassets.io | Visual Studio assets |
*.vsblob.visualstudio.com | Visual Studio blob storage |
*.vssps.visualstudio.com | Visual Studio identity |
pkgs.dev.azure.com, *.pkgs.dev.azure.com | Azure DevOps Artifacts/NuGet |
aex.dev.azure.com, aexus.dev.azure.com | Azure DevOps CDN |
vsrm.dev.azure.com, *.vsrm.dev.azure.com | Visual Studio Release Management |
github.com | GitHub main site |
api.github.com | GitHub API |
*.githubusercontent.com | GitHub raw content |
*.github.com | GitHub services |
*.copilot.github.com | GitHub Copilot |
*.githubcopilot.com | GitHub Copilot |
copilot-proxy.githubusercontent.com | GitHub Copilot proxy |
login.microsoftonline.com | Microsoft identity (OAuth) |
login.live.com | Microsoft account authentication |
login.windows.net | Azure AD authentication |
*.msauth.net, *.msftauth.net | Microsoft authentication assets |
*.msauthimages.net | Microsoft authentication images |
graph.microsoft.com | Microsoft Graph API |
management.azure.com | Azure Resource Manager |
*.blob.core.windows.net | Azure Blob storage |
*.table.core.windows.net | Azure Table storage |
*.queue.core.windows.net | Azure Queue storage |
*.applicationinsights.azure.com | Application Insights telemetry |
*.in.applicationinsights.azure.com | Application Insights ingestion |
dc.services.visualstudio.com | Visual Studio telemetry |
rt.services.visualstudio.com | Visual Studio runtime telemetry |
config.edge.skype.com | Configuration |
host.docker.internal | MCP Gateway (MCPG) and SafeOutputs on host — added for AWF targets (standalone, 1es), not part of CORE_ALLOWED_HOSTS |
aka.ms | Microsoft link shortener (used by az subcommand help/metadata) — contributed by the always-on Azure CLI extension |
Adding Additional Hosts
Section titled “Adding Additional Hosts”Agents can specify additional allowed hosts in their front matter using either ecosystem identifiers or raw domain patterns:
network: allowed: - python # Ecosystem identifier -- expands to Python/PyPI domains - rust # Ecosystem identifier -- expands to Rust/crates.io domains - "*.mycompany.com" # Raw domain pattern - "api.external-service.com" # Raw domainEcosystem Identifiers
Section titled “Ecosystem Identifiers”Ecosystem identifiers are shorthand names that expand to curated domain lists for common language ecosystems and services. The domain lists are sourced from gh-aw and kept up to date via an automated workflow.
Available ecosystem identifiers include:
| Identifier | Includes |
|---|---|
defaults | Certificate infrastructure, Ubuntu mirrors, common package registries |
github | GitHub domains (github.com, *.githubusercontent.com, etc.) |
local | Loopback addresses (localhost, 127.0.0.1, ::1) |
containers | Docker Hub, GHCR, Quay, Kubernetes |
linux-distros | Debian, Alpine, Fedora, CentOS, Arch Linux package repositories |
dev-tools | CI/CD and developer tool services (Codecov, Shields.io, Snyk, etc.) |
python | PyPI, pip, Conda, Anaconda |
rust | crates.io, rustup, static.rust-lang.org |
node | npm, Yarn, pnpm, Bun, Deno, Node.js |
go | proxy.golang.org, pkg.go.dev, Go module proxy |
java | Maven Central, Gradle, JDK downloads |
dotnet | NuGet, .NET SDK |
ruby | RubyGems, Bundler |
swift | Swift.org, CocoaPods |
terraform | HashiCorp releases, Terraform registry |
Additional ecosystems: bazel, chrome, clojure, dart, deno, elixir, fonts, github-actions, haskell, julia, kotlin, latex, lean, lua, node-cdns, ocaml, perl, php, playwright, powershell, python-native, r, scala, zig.
The full domain lists are defined in src/data/ecosystem_domains.json.
All hosts (core + MCP-specific + ecosystem expansions + user-specified) are combined into a comma-separated domain list passed to AWF’s --allow-domains flag.
Blocking Hosts
Section titled “Blocking Hosts”The network.blocked field removes hosts from the combined allowlist. Both ecosystem identifiers and raw domain strings are supported. Blocking an ecosystem identifier removes all of its domains. Blocking a raw domain uses exact-string matching — blocking "github.com" does not also remove "*.github.com".
network: allowed: - python - node blocked: - python # Remove all Python ecosystem domains - "github.com" # Remove exact domain - "*.github.com" # Remove wildcard variant tooPermissions (ADO Access Tokens)
Section titled “Permissions (ADO Access Tokens)”ADO does not support fine-grained permissions — there are two access levels: blanket read and blanket write. ARM service connections are used to mint scoped tokens for the agent (permissions.read) and optionally for the executor (permissions.write). The Stage 3 executor also uses the pipeline’s built-in $(System.AccessToken) as its default write token when no permissions.write override is configured.
Note: The trigger filter gate step (Setup job) uses System.AccessToken
for two purposes: (1) self-cancelling the build when filters don’t match
(PATCH to _apis/build/builds/{id}), and (2) fetching PR metadata for
Tier 2 filters (labels, draft status, changed files). The Stage 3 executor
also uses System.AccessToken as its default write token. In both cases
the pipeline must have “Allow scripts to access the OAuth token” enabled.
The agent (Stage 1) never receives System.AccessToken — this trust
boundary ensures the AI agent cannot directly perform write operations.
permissions: read: my-read-arm-connection # Stage 1 agent -- read-only ADO access write: my-write-arm-connection # Stage 3 executor -- write access for safe-outputsSecurity Model
Section titled “Security Model”permissions.read: Mints a read-only ADO-scoped token given to the agent inside the AWF sandbox (Stage 1). The agent can query ADO APIs but cannot write.permissions.write(optional): Overrides the Stage 3 executor’s default$(System.AccessToken)with an ARM-minted write token (SC_WRITE_TOKEN). Use this for cross-org or cross-project writes, or when you need the action attributed to a named service principal rather than the pipeline’s build service identity.- Both omitted: The agent has no ADO API access. Stage 3 still uses
$(System.AccessToken)for write operations (sufficient for most same-project safe outputs).
Examples
Section titled “Examples”# Agent can read ADO; executor writes via $(System.AccessToken) (default)permissions: read: my-read-sc
# Agent can read ADO; executor writes via named ARM identitypermissions: read: my-read-sc write: my-write-sc
# No ADO API read for agent; executor writes via named ARM identitypermissions: write: my-write-sc