| name | backstage-deployment |
| description | Deploys the upstream open-source Backstage developer portal on Azure AKS or locally via Docker Desktop. USE FOR: deploy Backstage, Backstage on AKS, Backstage local Docker, Backstage Helm chart, Backstage PostgreSQL, Backstage ACR image, Backstage GitHub OAuth, Microsoft Entra ID auth, GitHub Enterprise Managed Users. DO NOT USE FOR: full platform orchestration (use deploy-orchestration), Azure infrastructure provisioning (use @azure-portal-deploy). |
Backstage Deployment Skill
Deploys the upstream open-source Backstage developer portal on Azure AKS or locally via Docker Desktop.
Official Docs via MCP: Use backstagedocs_* tools from the mcp-ecosystem for live official documentation:
backstagedocs_get_page slug=deployment/docker — Docker deployment guide
backstagedocs_get_page slug=deployment/k8s — Kubernetes deployment guide
backstagedocs_get_page slug=auth/github/provider — GitHub auth provider docs
backstagedocs_get_page slug=auth/microsoft/provider — Microsoft auth provider docs
backstagedocs_search query="app-config" — search configuration docs
Scope
| Aspect | Detail |
|---|
| Platform | Azure AKS (production) or Docker Desktop + kind (local) |
| Region | East US 2 (eastus2) — PostgreSQL in Central US (centralus) |
| Image | Custom-built from backstage/ directory, stored in ACR |
| Auth | GitHub OAuth, Microsoft Entra ID, and Guest (dev only) |
| Catalog | H1 Foundation + H2 Enhancement Golden Paths pre-loaded |
| Used by | @backstage-expert, @deploy |
Azure MVP Deployment (rg-<platform>-<env>)
Resources
| Resource | Name | Type | Location |
|---|
| AKS | aks-<platform>-<env> | 2x Standard_B2s | eastus2 |
| ACR | <acr-name> | Basic | eastus2 |
| Key Vault | kv-<platform>-<env> | RBAC-enabled | eastus2 |
| PostgreSQL | pg-<platform>-<env> | Flexible B1ms v16 | centralus |
| Redis | redis-<platform>-<env> | Azure Managed B0 | eastus2 |
| AI Services | ai-<platform>-<env> | S0 (GPT-4o + Embeddings) | eastus2 |
| Log Analytics | law-<platform>-<env> | PerGB2018 | eastus2 |
| App Insights | appi-<platform>-<env> | Application Insights | eastus2 |
| Managed Prometheus | prometheus-<platform>-<env> | Azure Monitor Workspace | eastus2 |
| Managed Grafana | grafana-<platform>-<env> | Standard tier | eastus2 |
| Monitor | Container Insights + Metrics | Enabled on AKS | eastus2 |
| Defender | Containers + KV + OSS DB | Standard tier | subscription |
| Action Group | ag-<platform>-sre | Webhook → GitHub | eastus2 |
| Metric Alerts | CPU > 85%, Memory > 85% | Severity 2 | global |
Service Principal
| Name | Roles |
|---|
sp-<platform>-<env> | Contributor (RG), KV Secrets User, AI OpenAI User |
Kubernetes Components
| Horizon | Namespace | Component |
|---|
| H1 | ingress-nginx | NGINX Ingress + Azure LB |
| H1 | cert-manager | cert-manager v1.14 |
| H1 | gatekeeper-system | OPA Gatekeeper v3.14 |
| H1 | external-secrets | ESO v2.0 → Key Vault |
| H2 | argocd | ArgoCD v2.10 |
| H2 | monitoring | Prometheus + Grafana + Alertmanager |
| H2 | backstage | Backstage (custom ACR image v1.0.0) |
External URLs
| Service | URL |
|---|
| Backstage | http://backstage.<LB-IP>.sslip.io |
| ArgoCD | http://argocd.<LB-IP>.sslip.io |
| Grafana | http://grafana.<LB-IP>.sslip.io |
| Prometheus | http://prometheus.<LB-IP>.sslip.io |
| Alertmanager | http://alertmanager.<LB-IP>.sslip.io |
1. Prerequisites
CLI Tools
az --version
terraform --version
kubectl version
helm version
docker --version
node --version
yarn --version
gh auth status
Azure
az login
az account set --subscription "<SUBSCRIPTION_ID>"
az provider register -n Microsoft.ContainerService
az provider register -n Microsoft.KeyVault
az provider register -n Microsoft.Storage
Configuration Files
| File | Purpose |
|---|
backstage/app-config.yaml | Development config |
backstage/app-config.production.yaml | Production config (baked into image) |
2. Azure AKS Deployment
Terraform
cd terraform
terraform init -backend-config=environments/dev-backend.hcl
terraform plan \
-var-file=environments/dev.tfvars \
-var="portal_name=<client-portal-name>" \
-var="location=centralus"
terraform apply \
-var-file=environments/dev.tfvars \
-var="portal_name=<client-portal-name>" \
-var="location=centralus"
Module: terraform/modules/backstage/
Provisions:
- Helm release for
backstage/backstage chart
- Custom image from ACR
- PostgreSQL Flexible Server integration
- GitHub App secret in Key Vault
- Ingress with TLS (cert-manager)
Region Validation
variable "location" {
type = string
validation {
condition = contains(["centralus", "eastus"], var.location)
error_message = "Only Central US and East US are supported."
}
}
4. GitHub App Setup
For AUTH_PROVIDER=entra with GITHUB_IDENTITY_MODE=enterprise-managed-users, Entra ID handles user sign-in. GitHub App credentials are still required for technical GitHub integration: catalog sync, scaffolder writes, Actions, PRs, Codespaces, packages, and AI Impact metrics.
Create GitHub App
./scripts/setup-github-app.sh --target backstage --org <GITHUB_ORG>
Manual Creation
- Go to
https://github.com/organizations/<ORG>/settings/apps/new
- Set:
- Homepage URL:
https://<portal-url>
- Callback URL:
https://<portal-url>/api/auth/github/handler/frame
- Webhook: Disable (not needed for auth)
- Permissions:
contents: read
metadata: read
pull_requests: write
members: read
- Generate Private Key (.pem file)
- Note: App ID, Client ID, Client Secret
Configure in Backstage
Environment variables:
GITHUB_APP_ID=<numeric-app-id>
GITHUB_APP_CLIENT_ID=<client-id>
GITHUB_APP_CLIENT_SECRET=<client-secret>
GITHUB_APP_PRIVATE_KEY=<contents-of-pem-file>
Microsoft Entra ID Sign-In
Environment variables:
AUTH_PROVIDER=entra
GITHUB_IDENTITY_MODE=enterprise-managed-users
ENTRA_TENANT_ID=<tenant-id>
ENTRA_CLIENT_ID=<app-registration-client-id>
ENTRA_CLIENT_SECRET=<client-secret>
Backstage callback URL:
https://<portal-url>/api/auth/microsoft/handler/frame
5. Golden Path Templates
Valid Templates (YAML-compatible with Backstage parser)
| Template | Horizon | Description |
|---|
api-microservice | H2 | FastAPI microservice with PostgreSQL |
ado-to-github-migration | H2 | Azure DevOps to GitHub migration |
copilot-extension | H3 | GitHub Copilot Extension |
rag-application | H3 | RAG application with Azure AI |
Registration
Templates are registered via catalog.locations in app-config.production.yaml:
catalog:
locations:
- type: url
target: https://github.com/<org>/<repo>/blob/main/golden-paths/<horizon>/<template>/template.yaml
rules:
- allow: [Template]
6. Codespaces Integration
Each Golden Path template skeleton includes a .devcontainer/devcontainer.json that configures:
- Base image with required SDKs
- VS Code extensions for the template type
- Port forwarding for development servers
- Post-create setup scripts
Example: Python Microservice
{
"name": "Python Microservice",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/azure-cli:1": {},
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {}
},
"customizations": {
"vscode": {
"extensions": ["ms-python.python", "ms-python.pylint", "redhat.vscode-yaml"]
}
},
"postCreateCommand": "pip install -r requirements.txt",
"forwardPorts": [8000]
}
7. Troubleshooting
Backstage pod not starting
kubectl logs -n backstage -l app.kubernetes.io/name=backstage --tail=50
kubectl describe pod -n backstage -l app.kubernetes.io/name=backstage
Templates not loading
kubectl logs -n backstage -l app.kubernetes.io/name=backstage | grep 'YAML error'
kubectl exec -n backstage deploy/backstage -- cat /app/app-config.production.yaml | grep -A 2 'locations'
GitHub auth not working
kubectl exec -n backstage deploy/backstage -- \
node -e "fetch('http://localhost:7007/api/auth/github/start?env=development',{redirect:'manual'}).then(r=>console.log(r.status))"
Database connection
kubectl exec -n backstage deploy/backstage -- \
node -e "fetch('http://localhost:7007/.backstage/health/v1/readiness').then(r=>console.log(r.status))"