The pipeline from 3.7 signs in to Azure without a secret. For that it needs an identity with a federated credential and permissions. Who creates this identity? The pipeline can't, because without an identity it can't sign in. And who gives it permissions? Only someone who is Owner, User Access Administrator or Role Based Access Control Administrator themselves may assign roles (3.1.4). A pipeline with these permissions on the whole subscription would be the most dangerous identity you have.
This is the chicken-and-egg problem of every new subscription. The solution has two levels. The foundation is created once by a person who is Owner: budget, rules, resource groups, identities and their permissions. It lives in the repository as Bicep and is rolled out with a runbook. Everything else, the application, is rolled out afterward by the pipeline, with permissions that end at the resource group of its environment. In this lesson you write the foundation.
What comes before the application
| What | Why beforehand | Where |
|---|---|---|
| Budget | First the budget, then the first resource. | subscription |
| Policies "EU only" and "inherit tags" | They should apply to the first resource already, not only from the second. | subscription |
Resource groups rg-kladde-shared, rg-kladde-dev, -test, -prod |
The pipeline's permissions end at them; for that they have to exist beforehand. | subscription |
| Read access for the group "Kladde-Operations" | People watch, but change things only through the pipeline. | subscription |
| Container registry | One image for all environments (3.7.5: build once, deploy everywhere). | rg-kladde-shared |
Identity id-kladde-build |
Builds and pushes images, only from main. |
rg-kladde-shared |
Identity id-kladde-preview |
Reads prod and shows what-if before anyone approves a version. |
rg-kladde-shared |
Identity id-kladde-deploy-<environment> |
Deploys an environment, only from the GitHub environment of the same name. | rg-kladde-<environment> |
Identity id-kladde-app-<environment> |
The identity under which the Container Apps run. | rg-kladde-<environment> |
| GitHub environments and variables | The workflows need the IDs of the identities. | GitHub |
What the application itself needs is not part of it: Container Apps environment, database, storage account, Service Bus, Key Vault, Application Insights. The pipeline deploys that in the next lesson.
Why does the app's identity come into being here and not with the app? It needs the permission to pull images from the shared registry.
The registry lives in rg-kladde-shared, and the pipeline of an environment has no permissions there. So the foundation assigns this permission,
and for that the identity has to exist already. Since 3.3.1 you know that Microsoft recommends user-assigned identities for such cases:
They live independently of the app and survive the app being re-created.
Up to module 3.5, every app had its own identity: id-kladde-web-<environment>, one for the worker, id-kladde-import-<environment> for the
nightly fetch and id-kladde-scaler-<environment> for KEDA. In exercise 1 of lesson 3.3.5, a shared identity for web and worker
was even the mistake. The examples in this module combine the apps of an environment into id-kladde-app-<environment> to keep the foundation, the check script
and the rebuild short. That is a simplification with a price: The web app may then read from the queues too, and in a service's log
all apps look the same. For your Kladde you have two ways. You keep the separation from 3.3.5: then
environment.bicep creates one identity per app, each gets AcrPull and only its own data roles, and the scripts of this module check
each one individually. Or you adopt the simplification: then it goes into docs/decisions.md with this price, and review 2
(3.10.10) asks about it. Only the identity for KEDA stays a separate one in both cases, because it gets Data Owner, and no app may have that
(3.5.7); how it gets into the worker's Container App is shown in lesson 3.10.3.