Published: Sep 12, 2024 by Isaac Johnson
I’ve always had a soft spot for Cloudcraft since I saw it prominently on display at Hashiconf 2018.
Years ago, I was told by them that “GCP is coming” but it really never happened.
I recently had need for more cloud diagrams and thought it might be a good time to explore our options.
Today we’ll look at Hava (which I learned about from a vendor at a NewRelic user meetup), LusicScale from Lucid, and one I found just by way of a simple search, Holori.
I’ll look at the major clouds and terraform, but also generally focus on GCP as that is where I do most of my work presently. We’ll wrap with costs and touch on terraform to Graphviz.
Hava
We can signup for a new account at hava.io.
Let’s now add an environment.
Actually, that loaded a demo env, which was not what i wanted
Instead, I’m going to add a Source and choose Google
I need to create an SA and get it’s JSON for this:
$ gcloud iam service-accounts create havareadonly --display-name "HavaReadOnly" --project myanthosproject2
Created service account [havareadonly].
$ gcloud projects add-iam-policy-binding myanthosproject2 \
--member serviceAccount:havareadonly@myanthosproject2.iam.gserviceaccount.com \
--role roles/viewer
Updated IAM policy for project [myanthosproject2].
bindings:
- members:
... snip ...
Lastly, i need to download the JSON key
$ gcloud iam service-accounts keys create key.json --iam-account havareadonly@myanthosproject2.iam.gserviceaccount.com
created key [4c788b065ca222755f50f9b7170b9a08cabc3120] of type [json] as [key.json] for [havareadonly@myanthosproject2.iam.gserviceaccount.com]
this saved a key.json locally so i’ll move that to windows so I can upload it to hava
builder@DESKTOP-QADGF36:~$ ls -ltra | tail -n1
-rw------- 1 builder builder 2366 Jul 31 08:20 key.json
builder@DESKTOP-QADGF36:~$ cp ./key.json /mnt/c/Users/isaac/Downloads/hava-key.json
I can now import it into Hava
Which shows that Sync is now Queued
It’s not perfect, but we get a general overview of our cloud resources with connections setup for our Dapr Services
A Month later
I came back a month later to get an idea on costs.
Monthly it is $249
or $2388/year
LucidScale
A suite I use professionally is Lucidchart for diagrams.
They also have Lucidscale which should import diagrams of our cloud
It’s only a bit cheaper than Hava at $2000/year
I’ll create a new account
Once created, I can start with a given cloud. I’ll choose GCP for this
I get past more survey prompts
I’ll spare you the clippy-style wizard walk through, but I did like the fact I could easily kick this over to Lucidchart
I’m going to go to GCP and “Import New Project”
I’ll start with the GCP Service Account
In IAM, I’ll create a new SA for Lucidscale
I’ll grant “Viewer” from the Basic list
I don’t need to add anyone else for the “Grant users”, so I can click Done on the last step
I’ll now find it in the list of SAs and click “Manage keys” from the “…” menu
Click the “Add Key” drop down and choose to create a new key
We’ll leave the default “JSON” and click create
Back in my Lucidscale page, I can now import that downloaded JSON file and click next
I also need to verify the “Cloud Resource Manager API” is enabled
Note: Once I fixed that API, i could see it show up on the right in the Credentials tab
And it also was now listed in the “Projects to import” page (was blank prior)
I’ll leave all the types selected then choose to “Import GCP Projects”
I then see notices that is importing on the bottom right
I did see a note that not all my resources were imported
I guess only BigTable was missed (could be a lack of an API as I don’t use BigTable in this project)
I can now create a new model, and choose the project
Only a few were checked, but I wanted to see it all so I checked all the types of documentation
This kicked off another run
It created an “Untitled GCP Project” diagram
I love Lucid because I can fetch out details from metadata, something I sorely miss when having to use Miro
This is handy from an InfoSec point of view since I can, for example, look at the Firewall rules and see I (foolishly) left open 3389 (RDP) and 22 (SSH) for the world (0.0.0.0/0)
In the “Compliance Insights” we can see this even more clearly with our rules listed out in the diagram
Since this project is empty (at the moment), there is not much to say for Cost Savings, GKE Clusters or Infrastructure. But I can show the Network Topology view which, again, shows clearly those open rules for RDP and SSH
I can update the Chart at any time
Azure
Let’s pull in our P-A-Y-G subscription from Azure.
We’ll use “New Subscription” under Data Hub/Azure
Next, I’ll use Azure AD
I’ll click “Register AD Application”
I’ll name it “LucidImport” and click Register
I’ll search it up under All Applications in EntraAD (AAD)
Three of the four values Lucid desires we can copy from the Application page in Azure
You’ll need to go to “Certificates & Secrets” to generate the Client secret
At first I saw no subscriptions, but that is because I skipped the step to assign a role
I’ll just go to Subscriptions, pick my Subscription and assign Roles to add the “Reader” role to LucidImport
After I closed and re-opened the Azure Subscription import in LucidScale, I could see my subscription
I can select everything Lucid can diagram
And click Import to start the process
After import, I need to create a Model from the imported data if I want to view it
As before, I’ll ask for all of the types of documentation
which kicks off a diagraming run
Holori
Let’s look at one more - Holori. They have a decent free option and their pricing seems reasonable.
I opted to signup with Google and the first screen we encounter is the basic “tell us more about you” page
The next screen caught my eye because it prompted me to use AWS, GCP or actually upload my OpenToFu files (terraform).
I’m super curious how well it can handle TF of various ages. I have a project I whipped up for a client 5 years ago but I still have the Azure Repo with the sample TF handy
I’ll download that as a zip
I chose to Import from the Zip and it flashed this import screen for just a few seconds
Before showing me a “Import” project
That is basically right - an Azure AKS cluster with ACR and a logging workspace
And they have a nice isometric 3d view as well
I gave it a full night to come back on my old Terraform, but it never did render anything
I decided to ask Copilot to build me a basic three-tier app in Terraform with some parameters like GKE and CloudRun
I created some files with the Copilot answers in a new directory with VS Code
I then zipped it and imported it
While that one seemed to time out (still waiting), I did pull in the TF from my public GCPIMExample repo.
which rendered it in less than a minute
and in 3d
Graphviz and Terraform
We can get some basic diagrams using Terraform as wel.
I first need Graphviz if not installed already
builder@DESKTOP-QADGF36:/mnt/c/Users/isaac/Workspaces/TfExample$ sudo apt install graphviz
[sudo] password for builder:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
aspnetcore-runtime-3.1 aspnetcore-targeting-pack-3.1 aspnetcore-targeting-pack-6.0 dotnet-apphost-pack-3.1 dotnet-apphost-pack-6.0
dotnet-targeting-pack-3.1 dotnet-targeting-pack-6.0 fluent-bit libappstream-glib8 libdbus-glib-1-2 libfwupdplugin1 liblttng-ust-ctl4
liblttng-ust0 libxmlb1 python3-crcmod td-agent-bit
Use 'sudo apt autoremove' to remove them.
The following additional packages will be installed:
fonts-liberation libann0 libcdt5 libcgraph6 libgts-0.7-5 libgts-bin libgvc6 libgvpr2 liblab-gamut1 libpathplan4
Suggested packages:
graphviz-doc
The following NEW packages will be installed:
fonts-liberation graphviz libann0 libcdt5 libcgraph6 libgts-0.7-5 libgts-bin libgvc6 libgvpr2 liblab-gamut1 libpathplan4
0 upgraded, 11 newly installed, 0 to remove and 0 not upgraded.
Need to get 2701 kB of archives.
After this operation, 11.3 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://archive.ubuntu.com/ubuntu focal/main amd64 fonts-liberation all 1:1.07.4-11 [822 kB]
Get:2 http://archive.ubuntu.com/ubuntu focal/universe amd64 libann0 amd64 1.1.2+doc-7build1 [26.0 kB]
Get:3 http://archive.ubuntu.com/ubuntu focal/universe amd64 libcdt5 amd64 2.42.2-3build2 [18.7 kB]
Get:4 http://archive.ubuntu.com/ubuntu focal/universe amd64 libcgraph6 amd64 2.42.2-3build2 [41.3 kB]
Get:5 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgts-0.7-5 amd64 0.7.6+darcs121130-4 [150 kB]
Get:6 http://archive.ubuntu.com/ubuntu focal/universe amd64 libpathplan4 amd64 2.42.2-3build2 [21.9 kB]
Get:7 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgvc6 amd64 2.42.2-3build2 [647 kB]
Get:8 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgvpr2 amd64 2.42.2-3build2 [167 kB]
Get:9 http://archive.ubuntu.com/ubuntu focal/universe amd64 liblab-gamut1 amd64 2.42.2-3build2 [177 kB]
Get:10 http://archive.ubuntu.com/ubuntu focal/universe amd64 graphviz amd64 2.42.2-3build2 [590 kB]
Get:11 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgts-bin amd64 0.7.6+darcs121130-4 [41.3 kB]
Fetched 2701 kB in 1s (4435 kB/s)
Selecting previously unselected package fonts-liberation.
(Reading database ... 239202 files and directories currently installed.)
Preparing to unpack .../00-fonts-liberation_1%3a1.07.4-11_all.deb ...
Unpacking fonts-liberation (1:1.07.4-11) ...
Selecting previously unselected package libann0.
Preparing to unpack .../01-libann0_1.1.2+doc-7build1_amd64.deb ...
Unpacking libann0 (1.1.2+doc-7build1) ...
Selecting previously unselected package libcdt5:amd64.
Preparing to unpack .../02-libcdt5_2.42.2-3build2_amd64.deb ...
Unpacking libcdt5:amd64 (2.42.2-3build2) ...
Selecting previously unselected package libcgraph6:amd64.
Preparing to unpack .../03-libcgraph6_2.42.2-3build2_amd64.deb ...
Unpacking libcgraph6:amd64 (2.42.2-3build2) ...
Selecting previously unselected package libgts-0.7-5:amd64.
Preparing to unpack .../04-libgts-0.7-5_0.7.6+darcs121130-4_amd64.deb ...
Unpacking libgts-0.7-5:amd64 (0.7.6+darcs121130-4) ...
Selecting previously unselected package libpathplan4:amd64.
Preparing to unpack .../05-libpathplan4_2.42.2-3build2_amd64.deb ...
Unpacking libpathplan4:amd64 (2.42.2-3build2) ...
Selecting previously unselected package libgvc6.
Preparing to unpack .../06-libgvc6_2.42.2-3build2_amd64.deb ...
Unpacking libgvc6 (2.42.2-3build2) ...
Selecting previously unselected package libgvpr2:amd64.
Preparing to unpack .../07-libgvpr2_2.42.2-3build2_amd64.deb ...
Unpacking libgvpr2:amd64 (2.42.2-3build2) ...
Selecting previously unselected package liblab-gamut1:amd64.
Preparing to unpack .../08-liblab-gamut1_2.42.2-3build2_amd64.deb ...
Unpacking liblab-gamut1:amd64 (2.42.2-3build2) ...
Selecting previously unselected package graphviz.
Preparing to unpack .../09-graphviz_2.42.2-3build2_amd64.deb ...
Unpacking graphviz (2.42.2-3build2) ...
Selecting previously unselected package libgts-bin.
Preparing to unpack .../10-libgts-bin_0.7.6+darcs121130-4_amd64.deb ...
Unpacking libgts-bin (0.7.6+darcs121130-4) ...
Setting up liblab-gamut1:amd64 (2.42.2-3build2) ...
Setting up libgts-0.7-5:amd64 (0.7.6+darcs121130-4) ...
Setting up libpathplan4:amd64 (2.42.2-3build2) ...
Setting up libann0 (1.1.2+doc-7build1) ...
Setting up fonts-liberation (1:1.07.4-11) ...
Setting up libcdt5:amd64 (2.42.2-3build2) ...
Setting up libcgraph6:amd64 (2.42.2-3build2) ...
Setting up libgts-bin (0.7.6+darcs121130-4) ...
Setting up libgvc6 (2.42.2-3build2) ...
Setting up libgvpr2:amd64 (2.42.2-3build2) ...
Setting up graphviz (2.42.2-3build2) ...
Processing triggers for libc-bin (2.31-0ubuntu9.16) ...
/sbin/ldconfig.real: /usr/lib/wsl/lib/libcuda.so.1 is not a symbolic link
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for fontconfig (2.13.1-2ubuntu3) ...
I can then dump a plan to a graphviz digram
builder@DESKTOP-QADGF36:/mnt/c/Users/isaac/Workspaces/TfExample$ terraform graph -type=plan | dot -Tpng > graph.png
The raw output looks easy enough to manipulate. Here is a different TF repo with raw graph output:
builder@DESKTOP-QADGF36:~/Workspaces/gcpimexample$ terraform graph -type=plan
digraph {
compound = "true"
newrank = "true"
subgraph "root" {
"[root] google_container_cluster.primary (expand)" [label = "google_container_cluster.primary", shape = "box"]
"[root] google_container_node_pool.primary_preemptible_nodes (expand)" [label = "google_container_node_pool.primary_preemptible_nodes", shape = "box"]
"[root] google_service_account.default (expand)" [label = "google_service_account.default", shape = "box"]
"[root] google_storage_bucket.auto-expire (expand)" [label = "google_storage_bucket.auto-expire", shape = "box"]
"[root] google_storage_bucket.default (expand)" [label = "google_storage_bucket.default", shape = "box"]
"[root] provider[\"registry.terraform.io/hashicorp/google\"]" [label = "provider[\"registry.terraform.io/hashicorp/google\"]", shape = "diamond"]
"[root] provider[\"registry.terraform.io/hashicorp/random\"]" [label = "provider[\"registry.terraform.io/hashicorp/random\"]", shape = "diamond"]
"[root] random_id.bucket_prefix (expand)" [label = "random_id.bucket_prefix", shape = "box"]
"[root] var.bucketname" [label = "var.bucketname", shape = "note"]
"[root] var.projectid" [label = "var.projectid", shape = "note"]
"[root] google_container_cluster.primary (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/google\"]"
"[root] google_container_cluster.primary (expand)" -> "[root] var.projectid"
"[root] google_container_node_pool.primary_preemptible_nodes (expand)" -> "[root] google_container_cluster.primary (expand)"
"[root] google_container_node_pool.primary_preemptible_nodes (expand)" -> "[root] google_service_account.default (expand)"
"[root] google_service_account.default (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/google\"]"
"[root] google_service_account.default (expand)" -> "[root] var.projectid"
"[root] google_storage_bucket.auto-expire (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/google\"]"
"[root] google_storage_bucket.auto-expire (expand)" -> "[root] var.bucketname"
"[root] google_storage_bucket.auto-expire (expand)" -> "[root] var.projectid"
"[root] google_storage_bucket.default (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/google\"]"
"[root] google_storage_bucket.default (expand)" -> "[root] random_id.bucket_prefix (expand)"
"[root] google_storage_bucket.default (expand)" -> "[root] var.projectid"
"[root] provider[\"registry.terraform.io/hashicorp/google\"] (close)" -> "[root] google_container_node_pool.primary_preemptible_nodes (expand)"
"[root] provider[\"registry.terraform.io/hashicorp/google\"] (close)" -> "[root] google_storage_bucket.auto-expire (expand)"
"[root] provider[\"registry.terraform.io/hashicorp/google\"] (close)" -> "[root] google_storage_bucket.default (expand)"
"[root] provider[\"registry.terraform.io/hashicorp/random\"] (close)" -> "[root] random_id.bucket_prefix (expand)"
"[root] random_id.bucket_prefix (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/random\"]"
"[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/google\"] (close)"
"[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/random\"] (close)"
}
}
Pricing
Let’s first look at LucidScale which does all three major clouds. I really just see an annual option for $2000/year (avg $167/mo)
Hava, as we mentioned earlier is $249/mo
or $2390/annually
Cloudcraft has continued to tweak pricing post-Datadog acquisition. I was told that GCP was coming, but that was a long time ago and I still don’t see it. It’s $99/mo or $490/year (averages $40.83/mo if paid annually).
Holori Pricing is the cheapest at $49/mo or $470/year. Since this is on-par with CloudCraft, if Cloudcraft would get GCP support out the door, it would be a close call
We also have to consider Holori has Terraform/OpenToFu support.
Summary
Today we looked at a few cloud diagramming solutions such as Hava.io, LucidScale and Holori. The other big one out there is CloudCraft.co, but as they still do not support GCP, I didn’t explore it this time.
The fact that Lucid and Hava time out and then are locked down until one pays a very large sum mean I likely won’t come back, even if I think LucidScale is amazing (i would need some cheaper plan than $2000). However, Holori with it’s very reasonable free tier and $50/mo - I could easily see myself turning it on for a month or two to build a series of presentations.
If CloudCraft had a more reasonable per-month, I would consider it, but the lack of GCP is a real hassle (I have created GCP Diagrams in Cloudcraft manually just because I like it’s Isometric view).
Lastly, I touched on Graphviz. In July I did a whole post about Python Diagrams and Graphviz which I still use today. I’ve also written posts on MermaidJS which is natively supported in various GIT tooling including Azure Repos and Github. Graphviz, Python Diagrams (an extension thereof), and MermaidJS are nice open standards to “build it yourself”.