July 2025 – Microsoft 365 US Public Sector Roadmap Newsletter
July 26, 2025Introducing API Management Support in the Azure SRE Agent
July 26, 2025Launch a secure, scalable Slack bot for Azure support tickets in minutes — no secrets in code, no manual admin steps, and fully aligned with modern cloud-native best practices.
This guide walks you through deploying the GitHub sample azure-support-slack-bot on Azure Container Apps, using managed identities, Key Vault, and scale-to-zero architecture that just works, whether you’re building from scratch or plugging into your existing DevOps flow.
Here’s what you’ll build:
- Zero-admin secrets management with Managed Identity + Key Vault
- RBAC-first access to Azure Support APIs
- A clean, local-first development workflow (with ngrok support)
- Slack integration using manifest-based setup
- Observability with App Insights + Log Analytics
- Scale from 0 to N replicas, with autoscaling baked in
And yes, all of this, without ever hardcoding a secret or exposing a public endpoint you didn’t intend to.
If you’re running lean and building fast, this bot is a solid foundation. It’s not just a cool demo — it’s a production-ready blueprint for any digital native team that wants to integrate Slack with Azure support in a secure, automated, and developer-friendly way.
1. What you’re building
Features:
- /azure-support slash command
- Auto-scaling from 0→N replicas based on HTTP load
- Zero secrets in code or environment variables
- Comprehensive logging and Azure RBAC integration
2. Why Azure Container Apps (ACA)?
When you’re building for speed, security, and scale without a huge ops team, Azure Container Apps (ACA) hits the sweet spot.
This Slack bot doesn’t need a full-blown cluster. It needs event-driven scale, zero-trust security, and built-in automation, and that’s exactly what ACA delivers. Here’s why ACA is a better fit than the usual suspects:
Azure Container Instances (ACI)
- Great for quick scripts or batch jobs , but no built-in ingress, TLS, scaling rules, or managed identities.
- ACA gives you all that out of the box, with production features and native integration with Key Vault, App Insights, and autoscaling.
Web App for Containers
- Web Apps are more suited for classic web hosting. You’ll hit limits with scaling flexibility, networking, and secret management.
- ACA gives you Kubernetes-grade scale and observability, without having to think about servers or patching.
Azure Kubernetes Service (AKS)
- Powerful, but heavy. You manage clusters, patch nodes, deal with autoscaler configs, ingress controllers, and more.
- ACA does the heavy lifting for you, zero node management, zero cluster maintenance.
- And here’s the kicker: AKS charges for the VM nodes 24/7, even when idle.
- ACA? Pay-per-request. When there’s no traffic, it scales to zero, and you don’t pay.
Cost Efficiency That Scales With You
For digital native teams, especially startups and growth-stage companies, ACA’s serverless pricing model is a game-changer:
- You scale from 0 to N replicas based on actual demand
- You only pay when your app is running
- No need to over-provision VMs or guess your future traffic
This means you can launch a support bot, an internal API, or a microservice without worrying about burning cash while it’s idle.
Built for These Teams
ACA is ideal for:
- Platform engineering teams who want secure templates, not snowflake infra
- DevOps-light teams who need autoscaling without managing YAML storms
- Growth-stage product squads rolling out bots, APIs, or event-driven services fast
- Startups who care about velocity, observability, and not hiring a full SRE team
Comparison table:
Platform | Best Fit | Where It Falls Short | Why ACA Wins |
---|---|---|---|
ACI | Short-lived scripts & jobs | No ingress, limited identity, lacks autoscaling | ACA supports scale-to-zero, secure access, and managed identity out of the box |
Web App | Traditional web hosting | Rigid scaling, fewer network/runtime controls | ACA offers greater flexibility and microservice patterns |
AKS | Complex, large-scale distributed apps | Operational overhead, always-on cost | ACA simplifies ops with managed scaling & lower cost |
ACA | Cloud-native APIs, internal tools, microservices | — | Built-in identity, ingress, scale-to-zero, lower total cost |
ACA is your serverless container platform when you want:
- TLS and ingress baked in
- GitHub Actions support out of the box
- Built-in support for Key Vault, managed identities, and auto-scaling
- Production-grade infra, without managing a single VM
If you’re moving fast and don’t want to build a platform just to run a bot, ACA is the move.
3. Prerequisites & verification
Required:
- Azure subscription with Contributor access
- Azure CLI ≥ 2.49.0 with `containerapp` extension
- Docker Desktop or equivalent
- Slack workspace with app creation permissions
- Python 3.8+ for local development
Optional:
- ngrok account for stable local testing URLs
Setup verification:
# Verify Azure CLI and login
az –version
az login
az account set –subscription
az extension add –name containerapp –upgrade
# Verify Docker and Python
docker –version
python –version
# Verify current user permissions
currentUserId=$(az ad signed-in-user show –query id -o tsv)
subscriptionId=$(az account show –query id -o tsv)
az role assignment list –assignee $currentUserId –scope “/subscriptions/$subscriptionId” –query “[].roleDefinitionName” -o table
4. Azure permissions setup
The repository requires specific Azure RBAC roles that are often missed:
# Get current subscription and user
subscriptionId=$(az account show –query id -o tsv)
currentUserId=$(az ad signed-in-user show –query id -o tsv)
# Support Request Contributor – Required to create/manage Azure support tickets
az role assignment create
–assignee $currentUserId
–role “Support Request Contributor”
–scope “/subscriptions/$subscriptionId”
# Reader – Required to list and view Azure resources in the bot
az role assignment create
–assignee $currentUserId
–role “Reader”
–scope “/subscriptions/$subscriptionId”
Why these roles are required:
- Support Request Contributor: Allows creating and managing Azure support tickets
- Reader: Allows the bot to list subscriptions, services, and resources in dropdown menus
5. Local development setup
5.1 Clone and initialize project
git clone https://github.com/ricmmartins/azure-support-slack-bot.git
cd azure-support-slack-bot
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Linux/macOS
# Install dependencies
pip install -r requirements.txt
# Create local environment file
cp .env-example .env
5.2 Create Slack app with manifest
Using the provided manifest is crucial for correct configuration:
- Visit Slack API Apps
- Click “Create New App” → “From a manifest“
- Choose YAML and paste the contents from slack_app_manifest.yaml:
display_information:
name: azure-support
description: Bot to help with Azure Support
background_color: “#35373d”
features:
app_home:
home_tab_enabled: true
messages_tab_enabled: false
messages_tab_read_only_enabled: true
bot_user:
display_name: azure-support
always_online: true
shortcuts:
– name: azure-support
type: global
callback_id: open_azure_support_ticket
description: Open an Azure Support Ticket
slash_commands:
– command: /azure-support
url: https://YOUR-DOMAIN-NAME/slack/events
description: Open an Azure Support Ticket
should_escape: false
oauth_config:
scopes:
bot:
– channels:history
– chat:write
– users:read
– users:read.email
– reactions:write
– commands
– app_mentions:read
– groups:read
– channels:read
settings:
event_subscriptions:
request_url: https://YOUR-DOMAIN-NAME/slack/events
bot_events:
– message.channels
interactivity:
is_enabled: true
request_url: https://YOUR-DOMAIN-NAME/slack/events
message_menu_options_url: https://YOUR-DOMAIN-NAME/slack/events
org_deploy_enabled: false
socket_mode_enabled: false
token_rotation_enabled: false
- Click Next → Create
- Copy the Signing Secret from Basic Information
- Important: Click “Install App” → “Install to Workspace” to generate the Bot User OAuth Token (xoxb-…)
- After installation, copy the Bot User OAuth Token from the OAuth & Permissions page
5.3 Local testing with ngrok
# Edit .env with your tokens (local development only)
# SLACK_SIGNING_SECRET=your-signing-secret-here
# SLACK_BOT_TOKEN=xoxb-your-bot-token-here
# Terminal 1: Start the Flask app
python app.py
Expected output:
INFO:azure_support:Azure credentials configured successfully
INFO:azure_support:Preloading subscriptions completed
⚡️ Bolt app is running on port 5000!# Terminal 2: Create ngrok tunnel
ngrok http 5000
Copy the https forwarding URL (e.g., https://abc123.ngrok-free.app)
5.4 Update Slack app manifest for local testing
This is the critical step that’s often missed:
- In your Slack app settings, go to App Manifest
- Replace ALL instances of YOUR-DOMAIN-NAME with your ngrok domain
- Example replacement:
# Before
request_url: https://YOUR-DOMAIN-NAME/slack/events
# After
request_url: https://abc123.ngrok-free.app/slack/events
- Click Save Changes
- Go to Install App and install it to your workspace
- Copy the Bot User OAuth Token (xoxb-…)
5.5 Test local integration
- Invite the bot to channels:
/invite azure-support
- Test the slash command:
/azure-support
- You should be able to see this screen:
4. Monitor logs:
# Check your Python terminal for incoming requests
INFO:azure_support:Opened modal for support request
6. Azure infrastructure setup
6.1 Define resource names
# Set consistent naming convention
RG=”rg-slack-support-prod”
LOCATION=”eastus”
ACR_NAME=”acrsupport$RANDOM” # Globally unique
ENV_NAME=”aca-slack-env”
APP_NAME=”slack-support-app”
KV_NAME=”kv-slack-$RANDOM”
UAMI_NAME=”id-slack-support”
LAW_NAME=”law-slack-support”
# Verify names are available
echo “ACR Name: $ACR_NAME”
echo “Key Vault: $KV_NAME”
6.2 Create resource group
az group create
–name $RG
–location $LOCATION
–tags environment=production project=slack-support
7. Container registry with security
7.1 Create Azure container registry
az acr create
–name $ACR_NAME
–resource-group $RG
–sku Standard
–admin-enabled false # Security: No admin credentials
7.2 Build and push image
# Login to ACR
az acr login –name $ACR_NAME
# Build and push
IMAGE_NAME=”$ACR_NAME.azurecr.io/azure-support-slack-bot:latest”
docker build -t $IMAGE_NAME .
docker push $IMAGE_NAME
# Verify image
az acr repository show
–name $ACR_NAME
–repository azure-support-slack-bot
8. Managed Identity and RBAC Setup
8.1 Create User-Assigned Managed Identity
az identity create
–name $UAMI_NAME
–resource-group $RG
–location $LOCATION
# Get identity details
UAMI_ID=$(az identity show –name $UAMI_NAME –resource-group $RG –query id -o tsv)
UAMI_PRINCIPAL_ID=$(az identity show –name $UAMI_NAME –resource-group $RG –query principalId -o tsv)
UAMI_CLIENT_ID=$(az identity show –name $UAMI_NAME –resource-group $RG –query clientId -o tsv)
8.2 Grant ACR pull permissions
ACR_ID=$(az acr show –name $ACR_NAME –resource-group $RG –query id -o tsv)
az role assignment create
–assignee $UAMI_PRINCIPAL_ID
–role “AcrPull”
–scope $ACR_ID
# Wait for role propagation
echo “Waiting 60 seconds for role assignment propagation…”
sleep 60
8.3 Grant Azure support API permissions
# Get subscription ID (in case it’s not set from earlier)
subscriptionId=$(az account show –query id -o tsv)
# Support Request Contributor for the managed identity
az role assignment create
–assignee $UAMI_PRINCIPAL_ID
–role “Support Request Contributor”
–scope “/subscriptions/$subscriptionId”
# Reader role for listing Azure resources
az role assignment create
–assignee $UAMI_PRINCIPAL_ID
–role “Reader”
–scope “/subscriptions/$subscriptionId”
# Verify the role assignments were created successfully
echo “Azure Support API permissions granted to managed identity”
az role assignment list
–assignee $UAMI_PRINCIPAL_ID
–query “[].{Role:roleDefinitionName,Scope:scope}” -o table
9. Azure Key Vault Setup
9.1 Create Key Vault with RBAC
az keyvault create
–name $KV_NAME
–resource-group $RG
–location $LOCATION
–enable-rbac-authorization true
–retention-days 7
9.2 Grant Key Vault permissions
# Get current user and Key Vault scope
USER_PRINCIPAL_ID=$(az ad signed-in-user show –query id -o tsv)
KV_SCOPE=$(az keyvault show –name $KV_NAME –resource-group $RG –query id -o tsv)
# Grant admin access to current user
az role assignment create
–assignee $USER_PRINCIPAL_ID
–role “Key Vault Administrator”
–scope $KV_SCOPE
# Grant read access to managed identity
az role assignment create
–assignee $UAMI_PRINCIPAL_ID
–role “Key Vault Secrets User”
–scope $KV_SCOPE
# Wait for propagation
sleep 30
9.3 Store secrets
# Store Slack secrets (replace with your actual values)
echo “Enter your Slack Bot Token (xoxb-…):”
read -s SLACK_BOT_TOKEN
echo “Enter your Slack Signing Secret:”
read -s SLACK_SIGNING_SECRET
az keyvault secret set
–vault-name $KV_NAME
–name “slack-bot-token”
–value “$SLACK_BOT_TOKEN”
az keyvault secret set
–vault-name $KV_NAME
–name “slack-signing-secret”
–value “$SLACK_SIGNING_SECRET”
# Verify secrets are stored
az keyvault secret list –vault-name $KV_NAME –query “[].name” -o table
10. Container Apps environment
10.1 Create Log Analytics Workspace
az monitor log-analytics workspace create
–workspace-name $LAW_NAME
–resource-group $RG
–location $LOCATION
# Get workspace details
LAW_CUSTOMER_ID=$(az monitor log-analytics workspace show
–workspace-name $LAW_NAME
–resource-group $RG
–query customerId -o tsv)
LAW_SHARED_KEY=$(az monitor log-analytics workspace get-shared-keys
–workspace-name $LAW_NAME
–resource-group $RG
–query primarySharedKey -o tsv)
10.2 Create Container Apps environment
az containerapp env create
–name $ENV_NAME
–resource-group $RG
–location $LOCATION
–logs-workspace-id $LAW_CUSTOMER_ID
–logs-workspace-key $LAW_SHARED_KEY
11. Deploy Container App with security
11.1 Create Container App
az containerapp create
–name $APP_NAME
–resource-group $RG
–environment $ENV_NAME
–image $IMAGE_NAME
–target-port 5000
–ingress external
–registry-server “$ACR_NAME.azurecr.io”
–user-assigned $UAMI_ID
–min-replicas 1
–max-replicas 10
–cpu 0.5
–memory 1Gi
11.2 Configure Key Vault secret references
# Create secret references to Key Vault
az containerapp secret set
–name $APP_NAME
–resource-group $RG
–secrets
“slack-bot-token=keyvaultref:https://$KV_NAME.vault.azure.net/secrets/slack-bot-token,identityref:$UAMI_ID”
“slack-signing-secret=keyvaultref:https://$KV_NAME.vault.azure.net/secrets/slack-signing-secret,identityref:$UAMI_ID”
11.3 Configure environment variables
az containerapp update
–name $APP_NAME
–resource-group $RG
–set-env-vars
“SLACK_BOT_TOKEN=secretref:slack-bot-token”
“SLACK_SIGNING_SECRET=secretref:slack-signing-secret”
“AZURE_CLIENT_ID=$UAMI_CLIENT_ID”
“PORT=5000”
11.4 Configure scaling rules
az containerapp update
–name $APP_NAME
–resource-group $RG
–scale-rule-name “http-rule”
–scale-rule-type “http”
–scale-rule-http-concurrency 50
–min-replicas 0
–max-replicas 10
12. Production configuration
12.1 Get application URL
APP_FQDN=$(az containerapp show
–name $APP_NAME
–resource-group $RG
–query properties.configuration.ingress.fqdn -o tsv)
APP_URL=”https://$APP_FQDN”
echo “Production URL: $APP_URL/slack/events”
12.2 Update Slack app manifest for production
Critical: Replace ngrok URLs with production URLs:
- In your Slack app settings, go to App Manifest
- Replace all ngrok URLs with your Azure Container Apps URL:
settings:
event_subscriptions:
request_url: https://your-app-fqdn.region.azurecontainerapps.io/slack/events
interactivity:
is_enabled: true
request_url: https://your-app-fqdn.region.azurecontainerapps.io/slack/events
message_menu_options_url: https://your-app-fqdn.region.azurecontainerapps.io/slack/events - Click Save Changes
- Reinstall the app
Critical: URL Verification Step
After updating your Slack App Manifest with the production URL, Slack will attempt to verify the new endpoint. This verification process is mandatory and must succeed before your bot will work in production.
What happens during verification:
- Slack sends a POST request to your new URL (https://your-app-fqdn.region.azurecontainerapps.io/slack/events)
- The request contains a challenge parameter that your Flask app must echo back
- If verification fails, Slack will reject the manifest changes
Common verification failures:
- Container App not running: Ensure your Azure Container App is deployed and healthy
- Wrong URL format: Must end with /slack/events exactly
- HTTPS required: Slack only accepts HTTPS endpoints (Container Apps provides this automatically)
- Timeout issues: Container App must respond within Slack’s timeout window
12.3 Bot installation and invitation
Required Post-Deployment Steps:
- Slack App Manifest updated with production URL
- Reinstall the bot in your Slack workspace
- Invite the bot to channels: /invite @ azure-support
- Test with: /azure-support command
13. Testing and validation
13.1 Health and connectivity checks
# Test basic connectivity (note: this will return 404 since the app has no root endpoint handler)
curl -f “$APP_URL/” || echo “Expected 404 – app only handles /slack/events endpoint”
# Check container app status
az containerapp show
–name $APP_NAME
–resource-group $RG
–query properties.provisioningState
# Check logs
az containerapp logs show
–name $APP_NAME
–resource-group $RG
–follow
13.2 Functional testing
- Test Slack integration:
/azure-support
Complete workflow:
Fill out the support ticket modal completely
Submit the form
Verify ticket appears in Azure Portal → Help + Support
14. Production observability
14.1 Application Insights Integration
# Create Application Insights
APPINSIGHTS_NAME=”ai-slack-support”
az monitor app-insights component create
–app $APPINSIGHTS_NAME
–location $LOCATION
–resource-group $RG
–workspace $LAW_NAME
# Get instrumentation key
APPINSIGHTS_KEY=$(az monitor app-insights component show
–app $APPINSIGHTS_NAME
–resource-group $RG
–query instrumentationKey -o tsv)
# Add to container app
az containerapp update
–name $APP_NAME
–resource-group $RG
–set-env-vars
“APPLICATIONINSIGHTS_INSTRUMENTATION_KEY=$APPINSIGHTS_KEY”
14.2 Monitoring and alerts
# Create alert for container app failures
az monitor metrics alert create
–name “SlackBot-ContainerFailures”
–resource-group $RG
–scopes “/subscriptions/$subscriptionId/resourceGroups/$RG/providers/Microsoft.App/containerApps/$APP_NAME”
–condition “avg Requests < 1"
–description "Slack bot container app is not receiving requests"
–window-size 5m
–evaluation-frequency 1m
# Create alert for Key Vault access failures
az monitor metrics alert create
–name "SlackBot-KeyVaultAccess"
–resource-group $RG
–scopes "/subscriptions/$subscriptionId/resourceGroups/$RG/providers/Microsoft.KeyVault/vaults/$KV_NAME"
–condition "total ServiceApiHit < 1"
–description "Slack bot unable to access Key Vault secrets"
–target-resource-type "Microsoft.KeyVault/vaults"
–target-resource-region $LOCATION
–window-size 5m
–evaluation-frequency 1m
15. Security Hardening Checklist
Authentication & Authorization
- User-Assigned Managed Identity for all Azure resources
- RBAC-based access (no admin credentials)
- Key Vault for all secrets with proper role assignments
- Azure Support API permissions (Support Request Contributor + Reader)
- Least-privilege permissions
Network Security
- HTTPS-only ingress (Container Apps provides TLS termination)
- No public admin endpoints
- Container registry private access via managed identity
Operational Security
- Comprehensive logging with Log Analytics
- Health monitoring and alerting
- Automated vulnerability scanning (ACR)
- Secret rotation capability via Key Vault
Application Security
- No secrets in code or environment variables
- Slack request signature verification
- Input validation and sanitization (built into Slack Bolt framework)
16. Complete deployment script
Before running the one-command deployment script, ensure you’ve completed sections 3 and 4 above, then verify:
1. You’re in the repository root directory
pwd # Should end with: azure-support-slack-bot
ls # Should show: Dockerfile, requirements.txt, app.py
2. Docker is ready for building
docker ps # Should not show permission errors
3. You have your Slack tokens ready
Now, go from zero to production Slack bot in one command. Save this as deploy-slack-bot.sh for one-command deployment:
#!/bin/bash
set -euo pipefail
# Check parameters
if [ $# -ne 3 ]; then
echo “Usage: $0 ”
exit 1
fi
SUBSCRIPTION_ID=”$1″
SLACK_BOT_TOKEN=”$2″
SLACK_SIGNING_SECRET=”$3″
# Configuration – modern naming conventions
RG=”rg-slack-support-prod”
LOCATION=”eastus”
ACR_NAME=”acrsupport$RANDOM”
ENV_NAME=”aca-slack-env”
APP_NAME=”slack-support-app”
KV_NAME=”kv-slack-$RANDOM”
UAMI_NAME=”id-slack-support”
LAW_NAME=”law-slack-support”
echo “🚀 Deploying secure Azure Support Slack Bot…”
# Set subscription context
az account set –subscription “$SUBSCRIPTION_ID”
# Create resource group
az group create –name $RG –location $LOCATION –tags environment=production project=slack-support
# Create ACR with security defaults
az acr create –name $ACR_NAME –resource-group $RG –sku Standard –admin-enabled false
az acr login –name $ACR_NAME
# Build and push image
IMAGE_NAME=”$ACR_NAME.azurecr.io/azure-support-slack-bot:latest”
docker build -t $IMAGE_NAME .
docker push $IMAGE_NAME
# Create managed identity – zero-trust foundation
az identity create –name $UAMI_NAME –resource-group $RG –location $LOCATION
UAMI_ID=$(az identity show –name $UAMI_NAME –resource-group $RG –query id -o tsv)
UAMI_PRINCIPAL_ID=$(az identity show –name $UAMI_NAME –resource-group $RG –query principalId -o tsv)
UAMI_CLIENT_ID=$(az identity show –name $UAMI_NAME –resource-group $RG –query clientId -o tsv)
# Grant ACR pull permissions
ACR_ID=$(az acr show –name $ACR_NAME –resource-group $RG –query id -o tsv)
az role assignment create –assignee $UAMI_PRINCIPAL_ID –role “AcrPull” –scope $ACR_ID
# Grant Azure Support API permissions – least privilege
subscriptionId=”$SUBSCRIPTION_ID”
az role assignment create –assignee $UAMI_PRINCIPAL_ID –role “Support Request Contributor” –scope “/subscriptions/$subscriptionId”
az role assignment create –assignee $UAMI_PRINCIPAL_ID –role “Reader” –scope “/subscriptions/$subscriptionId”
echo “Azure Support API permissions granted to managed identity”
# Create Key Vault with RBAC (no access policies)
az keyvault create –name $KV_NAME –resource-group $RG –location $LOCATION –enable-rbac-authorization true –retention-days 7
KV_SCOPE=$(az keyvault show –name $KV_NAME –resource-group $RG –query id -o tsv)
# Grant Key Vault permissions
USER_PRINCIPAL_ID=$(az ad signed-in-user show –query id -o tsv)
az role assignment create –assignee $USER_PRINCIPAL_ID –role “Key Vault Administrator” –scope $KV_SCOPE
az role assignment create –assignee $UAMI_PRINCIPAL_ID –role “Key Vault Secrets User” –scope $KV_SCOPE
# Wait for RBAC propagation
sleep 60
# Store secrets securely
az keyvault secret set –vault-name $KV_NAME –name “slack-bot-token” –value “$SLACK_BOT_TOKEN”
az keyvault secret set –vault-name $KV_NAME –name “slack-signing-secret” –value “$SLACK_SIGNING_SECRET”
# Create observability foundation
az monitor log-analytics workspace create –workspace-name $LAW_NAME –resource-group $RG –location $LOCATION
LAW_CUSTOMER_ID=$(az monitor log-analytics workspace show –workspace-name $LAW_NAME –resource-group $RG –query customerId -o tsv)
LAW_SHARED_KEY=$(az monitor log-analytics workspace get-shared-keys –workspace-name $LAW_NAME –resource-group $RG –query primarySharedKey -o tsv)
# Create Container Apps environment
az containerapp env create –name $ENV_NAME –resource-group $RG –location $LOCATION –logs-workspace-id $LAW_CUSTOMER_ID –logs-workspace-key $LAW_SHARED_KEY
# Deploy Container App with scale-to-zero
az containerapp create
–name $APP_NAME
–resource-group $RG
–environment $ENV_NAME
–image $IMAGE_NAME
–target-port 5000
–ingress external
–registry-server “$ACR_NAME.azurecr.io”
–user-assigned $UAMI_ID
–min-replicas 0
–max-replicas 10
–cpu 0.5
–memory 1Gi
# Configure Key Vault secret references
az containerapp secret set –name $APP_NAME –resource-group $RG –secrets
“slack-bot-token=keyvaultref:https://$KV_NAME.vault.azure.net/secrets/slack-bot-token,identityref:$UAMI_ID”
“slack-signing-secret=keyvaultref:https://$KV_NAME.vault.azure.net/secrets/slack-signing-secret,identityref:$UAMI_ID”
# Configure environment variables
az containerapp update –name $APP_NAME –resource-group $RG –set-env-vars
“SLACK_BOT_TOKEN=secretref:slack-bot-token”
“SLACK_SIGNING_SECRET=secretref:slack-signing-secret”
“AZURE_CLIENT_ID=$UAMI_CLIENT_ID”
“PORT=5000”
# Configure HTTP-based autoscaling
az containerapp update –name $APP_NAME –resource-group $RG
–scale-rule-name “http-requests”
–scale-rule-type “http”
–scale-rule-http-concurrency 50
–min-replicas 0
–max-replicas 10
# Get deployment results
APP_FQDN=$(az containerapp show –name $APP_NAME –resource-group $RG –query properties.configuration.ingress.fqdn -o tsv)
echo “”
echo “🎉 Deployment Complete!”
echo “”
echo “Slack Webhook URL: https://$APP_FQDN/slack/events”
echo ” Resource Group: $RG”
echo ” Key Vault: $KV_NAME”
echo ” ACR: $ACR_NAME”
echo “”
echo ” Next Steps:”
echo “1. Update your Slack App Manifest with: https://$APP_FQDN/slack/events”
echo “2. Reinstall the Slack app in your workspace”
echo “3. Invite the bot to channels: /invite -support”
echo “4. Test with: /azure-support”
echo “”
echo “Monitor: az containerapp logs show -n $APP_NAME -g $RG –follow”
echo “Debug: az containerapp show -n $APP_NAME -g $RG –query properties.provisioningState”
Usage:
chmod +x deploy-slack-bot.sh
./deploy-slack-bot.sh “your-subscription-id” “xoxb-your-bot-token” “your-signing-secret”
Cost Expectations
- Scale-to-zero architecture = minimal compute costs
- Base charges: Key Vault ($0.03/day), Log Analytics ($2.30/GB ingested)
- Container Apps: Only charges when processing requests (true serverless)
Deployment Notes
- Script creates globally unique resource names using $RANDOM
- Takes ~8-12 minutes due to RBAC propagation delays
- After deployment, update your Slack App Manifest with the production URL
Post-Deployment Steps
- Update Slack App Manifest with your Azure Container Apps URL
- Reinstall the Slack app (required for URL changes)
- Test with /azure-support or the global shortcut
17. Cleanup
When you’re ready to remove all resources:
# Delete resource group (removes all resources)
az group delete –name $RG –yes –no-wait
# Purge Key Vault (if purge protection was enabled)
az keyvault purge –name $KV_NAME –location $LOCATION
18. You’re live, what’s next?
You’ve just deployed a production-grade Slack bot for Azure Support using a modern, secure-by-default architecture — no manual secrets, no patchy scripts, no guesswork.
What you now have is more than a bot — it’s a template for how digital native teams should approach platform automation on Azure:
- Zero-trust foundation with managed identities + Key Vault
- Dev-first workflows for local testing and CI/CD
- Scale-to-zero architecture on Azure Container Apps
- Built-in observability with Log Analytics and App Insights
- RBAC-controlled access to support APIs — no over-permissioned service principals
- End-to-end automation via GitHub Actions
This isn’t just a bot — it’s a pattern. A way to wire your internal tools to your platform securely, scalably, and with full auditability from day one.
This guide was made for fast-moving teams who prefer CLI over click-ops and automation over tribal knowledge. If you’re building platforms, bots, or tools to empower your engineering org, this is a foundation you can trust.