Skip to main content

Secure Deployment of Application with Azure Container Instances and Caddy

ยท 4 min read
Paul Greenberg

This tutorial walks you through deploying applications protected by caddy security app, hosted by Caddy web server via Azure Container Instances (ACI) service.

Table of Contentsโ€‹

Azure Configurationโ€‹

Define environment variables. Change app to something else, e.g. xyz.

export ACI_RG_NAME=app-auth-rg-001
export ACI_ST_ACCOUNT_NAME=appauthst001
export ACI_LOCATION=eastus
export ACI_ST_SHARE_NAME=appauthstsh001

Next, create resource group:

az group create --name "${ACI_RG_NAME}" --location eastus

Add Azure File Shareโ€‹

References:

Register a provider using your subscription ID:

az provider register -n Microsoft.Storage --subscription 91cd6b60-64b7-46e2-bffb-952352196549

Create a storage account:

az storage account create --resource-group "${ACI_RG_NAME}" --name "${ACI_ST_ACCOUNT_NAME}" --location "${ACI_LOCATION}" --sku Standard_LRS

Review the newly created account:

az storage account list | jq -r '.[]

Create a file share:

az storage share create --name "${ACI_ST_SHARE_NAME}" --account-name "${ACI_ST_ACCOUNT_NAME}"

Copy Files to Azure File Shareโ€‹

Navigate to Resource Group, then browse to Storage Share associated with it.

image

Next, open the share, click "Browse" and add the following nested directories. The app-auth-ci-001 is the name of the Caddy instance (ACI container).

  • caddy,
    • app-auth-ci-001
      • config

image

Next, browse to caddy/app-auth-ci-001/config and upload Caddyfile with the following content.

image

{
http_port 80
https_port 443
admin off
debug

order authenticate before respond
order authorize before basicauth

security {
local identity store localdb {
realm local
path {env.LOCAL_DATA_PATH}caddy/app-auth-ci-001/userdb/users.json
user webadmin {
name Webmaster
email webadmin@localhost.localdomain
# echo -n "App@2f4cb79053be" | bcrypt-cli -c 10
password "$2a$10$JqJEf2pra4hIkw4CSDePoOfIoXVUFwSn6pJie6m02MUP7YGQVPQAi" overwrite
roles "authp/admin" "authp/user"
}
user jsmith {
name John Smith
email jsmith@localhost.localdomain
# password {env.USER_JSMITH_SECRET}
password "App@2f4cb79053be"
roles "authp/admin" "authp/user"
}
}

authentication portal myportal {
crypto default token lifetime 7200
crypto key sign-verify {env.JWT_SHARED_KEY}
cookie domain app-auth-ci-001.eastus.azurecontainer.io
ui {
links {
"My Identity" "/auth/whoami" icon "las la-user"
"File Server" "/" icon "las la-cloud"
}
}
transform user {
match origin local
action add role authp/user
}
enable identity store localdb
}

authorization policy file_server_policy {
crypto key sign-verify {env.JWT_SHARED_KEY}
set auth url /auth/
allow roles "authp/admin" "authp/user"
}
}
}

:80 {
redir https://{host}{uri} 302
}

:443 {
tls internal {
on_demand
}

route /version* {
respond "app 1.0"
}

route /debug* {
authorize with file_server_policy
header Content-Type text/html
respond <<EOF
<html>
<body>
<p>Host: <code>{http.request.host}</code></p>
<p>Time: <code>{time.now.common_log}</code></p>
<p>ID: <code>{http.auth.user.id}</code></p>
</body>
</html>
EOF 200
}

route /auth* {
authenticate with myportal
}

route /* {
authorize with file_server_policy
file_server {
root {env.LOCAL_DATA_PATH}
browse
}
}
}

Container Deploymentโ€‹

Get Storage Account Key:

ACI_ST_ACCOUNT_KEY=$(az storage account keys list --resource-group "${ACI_RG_NAME}" --account-name "${ACI_ST_ACCOUNT_NAME}" --query "[0].value" --output tsv)
echo $ACI_ST_ACCOUNT_KEY

Next, deploy the container:

az container create --resource-group "${ACI_RG_NAME}" \
--name "app-auth-ci-001" \
--image "ghcr.io/authcrunch/authcrunch:latest" \
--dns-name-label "app-auth-ci-001" \
--ports 80 443 \
--azure-file-volume-account-name "${ACI_ST_ACCOUNT_NAME}" \
--azure-file-volume-account-key "${ACI_ST_ACCOUNT_KEY}" \
--azure-file-volume-share-name "${ACI_ST_SHARE_NAME}" \
--environment-variables LOCAL_DATA_PATH="/app/data/" JWT_SHARED_KEY="d24ae7de-ca54-4334-94ba-301fc414d5de" XDG_DATA_HOME="/app/data/caddy/app-auth-ci-001/data" XDG_CONFIG_HOME="/app/data/caddy/app-auth-ci-001/config" \
--azure-file-volume-mount-path /app/data/ \
--command-line "caddy run --config /app/data/caddy/app-auth-ci-001/config/Caddyfile"

Accessing Containerโ€‹

Browse to container URL: https://app-auth-ci-001.eastus.azurecontainer.io/

The first time your access your container, you get that the site is unreachable.

image

If you refresh after 10-15 seconds, you will get the connection is not private. It is expected. Trust the cert and proceed

image

After that, log in with username jsmith and password App@2f4cb79053be.

image

Click "File Server" to get redirected to Caddy file server browser:

image

You should be able to browse the contents of /app/data directory.

image

Troubleshootingโ€‹

List containers:

az container list --resource-group "${ACI_RG_NAME}"

Check logs:

az container logs --resource-group "${ACI_RG_NAME}" --name "app-auth-ci-001"
az container show --resource-group "${ACI_RG_NAME}" --name "app-auth-ci-001"

Conclusionโ€‹

There are some gaps in my explanation. Please engage, ask questions here or submit edits here.