Skip to main content

ยท 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.

ยท One min read
Paul Greenberg

Please share your stories about Caddy and auth plugins!

Simply add Markdown files (or folders) to the blog/ directory.

Additionally, add yourself to blog authors via authors.yml.

If your blog post has images, then create a folder for the post and co-locate images with the post itself.

  • 2021-10-31-mypost/index.md
  • 2021-10-31-mypost/image1.jpeg

Include the image in the .md file with the following snippet:

![Image for my post](./image1.jpeg)

The blog post date can be extracted from filenames, such as:

  • 2021-10-31-welcome.md
  • 2021-10-31-welcome/index.md