Blog Post

Startups at Microsoft
17 MIN READ

Azure Support Slack Bot on Azure Container Apps: Production-ready guide

rmmartins's avatar
rmmartins
Icon for Microsoft rankMicrosoft
Jul 25, 2025

Launch 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:

PlatformBest FitWhere It Falls ShortWhy ACA Wins
ACIShort-lived scripts & jobsNo ingress, limited identity, lacks autoscalingACA supports scale-to-zero, secure access, and managed identity out of the box
Web AppTraditional web hostingRigid scaling, fewer network/runtime controlsACA offers greater flexibility and microservice patterns
AKSComplex, large-scale distributed appsOperational overhead, always-on costACA simplifies ops with managed scaling & lower cost
ACACloud-native APIs, internal tools, microservicesBuilt-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 <your-subscription-id>
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/Azure-Samples/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:

  1. Visit Slack API Apps
  2. Click "Create New App" → "From a manifest"
  3. Choose YAML and paste the contents from slack_app_manifest.yaml:
  4. Click Next → Create
  5. Copy the Signing Secret from Basic Information
  6. Important: Click "Install App" → "Install to Workspace" to generate the Bot User OAuth Token (xoxb-...)
  7. 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:

  1. In your Slack app settings, go to App Manifest
  2. Replace ALL instances of YOUR-DOMAIN-NAME with your ngrok domain
  3. Example replacement:
   # Before
   request_url: https://YOUR-DOMAIN-NAME/slack/events
   
   # After  
   request_url: https://abc123.ngrok-free.app/slack/events
  1. Click Save Changes
  2. Go to Install App and install it to your workspace
  3. Copy the Bot User OAuth Token (xoxb-...)

5.5 Test local integration

  1. Invite the bot to channels:  
/invite azure-support
  1. Test the slash command:
 /azure-support
  1. 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:

  1. In your Slack app settings, go to App Manifest
  2. 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
  3. Click Save Changes
  4. 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:

  1. Container App not running: Ensure your Azure Container App is deployed and healthy
  2. Wrong URL format: Must end with /slack/events exactly
  3. HTTPS required: Slack only accepts HTTPS endpoints (Container Apps provides this automatically)
  4. Timeout issues: Container App must respond within Slack's timeout window

12.3 Bot installation and invitation

Required Post-Deployment Steps:

  1. Slack App Manifest updated with production URL
  2. Reinstall the bot in your Slack workspace
  3. Invite the bot to channels: /invite @ azure-support 
  4. 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 (details below)

    • Submit the form

    • Verify ticket appears in Azure Portal → Help + Support

13.3 Opening the support request

When you open the support request form, you’ll see a few fields that need your attention:

  • Subject: Think of this as your headline. Keep it short and clear
  • Problem Details: Here’s your chance to explain what’s going wrong. Be specific! The more details, the better.
  • Azure Subscription, Service, Problem Type, and Resource: Select the right options from the dropdown menus. This helps the support team route your ticket to the right experts.

 

 

 

 

 

 

 

 

You’ll notice options for advanced diagnostic info. If you’re not sure, just say “Yes” (it’s recommended). Set the severity, if it’s a minor issue, pick “Minimal impact.” And choose how you’d like to be contacted (email is usually easiest). Make sure your name and email are correct. If you want someone else to get updates, add their email too.

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Once you’ve filled everything out, click Submit. You’ll see a confirmation message, your ticket is on its way!

 

 

 

 

If you chose a Slack channel, you’ll get a message like this:

 

 

 

 

 

You’ll also get a link to view your ticket in the Azure portal, along an e-mail with all the details you provided.

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 <subscription-id> <slack-bot-token> <slack-signing-secret>"
    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.

Updated Sep 04, 2025
Version 8.0
No CommentsBe the first to comment