BloodHound CE Attack Path Analysis on AWS User Guide
Overview
BloodHound Community Edition uses graph theory to reveal the hidden and unintended privilege relationships in an Active Directory, Entra ID or Azure environment. You feed it the output of the SharpHound and AzureHound collectors and it maps every principal, group, computer, certificate template and trust into an interactive graph, then lets you trace the exact attack paths an adversary could walk to reach Domain Admins or any other high-value target. A built-in query library and pathfinding surface the shortest routes to compromise, so red teams can prove impact and blue teams can find and cut the edges that matter.
This cloudimg image runs BloodHound CE as the official upstream container (the Go API server plus the bundled React UI), published on host port 80, orchestrated by docker compose under systemd, and backed by a PostgreSQL 18 graph database. This image deliberately runs BloodHound's first-party PostgreSQL graph backend rather than the end-of-life Neo4j 4.4 line the upstream example uses, so the shipped stack carries no GPLv3 component and no end-of-life database. PostgreSQL is reachable only inside the private container network - it is never published to a host port. The Docker data root, holding the pre-pulled image and the whole security database, lives on a dedicated data volume mounted at /var/lib/bloodhound, so your ingested data survives OS-disk changes and is resizable independently.
Security is enforced from first boot. BloodHound upstream ships build-time defaults for its PostgreSQL password (bloodhoundcommunityedition) and administrator password (admin); this image never ships those to a customer. Before the stack the customer sees ever starts, a unique PostgreSQL password, JWT signing key and administrator password are generated for the individual instance on a fresh database. The initial admin password is deliberately single-use: BloodHound issues it already expired, so you are forced to set a new one at your first sign-in. Backed by 24/7 cloudimg support.
What is included:
- BloodHound Community Edition 9.4.0, the Apache-2.0 licensed Active Directory and Entra ID attack path analysis platform, shipped as the official upstream container
- The BloodHound Go API and React UI on host port 80
- A bundled PostgreSQL 18 graph database (the application store and the attack-path graph), reachable only inside a private container network
- Docker Engine and the docker-compose plugin from the official Docker APT repository
- A unique PostgreSQL password, JWT signing key and single-use administrator password generated on each instance's first boot, on a fresh database
- The Docker data root and security database on a dedicated data volume at
/var/lib/bloodhound - A genuine SharpHound sample dataset staged at
/opt/bloodhound/sample-data/for immediate exploration docker.service,bloodhound-firstboot.serviceandbloodhound.serviceas systemd units- 24/7 cloudimg support
Prerequisites
An AWS account, an EC2 key pair in the target region, and a VPC with a public subnet. m5.large (2 vCPU / 8 GiB RAM) is the recommended instance type; BloodHound's own guidance is a floor of 8 GiB RAM. Security group inbound: allow 22/tcp from your management network for SSH, and 80/tcp for the BloodHound UI and API from wherever your analysts browse.
Step 1 - Launch the AMI
Subscribe to the listing in AWS Marketplace, then launch an instance from the AMI into your VPC with the security group described above. Choose the m5.large instance type and attach your EC2 key pair. The image keeps the pre-pulled container images on the dedicated data volume, so the BloodHound stack comes up within a few minutes of first boot with no image re-pull while it rotates its secrets and initialises a fresh database.
Step 2 - Connect to your instance
Connect over SSH as the default login user for the operating system variant you launched. The login user differs per OS, so use the row for your variant:
| OS variant | SSH login user | Example |
|---|---|---|
| Ubuntu 24.04 | ubuntu |
ssh -i your-key.pem ubuntu@<instance-public-ip> |
ssh -i your-key.pem ubuntu@<public-ip>
Step 3 - Read your unique credentials
On first boot the instance generates a unique administrator password, seeds a fresh administrator on a clean database, arms forced rotation so the password is single-use, and writes the credentials along with the resolved web URL to a root-only file. View the URL and username (the password line is kept off screen here):
sudo grep -E '^(bloodhound\.url|bloodhound\.admin\.user)=' /root/bloodhound-credentials.txt
bloodhound.url=http://<instance-public-ip>/ui/login
bloodhound.admin.user=admin
The same file also contains the line BLOODHOUND_ADMIN_PASSWORD=<unique-per-instance-password>. Read the whole file with sudo cat /root/bloodhound-credentials.txt when you are ready to sign in. There is no default or shared login anywhere in the image; every secret is unique to this instance, and the administrator password must be changed at your first sign-in.
Step 4 - Verify the security model from the command line
Confirm the three systemd units are active:
sudo systemctl is-active docker bloodhound bloodhound-firstboot
active
active
active
Confirm that only SSH and the BloodHound UI are bound on the host - PostgreSQL (5432) and the Neo4j ports (7474 / 7687) never appear, because PostgreSQL is reachable only on the private container network and no Neo4j is shipped at all:
sudo ss -tlnH | awk '{print $4}' | grep -Eo ':(80|5432|7474|7687)$' | sort -u || true
:80
Confirm BloodHound answers its unauthenticated health probe and serves the sign-in page, while the API rejects unauthenticated calls:
curl -s -o /dev/null -w 'health %{http_code}\n' http://127.0.0.1/health
curl -s -o /dev/null -w 'sign-in page %{http_code}\n' http://127.0.0.1/ui/login
curl -s -o /dev/null -w 'unauth API %{http_code}\n' http://127.0.0.1/api/v2/available-domains
health 200
sign-in page 200
unauth API 401
Confirm the well-known upstream default credentials are rejected, and that the unique per-instance administrator password authenticates (the password is read into a shell variable and never printed):
curl -s -o /dev/null -w 'admin / admin HTTP %{http_code}\n' -X POST http://127.0.0.1/api/v2/login -H 'Content-Type: application/json' -d '{"login_method":"secret","username":"admin","secret":"admin"}'
curl -s -o /dev/null -w 'admin / bloodhoundcommunityedition HTTP %{http_code}\n' -X POST http://127.0.0.1/api/v2/login -H 'Content-Type: application/json' -d '{"login_method":"secret","username":"admin","secret":"bloodhoundcommunityedition"}'
PASS=$(sudo grep '^BLOODHOUND_ADMIN_PASSWORD=' /root/bloodhound-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'admin / per-instance password HTTP %{http_code}\n' -X POST http://127.0.0.1/api/v2/login -H 'Content-Type: application/json' --data-binary "$(python3 -c 'import json,sys;print(json.dumps({"login_method":"secret","username":"admin","secret":sys.argv[1]}))' "$PASS")"
admin / admin HTTP 401
admin / bloodhoundcommunityedition HTTP 401
admin / per-instance password HTTP 200
Finally, confirm that no Neo4j image is present in the appliance - the graph runs entirely on PostgreSQL:
sudo docker ps -a --format '{{.Image}}' | grep -ci neo4j || echo 0
0
Step 5 - Sign in to the web UI
Open the BloodHound UI in a browser at http://<instance-public-ip>/ui/login and sign in as admin with the password from /root/bloodhound-credentials.txt. Because the initial password is issued already expired, BloodHound requires you to choose a new password at this first sign-in; keep the new one safe.

Step 6 - Explore attack paths
Once signed in you land on the Explore view. Open the Cypher tab and its saved-query library to run BloodHound's prebuilt queries and pathfinding, or write your own Cypher against the graph:

Running a query such as All Domain Admins or Shortest paths to Domain Admins renders the attack-path graph: every principal and the relationships that lead to a high-value target. The image below shows the bundled SharpHound sample dataset, with Active Directory users mapped by their MemberOf relationships into the Domain Admins groups across three trusted domains:

Step 7 - Review the ingested data
The Administration area's Data Quality view summarises the objects collected in each environment - users, groups, computers, OUs and GPOs - so you can confirm a collection landed correctly before you start hunting:

Step 8 - Ingest your own collector data
A genuine SharpHound sample dataset is staged read-only on the instance so you can explore immediately, and you can re-upload it or your own collector output at any time from the UI's Quick Upload or File Ingest:
ls -1 /opt/bloodhound/sample-data/
ad_sampledata.zip
Download the SharpHound and AzureHound collectors from the official SpecterOps releases (github.com/SpecterOps/SharpHound and github.com/SpecterOps/AzureHound), run SharpHound against your own Active Directory (or AzureHound against your Entra ID tenant), then upload the resulting JSON or ZIP through the BloodHound UI. BloodHound ingests the data, runs its analysis pass, and the new attack paths become queryable in Explore. (The collector binaries are not bundled in this image; they are offensive-security tools you download and run against environments you are authorised to assess.)
Step 9 - Confirm the dedicated data volume
The Docker data root and the whole security database live on a dedicated EBS volume mounted at /var/lib/bloodhound, so they survive OS-disk changes and can be grown independently:
findmnt -no SOURCE,TARGET,FSTYPE /var/lib/bloodhound
/dev/nvme1n1 /var/lib/bloodhound ext4
To grow it, expand the EBS volume in the AWS console, then run sudo resize2fs /dev/nvme1n1 (use the device shown by the command above).
Step 10 - Point the instance at your own domain and TLS
BloodHound is served over plain HTTP on port 80 out of the box. For production, put the instance behind an Application Load Balancer or a reverse proxy such as nginx or Caddy terminating TLS with your own certificate and domain, and restrict the security group so only your load balancer reaches port 80. The BloodHound UI and API are origin-agnostic, so no application reconfiguration is needed when you place a proxy in front.
Support
cloudimg provides 24/7 technical support for this product by email and live chat at support@cloudimg.co.uk. We can help with deployment, re-pointing the instance at your own domain or DNS name, reverse-proxy TLS termination, ingesting SharpHound and AzureHound collector data, and backing up the security database with EBS snapshots or AWS Backup.