NETWORG internal — July 2025
- Container image with all tools (Copilot CLI, playwright-cli, code-server, ttyd, az, gh, python, node)
-
agentboxCLI for local and Azure lifecycle (spawn/list/kill/open/term/logs) - Multi-arch image (arm64 + amd64) on GHCR
- nginx reverse proxy for single-port access (port 80)
- Azure ACI deployment with DNS label
- Nginx proxy image not yet rebuilt (disk space constraint)
- No HTTPS (HTTP only)
- No authentication
- No fleet dashboard
- Rebuild image with nginx proxy
- Test locally and on ACI
- Push updated multi-arch image
- Commit all changes to GitHub
All Azure and Entra ID resources managed via Terraform (infra/). All builds and deployments via GitHub Actions (.github/workflows/).
| Resource | Terraform file | Notes |
|---|---|---|
| Resource group | main.tf |
agentbox-rg |
| Container Apps Environment | container-apps.tf |
Hosts API app |
| Container App (API) | container-apps.tf |
YARP + API |
| Easy Auth config | container-apps.tf |
Entra ID provider, networg.com |
| Key Vault | keyvault.tf |
SSH CA, SP Reader cert, secrets |
| DNS zone / records | dns.tf |
*.agentbox.networg.com wildcard |
| Entra ID app registrations | entra.tf |
API, SP Reader, service principal |
| Entra ID group | entra.tf |
"AgentBox Admins" |
| GitHub Actions federated cred | entra.tf |
OIDC workload identity federation |
| Storage Account | main.tf |
Terraform state backend |
ACI containers are NOT in Terraform — they're ephemeral, created/destroyed at runtime by the API.
State stored in Azure Storage Account. Two environments: dev.tfvars / prod.tfvars.
| Workflow | Trigger | What it does |
|---|---|---|
infra.yml |
Push to main (infra/**) or manual |
terraform plan → apply. OIDC auth (no stored secrets). Plan on PRs, apply on merge. |
container-image.yml |
Push to main (Dockerfile, entrypoint.sh) or manual |
Multi-arch build (amd64+arm64) via Buildx+QEMU → push to GHCR. Tags: latest + sha-<commit>. |
api.yml |
Push to main (src/api/**) or manual |
dotnet build → dotnet test → Docker image → push → az containerapp update. |
pr-checks.yml |
PRs to main |
terraform validate, dotnet build+test, Docker build (no push), Terraform plan as PR comment. |
Auth: Workload identity federation (OIDC) — GitHub Actions authenticates to Entra ID without stored secrets. Federated credential scoped to repo:NETWORG/AgentBox.
Consolidation: The HTTPS proxy, dashboard, and API are a single ASP.NET Core application hosted on Azure Container Apps. This eliminates the need for separate Static Web Apps + Functions + proxy.
Tech stack: ASP.NET Core + YARP (Microsoft's reverse proxy) + Razor/Blazor or portal SPA
What the API does (one Container App, one deployment):
- Portal — Dashboard SPA served as static files (or Blazor), mobile-first (iPhone)
- API — REST endpoints for container lifecycle (
/api/boxes), OAuth flows, SSH certificates - Reverse proxy — YARP routes
*.agentbox.networg.com→ individual ACI containers, WebSocket pass-through - Authorization — C# middleware checks container ownership, shared access, admin group — shared logic for both API and proxy
- TLS — Container Apps managed certificates (free, auto-renewing)
- Authentication — Container Apps Easy Auth (Entra ID, networg.com tenant)
Architecture:
Internet → Container Apps (TLS + Easy Auth)
│
┌─────────┴──────────┐
│ AgentBox API │
│ (ASP.NET Core) │
│ │
│ ├── Static files │ → Dashboard SPA
│ ├── /api/* │ → API controllers (spawn, list, destroy, tokens)
│ ├── /auth/* │ → OAuth callbacks (GitHub, ADO, JSM)
│ └── YARP proxy │ → *.agentbox.networg.com → ACI containers
│ (WebSocket ✅)│
└────────────────────┘
│
┌────────┴────────┐
│ ACI fleet │
│ ┌───┐ ┌───┐ │
│ │AB1│ │AB2│...│
│ └───┘ └───┘ │
└─────────────────┘
Cost: ~$5-10/mo (Container Apps Consumption plan, 0.25 vCPU, 0.5 GiB)
Dashboard features:
- List active AgentBoxes (name, status, URLs, runtime)
- Spawn new AgentBox (name, OAuth flows, Dataverse environments, SharePoint sites)
- Destroy AgentBox (with confirmation)
- Direct links to VS Code and terminal for each box
- Mobile-responsive (iPhone first)
- "Run Locally" section — low-friction instructions for local disk access
API endpoints (served by the same ASP.NET Core app):
POST /api/boxes— spawn a new AgentBoxGET /api/boxes— list all AgentBoxesGET /api/boxes/:name— get AgentBox detailsDELETE /api/boxes/:name— destroy an AgentBoxGET /api/boxes/:name/status— health checkPOST /api/boxes/:name/ssh-certificate— sign SSH public key- Auth: Entra ID bearer token (validated by Easy Auth or
Microsoft.Identity.Web) - Future: Add Copilot SDK integration for conversational API
When users need AgentBox to access their local filesystem (e.g., working on a local project), cloud containers won't work. The dashboard provides a "Run Locally" page with:
- One-click token: User is already authenticated (Entra ID + GitHub OAuth). Dashboard shows a ready-to-copy command with their
GH_TOKENpre-filled:docker run -it --rm \ -v $(pwd):/home/agentbox/workspace \ -p 8080:80 \ -e GH_TOKEN=ghu_xxxxxxxxxxxx \ ghcr.io/networg/agentbox:latest - Zero-config: No manual token management — the OAuth flow on the dashboard already acquired the GitHub token
- Volume mount:
-v $(pwd):/workspacegives the agent access to whatever directory the user runs it from - Platform-specific tabs: macOS (Docker Desktop / Apple Containers), Windows (Docker Desktop / WSL), Linux
- Copy button: One tap to copy the full command to clipboard
- Token refresh: If the 8hr GitHub token expires, user returns to dashboard for a fresh command (or we add a refresh endpoint)
- Optional: "Advanced" expandable section with custom flags (port mapping, extra env vars, volume mounts)
The key insight: the dashboard is the token vending machine. Whether deploying to cloud or running locally, users authenticate once on the website and get a pre-configured command or container.
See identity.md for the full 6-service identity design (Entra ID, GitHub, ADO, JSM, Dataverse, SharePoint).
- Preferred: Entra ID SSH — Microsoft-managed CA,
az ssh vm --ip, Conditional Access- Tier 1 (start here): Extract tenant SSH CA public key, configure sshd
TrustedUserCAKeys, static principal mapping - Tier 2 (if needed): Install
aadsshloginPAM module for dynamic RBAC ⚠️ ACI reserves port 22 — must use port 2222- See entra-ssh-investigation.md for 5 validation experiments
- Tier 1 (start here): Extract tenant SSH CA public key, configure sshd
- Fallback: Custom CA in Azure Key Vault (HSM-backed) if Entra ID SSH doesn't work with ACI
- API endpoint:
POST /api/boxes/:name/ssh-certificate— signs SSH public key (24hr validity)
- API endpoint:
- Add openssh-server to container image, TrustedUserCAKeys only (no passwords)
- VS Code Remote SSH:
az ssh configor managed~/.ssh/config
- Apple Containers (macOS Tahoe): Native ARM64 local runtime on Apple Silicon Macs — replaces Docker Desktop for local use, provides native performance without QEMU emulation
- ACI: Current cloud runtime (cheap, simple)
- Azure Container Apps: For the API only (not for agent containers)
- Runtime abstraction in agentbox CLI — same commands, different backends
- Auto-detection: Apple Containers → Docker → ACI fallback
- Embed
@github/copilot-sdkinto AgentBox API - Enable programmatic multi-turn conversations with agent
- SSE streaming for real-time responses
- Use Copilot SDK for the "brain", AgentBox container for the "body"
- Adopt GitHub's agent firewall pattern
- Default allowlist: npm, PyPI, GitHub, Azure, MS domains
- Per-container custom allowlist at spawn time
- Network policy enforcement via iptables in container
- Mount Azure File Share for workspace persistence across container restarts
- Git auto-commit workspace changes
- Export session artifacts (markdown, code, screenshots)
- Entra ID-based: all access controlled via networg.com tenant
- Per-user container ownership and visibility
- Admin role for fleet-wide management
- Usage tracking and cost allocation per user
- 5-day max TTL enforced at API level with auto-cleanup
- Idle timeout (configurable, default 8 hours)
- Audit log of container lifecycle events
| Resource | Cost | Notes |
|---|---|---|
| AgentBox container (ACI) | ~$0.03/hr | 0.5 vCPU, 1 GB RAM |
| 8-hour workday | ~$0.24 | Per container |
| AgentBox API (Container App) | ~$5-10/mo | YARP proxy + API, Consumption plan |
| GitHub App | Free | No cost for OAuth app registration |
| Entra ID app registrations | Free | Dashboard, API, SharePoint Reader |
| Monthly (5 users, 8hr/day, 20 days) | ~$29-34 | Very affordable |
Scale note: 50 users × 8hr × 20 days = ~$240/mo + $10 API = $250/mo total
Note: 5-day max TTL means forgotten containers cost at most ~$3.60 each before auto-cleanup
| Risk | Impact | Mitigation |
|---|---|---|
| Copilot SDK stays in preview | Medium | Fall back to Copilot CLI direct; SDK is optional |
| ACI deprecated | Low | Container Apps is the successor; migration straightforward |
| Apple Containers delayed | Low | Docker Desktop continues to work fine locally |
| Security breach via agent | High | Firewall allowlist, scoped tokens, ephemeral containers |
| Cost runaway (orphaned containers) | Medium | Auto-cleanup after idle timeout; dashboard shows all active |
| ISP DPI blocking | Low | Already solved with nginx proxy on port 80; HTTPS will also solve |