fox-send/docs/azure.md

5.4 KiB

Deployment to Azure

Minimal deployment

This document describes how to do a minimal deployment of Send in Azure

Resources

  • A Storage Account with a least one container created (Standard V2, Cool access tier)
  • An Azure Redis Cache instance (Basic C0)
  • An Azure Container Apps Environment (to host Send in a "serverless" manner )

The "Send" application will be hosted in a Azure Container App, which will allow it to scale up and down. This will also allow to scale to 0 instances, thus preventing any cost when the app is not used.

The Redis cache used is the smallest available. Although redis could be hosted in any generic container solution, this "PaaS" approach is the best to prevent data loss.

The storage Account used is "Cold", which will increase a bit latency but once again reduce total cost. As this doesn't decrease download speed, this should be plenty sufficient for this app.

Authentication

Using the identity module, multiples ways to handle authentication are provided. In a nutshell :

  • On Azure, resources will use their Managed Identities, to minimise the use of credentials (Redis still requires it).
  • While developing, it will use the Azure CLI
  • On more complex scenarios (multi-cloud, mix of on premises and cloud), you'll have to revert to using Service principals

Using Azure CLI

# Parameters
# Resource group name
RG_NAME="mozilla-send-on-azure"
# Az region to deploy inyo
LOC="westeurope"
# Send container image to deploy
IMG="registry.gitlab.com/timvisee/send:latest"

################################
#           Constants          #
################################
# Some resources names cannot contain hyphens or spaces
SAFE_RG_NAME=$(sed 's/-//g; s/\s+//g' <<<"$RG_NAME")
ST_NAME="${SAFE_RG_NAME}sa"
ST_CONTAINER_NAME="files"
ST_ACCESS="Cool"

# Basic redis
REDIS_NAME="$RG_NAME-cache"
REDIS_SKU="basic"
REDIS_SIZE="C0"

ENV_NAME="$RG_NAME-aca-env"

SEND_NAME="send"
# Scale out properties. Allow to scale to 0
# By default, sclae out will occur with traffic
SEND_MIN_REPLICAS=0
SEND_MAX_REPLICAS=10
# Spec of a single send instance
SEND_CPU=0.25
SEND_MEMORY="0.5Gi"

################################
#           Script             #
################################
az group create --name $RG_NAME --location $LOC

# Init the backing services

#   Storage account
az storage account create -n $ST_NAME -g $RG_NAME -l $LOC \
    --sku "Standard_LRS" --access-tier $ST_ACCESS

az storage container create -n $ST_CONTAINER_NAME --account-name $ST_NAME \
    --public-access "off"

#   Redis (This can take a good 15 minutes )
az redis create --name $REDIS_NAME --resource-group $RG_NAME --location "$LOC" \
    --sku $REDIS_SKU --vm-size $REDIS_SIZE \
    --enable-non-ssl-port \
    --mi-system-assigned
redisKey=`az redis list-keys -g $RG_NAME -n $REDIS_NAME | jq -r '.primaryKey'`


# Next, create the send app itself
az containerapp env create --name $ENV_NAME -g $RG_NAME --location $LOC
az containerapp create -n $SEND_NAME -g "$RG_NAME" \
    --image "$IMG" --environment "$ENV_NAME" \
    --cpu $SEND_CPU --memory $SEND_MEMORY \
    --min-replicas $SEND_MIN_REPLICAS --max-replicas $SEND_MAX_REPLICAS \
    --ingress external --target-port 1443 \
    --secrets rediskey=$redisKey \
    --system-assigned \
    --env-vars \
        REDIS_HOST=$REDIS_NAME.redis.cache.windows.net \
        REDIS_PASSWORD=secretref:rediskey \
        AZ_STORAGE_URL=https://$ST_NAME.blob.core.windows.net \
        AZ_STORAGE_CONTAINER=files \
        DETECT_BASE_URL=true


# Authorize the send app to access the storage account through its managed identity
sendIdentityId=`az containerapp identity show -n $SEND_NAME -g $RG_NAME | jq -r '.principalId'`
stIdentity=`az storage account show -n $ST_NAME -g $RG_NAME --query id --output tsv`
az role assignment create --assignee "$sendIdentityId" \
--role "Storage Blob Data Contributor" \
--scope "$stIdentity"

sendHost=`az containerapp ingress show -g $RG_NAME -n $SEND_NAME | jq -r '.fqdn'`
echo "Send is up on https://$sendHost"

Send is now fully deployed, and you should be able to access it with the url echoed by the script

Going further

About security

This minimal deployment is not fully secure. Although all the resources are configured to reject any public connections attempts, connections from Azure networks will still go through. This isn't a real problem for the backing storage, as only the "send" application is authorized to read/write to the Storage account through its managed identity. Redis on the other hand is using credentials, and could be vulnerable to a bruteforce attack from another Azure network.

To prevent this :

This would ensure that only the "send" app is able to resolve Redis' name.

This would however add a substantial amount to the total cost, which is why this is not in the terraform gist above.