Week 14 - Infrastructure as Code
Why use Infrastructure as Code
Your team still creates Azure resources by clicking through the portal. That worked for one environment; it does not work for three. Drift shows up, nobody can reproduce last week's setup, and the final-project capstone will need infrastructure you can re-deploy from a file.
Chapters 3β4 already taught you to author a storage account + nested container as a module. This assignment does not ask you to copy that work from the reference repo. Your fork starts with that Chapter 4 end state already in place. Your job is to extend it (environments via parameters, a second nested container), prove a deploy with what-if, tear down, and write it up.
The required work is entirely Bicep. Optional CI evidence (Task 6) does not affect whether you pass.
<aside> π If a task feels unfamiliar, work through Practice first. Practice Exercises 1 to 5 harden the authoring, drift, and module skills on the reference clone; Exercise 6 keeps the Deploy Bicep from CI/CD workflow on this assignment fork.
</aside>
Fork the cohort hand-in repo c55-data-week-14 into your own GitHub account (Chapter 5 already walked this if you planted AZURE_CREDENTIALS and bicep.yml early). The repo README covers Codespaces and the HYF-tenant az login details.
main.bicep and modules/storage.bicep: they should already look like your Chapter 4 end state (thin main, module, storage account, nested raw container, @secure()).README.md, so a reviewer can tell whose fork they opened.Do not replace the starter by pasting from azure-bicep-reference *-solution branches. Extend what is already in the fork.
Before you deploy:
az login
export CLASS_RG=rg-hyf-students # replace if your teacher gave a different name
az bicep version || az bicep install
Confirm az account show points at the shared HYF subscription. You deploy into $CLASS_RG; students cannot create resource groups themselves.
If it names a different subscription, or an N/A(tenant level account) entry, you are pointed somewhere else. List what you have and pick the shared one:
az account list --all --output table
az account set --subscription "<the shared HYF subscription>"
Anyone with a personal Azure for Students subscription will hit this: the CLI keeps one default across every tenant you have signed into, and it is not always the one you want.
c55-data-week-14/
βββ .hyf/
β βββ test.sh # static auto-grader (bash .hyf/test.sh)
βββ main.bicep # starter (Ch4 end state) β Tasks 1β2: extend
βββ modules/
β βββ storage.bicep # starter: storage + nested raw β extend
βββ docs/
β βββ deploy_succeeded.txt # Task 3: az deployment group create output
β βββ what_if.txt # Task 3: az deployment group what-if output
β βββ portal_confirm.md # Task 3: portal confirmation notes + teardown line
β βββ optional/ # Task 6: optional CI what-if evidence
βββ WRITEUP.md # Task 4: half-page teammate write-up
βββ AI_ASSIST.md # Task 5: one LLM use you critically reviewed
βββ README.md # assignment-repo README
Locked surface: storage account + nested blob containers only. Do not invent Postgres, Key Vault, Container Apps, ACR, or Databricks resources.
Add an environment parameter (for example dev or prod) and set an Environment tag on the storage account from that parameter (pass tags through the module if needed). Same idea as Practice Exercise 2 / Chapter 2: one template, many environments.
environment=dev (and your unique storageName).az deployment group what-if with the same storageName and environment=prod. You should see a tag modification, not a new storage account.prod parameter set (or leave dev if you prefer; the important part is the parameter + tag wiring and a real what-if later in Task 3).Keep the existing @secure() dummy param: pass it at deploy time; never commit the value.
Keep the nested raw container. Add a second nested blob container named curated under the same account's default blob service (parent:), still in modules/storage.bicep.
After deploy, both containers should appear under the storage account in the portal.
With Tasks 1β2 in the template:
az deployment group create --resource-group "$CLASS_RG" ... and save output showing provisioningState: Succeeded to docs/deploy_succeeded.txt.az deployment group what-if --resource-group "$CLASS_RG" ... and save the output to docs/what_if.txt. A tag or container change is ideal: for example deploy with environment=dev, then preview environment=prod and capture the ~ tags.Environment: "dev" => "prod" line. Do not chase a clean "no change": your containers will keep printing ~ with - property lines no matter what, as explained in Reading a noisy preview.$CLASS_RG, confirm the storage account and both containers (raw and curated), and note the deployment under Deployments. Write two or three sentences in docs/portal_confirm.md.docs/portal_confirm.md saying what you deleted and when, for example Teardown: deleted sthyf<yourname> (and both containers) on 2026-08-14. If your role blocked the delete, say that instead and name who you asked.<aside> π‘ Attempting the optional Task 6? Do it before this teardown step. Task 6 previews a tag or SKU change on the live account, so it needs the account to still exist. Tear down once, after the CI evidence is captured.
</aside>
.bicep files, parameters files, or docs. A committed secret fails the assignment.docs/portal_confirm.md (Task 3 step 4). Deleting the storage account removes its containers; if your role blocks delete, ask your teacher and write that down instead. Leaving unused resources bills forever.<aside>
π‘ Using AI to help: Paste your main.bicep / module (no secrets) and ask an LLM how to wire an Environment tag or a second nested container. Diff the suggestion, then run what-if yourself before you deploy. (β οΈ no real data, no PII)
</aside>
Fill in WRITEUP.md (about half a page): what you extended, why environment tags and a second container matter, and how deploying as code differs from clicking through the portal.
Fill in AI_ASSIST.md with:
Critical review is the point: an unedited paste does not pass this task.
This builds on Deploy Bicep from CI/CD and does not affect whether the assignment passes. Do it after Tasks 1β2 and after you capture the Task 3 evidence, but before the Task 3 teardown: the preview below runs against the live account, so it needs the account to still exist.
.github/workflows/bicep.yml is on this assignment fork (not the reference repo). Add it from Chapter 5 if it is missing.AZURE_CREDENTIALS (from Key Vault azure-credentials-week14-<yourname>).bicep.yml, set storageName= to your unique sthyf⦠name (plain text in the workflow is fine).what-if job log under docs/optional/. Open that PR inside your own fork (base repository <you>/c55-data-week-14), not against the cohort repo: GitHub withholds repository secrets from pull requests opened from a fork, so azure/login fails there.If your Key Vault secret is not ready yet, still keep the workflow file committed; live runs wait on azure-credentials-week14-<yourname>.
Out-of-week optional (not graded here): Bonus - AI-assisted data enrichment if you want an LLM pipeline step on a small, PII-free table.
main.bicep + modules/storage.bicep (environment tags + raw and curated), docs/deploy_succeeded.txt, docs/what_if.txt, docs/portal_confirm.md, WRITEUP.md, AI_ASSIST.mdwhat-if job evidence under docs/optional/<aside>
β οΈ Never commit an Azure key, connection string, or database password. Use @secure() parameters or Key Vault references. A leaked secret is an automatic fail and a real-world security incident.
</aside>
environment drives an Environment tag; what-if can show a tag change between values.raw and curated containers exist under the storage account.$CLASS_RG, and the teardown line says what you removed.WRITEUP.md and AI_ASSIST.md show your own judgement, not a pasted wall of text.Your teacher reviews the PR against the required tasks above. In practice they check:
environment + Environment tag; nested containers raw and curated.$CLASS_RG, Succeeded output, portal notes, and a real what-if capture.@secure() still present; no committed secrets; locked stack only.docs/portal_confirm.md records what you deleted and when (or why delete was blocked).WRITEUP.md and AI_ASSIST.md show decisions and critical review.Optional CI evidence is bonus only; it does not decide pass/fail. Point weights stay with your teacher (they are not published in this chapter on purpose).
bash .hyf/test.sh and fix anything it flags. The grader is static only (it cannot see your Azure subscription); your teacher still reviews the live deploy and the docs/ evidence. A fresh starter should clear Level 2 baseline; environment tags and curated are the extension points.week14/your-name in your fork.Your PR description is checked too. The repo ships .github/PULL_REQUEST_TEMPLATE.md, and a PR body check fails the pull request when the description is missing any of these headings:
## What I built
## How to review
## How to run
## What reviewers should see
## Self-check
GitHub fills that template in automatically only when you open the PR from the website, or with gh pr create and no --body. Open it through the API or with gh pr create --body "...", which is what most AI tools do, and the template is skipped silently. If the check goes red, click Edit on the description, paste the template, and fill it in: editing re-runs the check on its own, with no new commit needed.
<aside>
π‘ If you added the optional bicep.yml, its what-if check may show red on this hand-in PR. That is expected and does not count against you: secrets do not cross from your fork to the cohort repo, so azure/login cannot sign in there. Your green evidence comes from the in-fork PR in Task 6.
</aside>