Skip to content

Using Cirro and CirroDash

This page is the repeatable tool workflow for the lab. You will run it more than once as your identity and available evidence change:

Azure login -> Cirro collection -> SQLite artifact -> Cirro ingestion
            -> Neo4j -> CirroDash investigation

1. Check the workshop tools

Open a terminal in the workshop environment and confirm that the required commands are available:

az version
cirro --version
cirro collect az --help
cirro graph ingest --help

Use the binaries supplied by the instructor. If a command is missing or the available options differ from this guide, stop and ask an instructor before installing a different release.

Create a directory for your lab artifacts and keep all collected data there:

mkdir -p workshop-artifacts
cd workshop-artifacts

Sensitive artifacts

Cirro SQLite databases can contain tenant metadata and data-plane values. Keep this directory local to the workshop system, do not commit it, and remove it when instructed at the end of the lab.

2. Authenticate to the correct tenant

Clear any previous Azure CLI session, then authenticate with the identity for the current lab stage:

az logout
az login \
  --tenant <workshop-tenant-id> \
  --username <your-user-principal-name> \
  --allow-no-subscriptions
az account show --output table

Before collecting, verify all three of these values:

  • the active tenant is the workshop tenant;
  • the signed-in user is the intended guest identity; and
  • the active subscription is the workshop subscription, when that identity has subscription access.

An initial low-privilege guest may not have a visible subscription. That is an expected observation during the first collection.

3. Collect with Cirro

Run Cirro using the authenticated Azure CLI session:

cirro collect az azcli

Cirro writes the normalized collection to cirro_output.db. Confirm that the file exists and contains tables before continuing:

ls -lh cirro_output.db
sqlite3 cirro_output.db '.tables'

Make a stage-specific copy so a later collection does not erase your evidence:

cp cirro_output.db initial-guest.db

Use names such as initial-guest.db, defcon-reader.db, and key-vault-data.db throughout the lab.

If collection returns less data than expected

Recheck az account show, confirm the identity's current access, and run the collection again. Dynamic group membership and new role access may take several minutes to propagate.

4. Inspect before ingesting

The SQLite artifact is evidence as well as graph input. A quick inspection helps distinguish a successful but low-privilege collection from a failed one:

sqlite3 cirro_output.db '.tables'
sqlite3 cirro_output.db \
  "SELECT resource_type, COUNT(*) FROM resources GROUP BY resource_type ORDER BY COUNT(*) DESC LIMIT 15;"

If the resources table is absent during the first guest collection, inspect the identity tables that are present instead. Do not edit the database.

5. Ingest into Neo4j

Use the Neo4j connection values supplied by the instructor. The common local workshop form is:

cirro graph ingest \
  --type az \
  --file cirro_output.db \
  --server bolt://localhost:7687 \
  --user neo4j \
  --password <workshop-neo4j-password>

Look for a successful completion message with no connection or schema errors. If ingestion fails, do not repeatedly recollect Azure data—the SQLite artifact already exists. Fix the Neo4j connection and ingest the same file again.

Refreshing the graph

Ingest each new stage-specific collection as the lab progresses. Cirro uses stable object identifiers to connect new evidence to existing nodes.

6. Connect CirroDash

Open the CirroDash URL supplied by the instructor. On the connection screen, enter the Neo4j settings used for ingestion:

Field Common local value
Scheme bolt
Server localhost
Port 7687
Username neo4j
Password instructor-provided password

If CirroDash runs in a container, localhost may refer to that container rather than your host. Use the server name supplied by the instructor in that case.

After connecting:

  1. Open a preconfigured identity or resource table.
  2. Confirm that rows appear and that the most recent identity is present.
  3. Create a tab named Workshop Investigation.
  4. Add a Count card named Total nodes with this query:
MATCH (n)
RETURN count(n) AS total
  1. Add a Table card named Node types with this query:
MATCH (n)
UNWIND labels(n) AS label
RETURN label, count(*) AS total
ORDER BY total DESC

Use Test Query before saving each card. These two cards provide a quick check that later ingestion actually changes the graph.

7. Investigate without getting lost

For each lab stage, use the same sequence:

  1. Find the known starting object, usually your current user.
  2. Inspect its properties and copy its stable identifier into your notes.
  3. Follow one relationship at a time.
  4. Record the relationship verb and the destination object.
  5. Compare the path with the raw SQLite evidence when a relationship is unclear.
  6. Save useful Cypher as a CirroDash table card.

A generic search card can help locate a known display value without assuming a specific node label:

MATCH (n)
WHERE any(value IN [n.displayName, n.userPrincipalName, n.name]
          WHERE toLower(coalesce(value, '')) CONTAINS toLower('<search-text>'))
RETURN labels(n) AS labels, n.displayName, n.userPrincipalName, n.name, n.id
LIMIT 50

Replace <search-text> with a non-secret value such as part of your user principal name or vm-cocoaman-diagnostics.

Troubleshooting checklist

Symptom Check
az login reaches the wrong tenant Log out and repeat login with the workshop tenant ID
No subscription appears Confirm the current identity and allow time for dynamic membership
cirro_output.db is missing Review the Cirro error and verify the working directory is writable
SQLite has identity data but no resources The current identity may not yet have subscription visibility
Neo4j connection is refused Confirm Neo4j is running and verify scheme, host, and port
CirroDash connects but shows no rows Ingest the database, refresh the card, and verify the selected Neo4j database
A query reports an unknown property Inspect a returned node first; Azure object types do not all share the same properties

For command options outside this workshop, consult the Cirro documentation.