Skip to content

feat: add Azure install reference for the static files scope - #20

Merged
jcastiarena merged 4 commits into
mainfrom
feat/azure-install-reference
Sep 8, 2026
Merged

feat: add Azure install reference for the static files scope#20
jcastiarena merged 4 commits into
mainfrom
feat/azure-install-reference

Conversation

@jcastiarena

@jcastiarena jcastiarena commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Closes the gap specs/install/README.md asks for: "Not yet provided — Azure ... Contributions welcome, file a PR adding a sibling azure/ directory with the same file layout."

The scope already supports Azure at runtime — provider/azure, network/azure_dns and distribution/blob-cdn are complete and covered by the azure_blobcdn_azuredns integration test — but specs/install only shipped an AWS example, so there was no documented way to register it on an Azure account.

What this adds

specs/install/azure/ mirroring the AWS layout: the same scope_definition and scope_definition_agent_association calls, and a nullplatform_provider_config carrying the azure_* attributes of the scope-configuration schema.

Following the AWS example's shape, provider_configs stays a list — one entry per environment — and what varies per entry is the NRN, the resource group and the DNS zone. The OpenTofu state storage account is shared across entries, the same way aws_state_bucket is. azure_dns_zone_resource_group is optional and falls back to the entry's resource group, which is the common case.

Documentation

Adds the #### Azure pre-requisites section, which did not exist:

  1. Storage account + container for the OpenTofu state.
  2. A public Azure DNS zone (looked up via data source; the scope writes records, it does not create the zone).
  3. A storage account with the static website feature enabled — the distribution layer reads it with a data source and uses its primary_web_host as the CDN origin, so it must exist and be configured beforehand, with the 404 document pointing at index.html for client-side routing.
  4. The agent's Azure RBAC assignments, with the trap spelled out: Contributor on the resource group is not enough, because it grants the management plane but not the blob data plane. The Storage Blob Data Contributor assignments are required in addition.

Also documents something that is an advantage over the AWS path and was not written down anywhere: there is no certificate pre-requisite on Azure. The distribution layer requests a CDN-managed certificate (Dedicated, TLS 1.2) for the custom domain, whereas AWS needs an ACM certificate in us-east-1 created and validated beforehand.

Known limitation — an Azure install cannot complete a deployment yet

Documented in both READMEs rather than left for someone to discover.

deployment/distribution/blob-cdn/setup derives the storage account, container and prefix from the asset URL and expects https://<storage>.blob.core.windows.net/<container>/.... Nothing on the platform produces such a URL today.

Re-verified against the provider catalogue on 2026-09-08. Of the 32 provider specifications available, exactly two carry the asset-repository role — the ones whose mapping writes repository_provider to global.asset_repository_provider:

slug name asset URL shape
ecr AWS ECR image URI
docker-server Docker Server image URI

Both are container-registry shaped, so np asset push yields an image URI and the blob-cdn setup rejects it.

Worth naming precisely, because it is easy to get wrong: s3-configuration is not an asset-repository provider. It does not declare global.asset_repository_provider at all — it maps bucket.name to aws.s3_assets_bucket, and that is what makes the AWS path resolve to the s3://… URL cloudfront/setup parses. So what Azure is missing is either an Azure Blob asset-repository provider, or an azure-blob-configuration counterpart to s3-configuration.

So this PR makes the scope installable and scope-creatable on Azure, but a deployment cannot succeed until that gap is closed on the platform side. I would rather land the reference with the limitation stated than leave the directory missing.

Relationship to #19

No git dependency: azure/ carries its own versions.tf and provider.tf, which is why it initializes standalone. But #19 adds those two files to aws/, so merging it first keeps the two examples symmetric.

One follow-up I owe this PR either way — the layout tree in install/README.md is missing azure/provider.tf, and will need aws/versions.tf and aws/provider.tf added once #19 lands. Happy to fix the tree in a follow-up commit here.

Verification

cd static-files/specs/install/azure
tofu init -backend=false   → OpenTofu has been successfully initialized!
tofu validate              → Success! The configuration is valid.
tofu fmt -recursive -check → clean

The scope already supports Azure at runtime (provider/azure, network/azure_dns
and distribution/blob-cdn, covered by the azure_blobcdn_azuredns integration
test) but specs/install only shipped an AWS example, so there was no documented
way to register it on an Azure account.

Adds specs/install/azure/ mirroring the AWS layout: same scope_definition and
scope_definition_agent_association calls, and a nullplatform_provider_config
carrying the azure_* attributes of the scope-configuration schema. Per entry in
provider_configs what varies is the NRN, the resource group and the DNS zone;
the OpenTofu state storage account is shared, the same way aws_state_bucket is.
azure_dns_zone_resource_group is optional and falls back to the entry's
resource group.

Also documents the Azure pre-requisites, which were missing: state storage
account and container, public DNS zone, a storage account with the static
website feature enabled (read via data source for its primary_web_host), and
the agent's RBAC assignments. Calls out that Contributor on the resource group
does not cover the blob data plane, and that no certificate pre-requisite
exists on Azure because the distribution layer requests a CDN-managed
certificate.

Known limitation, documented in both READMEs: the distribution layer derives
the storage account from the asset URL and expects
https://<storage>.blob.core.windows.net/<container>/..., which needs an
asset-repository provider specification for Azure Blob. None exists today
(only s3-configuration and docker-server), so an Azure install can register
the scope but cannot complete a deployment yet.

Note: the layout in install/README.md also lists a versions.tf under aws/,
which is added by the companion fix for the AWS example's provider source.
@jcastiarena
jcastiarena force-pushed the feat/azure-install-reference branch from 3884948 to 9faee85 Compare July 29, 2026 21:52
jcastiarena and others added 3 commits July 29, 2026 19:17
The schema declared `blob_cdn` (underscore) as both the default and the only
allowed value, but the layer value is used verbatim as a directory name by
`layer_executor` and the implementation lives in
`deployment/distribution/blob-cdn`. Any scope configured through the UI, which
renders from this schema, therefore failed `start-initial` with
"Unknown distribution implementation: 'blob_cdn'".

The other three layers already matched their directories (`azure_dns`,
`route53`, `cloudfront`); this was the only divergence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… docs

Review follow-ups on the Azure install reference:

- Allow a per-environment Azure subscription. `azure_subscription_id` is now
  optional per `provider_configs` entry and falls back to the top-level
  variable, so a subscription-per-environment layout no longer requires
  duplicating the whole module. Mirrors how the AWS reference varies
  `aws_region` per entry.
- Stop exposing `azure_dns_zone_resource_group` as configurable. The value is
  preflight-checked by `network/azure_dns/setup` but never forwarded to the
  module, which resolves the zone against the scope's resource group. Pointing
  it elsewhere passed the preflight and then read the wrong resource group, so
  the docs described an override that never worked.
- Fix the agent's Azure role assignments: the assets storage account needs
  `Reader`, not `Storage Blob Data Contributor`. The distribution layer only
  reads it through a data source to resolve `primary_web_host`; uploading the
  bundles is CI's job. This now matches the guidance embedded in
  `scope-configuration.json.tpl`.
- Point both Gotchas at the Azure example instead of describing it as future
  work, and drop `aws/versions.tf` from the layout tree, where it does not
  exist yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`var.np_api_key` only reached the `np` CLI that the module dependencies shell
out to; it never configured the Terraform provider, which falls back to the
NULLPLATFORM_API_KEY environment variable. Following the README literally —
fill in terraform.tfvars, then `tofu init && tofu apply` — failed to
authenticate unless the operator also exported that variable, which the README
does not mention.

Wires the existing variable into a provider block, matching the AWS example. No
new input: the terraform.tfvars.example already prompts for np_api_key.

Note: with provider 0.0.97 `tofu validate` reports a spurious "np_apikey is
deprecated" warning for this block even though only `api_key` is set. That is
already fixed upstream and will clear on the provider's next release; `api_key`
is the correct attribute.

@sebastiancorrea81 sebastiancorrea81 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@jcastiarena
jcastiarena merged commit 632c34e into main Sep 8, 2026
5 checks passed
@jcastiarena
jcastiarena deleted the feat/azure-install-reference branch September 8, 2026 15:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants