Skip to content

Repository files navigation

rse-cloud-cybersecurity

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.

Prerequisites

  • Python 3.11 or later
  • uv for Python environment and dependency management
  • Pulumi CLI
  • Azure CLI (az), authenticated via az 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)

For users: running the deployment

  1. Clone the repository and move into it:

    git clone https://github.com/<org>/rse-cloud-cybersecurity.git
    cd rse-cloud-cybersecurity
  2. Log in to Azure:

    az login
  3. 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>
  4. 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.

  5. Install the project's Python dependencies into a virtual environment:

    uv sync
  6. Select (or create) a stack:

    pulumi stack select dev   # or: pulumi stack init dev

    db-admin-username and vm-admin-username are configurable (see Pulumi.dev.yaml for their defaults). The VM and database admin passwords are generated by Pulumi and exported as secret stack outputs — retrieve them after deploying with pulumi stack output vm_admin_password --show-secrets and pulumi stack output db_admin_password --show-secrets.

  7. Deploy:

    pulumi up
  8. To tear down the deployed infrastructure:

    pulumi destroy

For contributors: setting up a development environment

  1. 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 by pyproject.toml / uv.lock.

  2. Run the program locally:

    pulumi preview
  3. Lint and format code with ruff:

    uv run ruff check .
    uv run ruff format .
  4. Type-check with ty:

    uv run ty check
  5. Run the test suite (unit tests use Pulumi's built-in mocking framework, so no cloud credentials are needed):

    uv run pytest
  6. Before opening a pull request, make sure ruff check, ruff format --check, ty check, and pytest all pass.

Project structure

  • Pulumi.yaml — project definition
  • Pulumi.<stack>.yaml — per-stack configuration (e.g. Pulumi.dev.yaml)
  • __main__.py — program entry point
  • infra/ — infrastructure resource definitions, split by concern and re-exported from infra/__init__.py for __main__.py and the test suite:
    • resource_group.py — the shared resource group
    • naming.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 machine
    • storage.py — the storage account and its blob container
    • database.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 per infra concern (test_networking.py, test_storage.py, test_database.py, test_compute.py, test_resource_group.py), plus conftest.py which wires up the shared mocks and test config
  • pyproject.toml / uv.lock — dependency manifest and lockfile managed by uv

Current scenario

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).

About

A repository for the "Cloud Cybersecurity for Research Engineers​" presentation at RSECON26

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages