Skip to content

Azure Container

Everything a customer Azure environment must provide to run the ansible-epic control node as an Azure Container Instances container group — the compute itself plus the registry, storage, identity, secret, and network dependencies around it. This page is the full deployment picture behind the summary bullets in Requirements → Azure Container; it slots into steps 1–2 of the New Customer Checklist. Access-mode and image details live in Containers.

Compute

  • One container group running ansible-epic/base:latest — 2 vCPU / 4 GB is the working default — with:
    • a private IP in the delegated container subnet (no public IP);
    • TCP 22 exposed (SSH access mode);
    • the customer's persistent file share mounted at /home/ansible/source;
    • the user-assigned identity (below) attached;
    • registry credentials via that identity (no admin passwords);
    • environment variables per the chosen access mode (e.g. AUTHORIZED_KEYS for SSH, TUNNEL_NAME for a VS Code tunnel) and USER_SETUP=1 if the per-user setup and persistence feature is wanted.
  • Pin the group to an availability zone if the customer's platform standards require zonal placement.

Container registry

  • An Azure Container Registry in the customer environment, with an artifact cache rule mapping ghcr.io/sapphire-health/ansible-epic/base to a local repository. The image then mirrors on demand — no manual push pipeline. The GHCR packages are public, so the cache rule needs no upstream credential.
  • Be aware of the cache's latest-tag revalidation lag: a re-published latest upstream can take time to be re-fetched.
  • The container's identity needs AcrPull on this registry.

Persistent storage

  • A storage account with an ansible-files share (32 GB is a comfortable start) for /home/ansible/source — playbooks, inventory, and per-user state survive container restarts.
  • Do not use a default (Standard) storage account — standard file shares have caused real performance problems for this workload (git operations and Ansible runs hit thousands of small-file IOPS). The account must be created with these settings, which can't be changed after creation:

    Setting Required value
    account_tier Premium
    account_kind FileStorage (SSD file shares — Premium tier alone isn't enough if the kind is StorageV2)
    account_replication_type LRS
    provisioned_billing_model_version V2 (provisioned IOPS/throughput scale independently of quota)
  • The storage account must be in the same region as the container group — a cross-region SMB mount adds latency to every file operation and can fail ACI's mount at group creation.

  • Public network access disabled on the storage account; access is via a file private endpoint in a non-delegated subnet, with a privatelink.file.core.windows.net private DNS zone linked to the vnet so the mount resolves privately.
  • The container subnet needs the Microsoft.Storage service endpoint for the ACI file-share mount.

Key Vault and the vault password

  • A Key Vault that lives outside the deployment's lifecycle — its own resource group, never in any automated destroy path. It holds the ansible-vault-password secret, which the container reads on every playbook run (scripts/azure-vault-pass.shaz login --identity → secret get; see Secret Management).
  • The secret's value should be generated, never typed or committed — and must be retrievable only from the vault (long and random; the encrypted vault files' ciphertext is only as strong as this password).
  • If the vault is network-restricted, it needs its own private endpoint and privatelink.vaultcore.azure.net DNS zone reachable from the container subnet.

Identity and permissions

A user-assigned managed identity for the container, with:

Grant Purpose
AcrPull on the registry Pull the cached image
Key Vault Secrets User (or access-policy get) on the vault Read ansible-vault-password at runtime
Reader on every subscription with managed hosts The azure_rm dynamic inventory enumerates VMs

Whoever performs the deployment needs, beyond resource-creation rights in the subscription:

  • rights to create role assignments (User Access Administrator or Owner) for the grants above;
  • Key Vault Secrets Officer on the vault, to seed the ansible-vault-password secret.

Network

  • A vnet with two subnets:
    • a container subnet carrying the exclusive Microsoft.ContainerInstance/containerGroups delegation (nothing else can share it) plus the Microsoft.Storage service endpoint;
    • a general subnet for the private endpoints (they can't land in the delegated subnet).
  • Reachability from the container subnet to every managed host: 22 to Linux, 5985/5986 to Windows — see Requirements → Network. ACI containers can change IP across restarts, so scope these rules to the delegated subnet, never the container's current IP.
  • An NSG on the container subnet admitting inbound SSH (22) — and HTTPS (443) if a web access mode is used — from the customer's management ranges only.
  • Outbound, the container subnet must reach the ACR endpoint (image pull), the Key Vault endpoint (secret reads), and the storage account's private endpoint (share mount). No ghcr.io egress is needed — the registry cache fetches upstream on ACR's side.

Validating a deployment

From inside the running container:

  1. az login --identity succeeds (identity attached and functional);
  2. the vault password script prints the secret (Key Vault grant + network path);
  3. ansible-inventory --list enumerates the customer's VMs (subscription Reader + inventory config);
  4. a file written under /home/ansible/source survives a container restart (share mounted, private endpoint resolving);
  5. ansible -m ping / -m win_ping reach a Linux and a Windows host (network reachability rules).

Then continue the New Customer Checklist from step 3 (repository, inventory, vault contents, first playbook run).