A repository for the "Cloud Cybersecurity for Research Engineers" presentation at RSECON26.
This repository contains a Pulumi program, written in Python, that deploys Azure infrastructure. See CLAUDE.md for the full technology stack and the coding guidelines followed when changing it.
- Python 3.11 or later
- uv for Python environment and dependency management
- Pulumi CLI
- Azure CLI (
az), authenticated viaaz login— this is the only supported way to authenticate against Azure - An Azure Blob Storage container for the Pulumi state backend (see step 3 below if you don't have one yet)
-
Clone the repository and move into it:
git clone https://github.com/<org>/rse-cloud-cybersecurity.git cd rse-cloud-cybersecurity
-
Log in to Azure:
az login
-
Provision (or reuse) a storage account and blob container to hold the Pulumi state, if one doesn't already exist:
az group create --name <resource-group> --location uksouth az storage account create --name <storage-account> --resource-group <resource-group> az storage container create --name <container> --account-name <storage-account> --auth-mode login
See Create an Azure storage account and Manage blob containers using Azure CLI for the full set of options (redundancy, access tier, networking, etc.).
Since this project authenticates solely via the Azure CLI, grant your account the Storage Blob Data Contributor role on the storage account (or its resource group) so Pulumi can read/write state — see Assign an Azure role for access to blob data.
az role assignment create --role "Storage Blob Data Contributor" --assignee <email> \ --scope /subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>/blobServices/default/containers/<container>
-
Log Pulumi in to the Azure Blob Storage state backend, using the container name from step 3 and the storage account it lives in:
pulumi login "azblob://<container>?storage_account=<storage-account>"The
<container>value is just the container name you chose above (e.g.pulumi-state);<storage-account>is the account it was created in. See Pulumi's Azure Blob Storage backend docs for the full URL syntax and alternative authentication options. -
Install the project's Python dependencies into a virtual environment:
uv sync
-
Select (or create) a stack:
pulumi stack select dev # or: pulumi stack init dev
db-admin-usernameandvm-admin-usernameare configurable (seePulumi.dev.yamlfor their defaults). The VM and database admin passwords are generated by Pulumi and exported as secret stack outputs — retrieve them after deploying withpulumi stack output vm_admin_password --show-secretsandpulumi stack output db_admin_password --show-secrets. -
Deploy:
pulumi up
-
To tear down the deployed infrastructure:
pulumi destroy
-
Follow the prerequisites above, then install the dev dependencies:
uv sync
This installs
pulumi,pulumi-azure-native, plus the dev tools (ruff,ty,pytest) into a local.venv, driven entirely bypyproject.toml/uv.lock. -
Run the program locally:
pulumi preview
-
Lint and format code with ruff:
uv run ruff check . uv run ruff format .
-
Type-check with ty:
uv run ty check
-
Run the test suite (unit tests use Pulumi's built-in mocking framework, so no cloud credentials are needed):
uv run pytest
-
Before opening a pull request, make sure
ruff check,ruff format --check,ty check, andpytestall pass.
Pulumi.yaml— project definitionPulumi.<stack>.yaml— per-stack configuration (e.g.Pulumi.dev.yaml)__main__.py— program entry pointinfra/— infrastructure resource definitions, split by concern and re-exported frominfra/__init__.pyfor__main__.pyand the test suite:resource_group.py— the shared resource groupnaming.py— a random suffix shared by globally-unique resource names (storage account, SQL logical server)networking.py— VNet, subnet, public IP, and NIC for the virtual machinestorage.py— the storage account and its blob containerdatabase.py— the Azure SQL Database logical server, firewall rule, and database (Basic tier — the cheapest managed RDBMS on Azure)compute.py— the virtual machine
tests/— unit tests using Pulumi's mocking framework, one module perinfraconcern (test_networking.py,test_storage.py,test_database.py,test_compute.py,test_resource_group.py), plusconftest.pywhich wires up the shared mocks and test configpyproject.toml/uv.lock— dependency manifest and lockfile managed by uv
See specs/01-the-scenario.md for the design behind the current infrastructure — a storage account, an Azure SQL Database (Basic tier — the cheapest managed RDBMS on Azure), and a Linux VM able to reach both, all kept at minimum cost. This is the initial iteration: security hardening (private networking, managed identity, RBAC) is intentionally deferred to a later iteration, so the storage account, database, and VM are all reachable over the public internet. See CLAUDE.md for how changes to this infrastructure are verified (unit tests and static checks only — no live deployments).