In previous FinOps as Code explorations, we introduced how you can apply Infrastructure as Code (IaC) techniques to the FinOps world. We walked through several FinOps use cases, showcasing how Terraform can automate and optimize cloud financial operations.

For practitioners who want to expand their FinOps as Code toolkit even further, enter Pulumi—a versatile IaC platform that functions as both a declarative and imperative tool using familiar programming languages. This blog will discuss some differences between Pulumi and Terraform, as well as provide an overview into how to use Pulumi from a FinOps as Code lens.

Pulumi: Getting Started

Pulumi is an open-source IaC tool that lets you define and deploy cloud infrastructure using familiar programming languages, like Python, TypeScript, Java, Go, C#, and others. You can use fundamental programming constructs in your infrastructure definitions, such as loops, conditionals, and functions. You can also create a desired infrastructure using both imperative (explicitly use code for each step) and declarative (describe the desired end state) approaches. Pulumi is cloud-agnostic, and you can create configurations for multiple cloud providers in a single Pulumi program.

To get started with Pulumi, install the Pulumi CLI and configure your language runtime, as well as any required access credentials. The Pulumi architecture consists of projects—or the directory that contains the source code. Projects contain programs—or the directions for how to create your infrastructure. Use the Pulumi CLI to create a stack—or an instance of your program.

Diagram of Pulumi architecture. Image courtesy of the Pulumi documentation.

Pulumi vs. Terraform: Comparing IaC Options

Visit any DevOps or IaC-related forum, and you’ll most likely come across a Terraform vs. Pulumi debate. Commenters will often focus on how Pulumi doesn’t require you to learn a domain-specific language (DSL), unlike Terraform, which typically uses HashiCorp Configuration Language (HCL).

The table below provides a high-level feature comparison of the two tools and is not meant to be an exhaustive comparison. Ultimately, tool choice comes down to personal preference, team preferences, or project-specific requirements.

Feature Pulumi Terraform
Declarative Syntax A declarative tool that uses imperative language to define the end state. Primarily declarative.
Language Support Multi-language support (e.g., TypeScript, Python, Java, Go). Primarily uses HCL, with limited support for JSON configurations. Terraform CDK can transpile familiar languages to HCL.
Licensing Apache 2.0 license. More restrictive BSL license.
State Management Offers management option via Pulumi Cloud, which is the default backend (free for individual use forever). By design, Pulumi also encrypts secrets in state files. Uses a centralized state file, which can be stored locally or remotely in various backends, such as Terraform Cloud.
Community, Documentation, and Support Growing community; offers a number of provider integrations. Newer Pulumi AI feature helps you create AI-generated infrastructures. Large and mature community with extensive provider support.
Learning Curve Potentially easier to pick up due to flexibility in language choice. You don’t need to learn a specific DSL. Moderate learning curve, especially for those new to IaC.
Provider Support Supports a variety of cloud providers and services. Expanded ecosystem now provides support for any Terraform provider. Provider support with well-established integrations for major cloud platforms and services.
Integration with CI/CD Integrates well with CI/CD pipelines and offers Pulumi Deployments for built-in automation. Supports CI/CD integration, with Terraform Cloud providing a managed workflow.

Comparing IaC options with Pulumi vs. Terraform

FinOps as Code with Pulumi

Pulumi is well suited for cloud cost optimization and FinOps, offering compatibility for all major clouds providers. Pulumi also offers an open-source Policy as Code product called CrossGuard, which helps organizations to maintain best practices and safeguards when creating infrastructure. For example, CrossGuard can enforce resource tagging rules to ensure cloud costs are appropriately allocated to the right department. FinOps practitioners can use Pulumi templates to get started and ensure infrastructure is defined in line with their organization’s financial standards.

The Pulumi integration with Vantage also provides another way for practitioners to further enhance their FinOps as Code process. In the following example, we’ll use the Vantage provider, on the Pulumi Registry, to demo a simplified workflow and architecture for a Marketing department that uses AWS and Snowflake.

Note: You can find all demo files on the FinOps as Code repository.

Prerequisites

Before you use the Vantage Pulumi provider, you’ll need a Vantage API token.

  • Store your API token as an environment variable with: export VANTAGE_API_TOKEN=<YOUR_TOKEN>.

  • Export the Vantage API host with: export VANTAGE_API_HOST="https://api.vantage.sh".

  • A Vantage account with at least one connected integration.

You also need to download and install Pulumi, if you have not already, and get a free Pulumi Cloud account to manage your infrastructure state and secrets.

Step 1: Install Packages and Credentials

Note: For continuity, the following demo mirrors our first FinOps as Code demo with Terraform and creates the same final cost reporting infrastructure.

Create a directory for your project, then create the Pulumi directory structure. We’ll use Python as the language of choice for this demo.

mkdir pulumi-vantage-example && cd pulumi-vantage-example
pulumi new python

You’ll be directed through a series of prompts that asks you to name your project and stack and select a toolchain for installing dependencies.

Project name (pulumi-vantage-example):
Project description (A minimal Python Pulumi program):
Created project 'pulumi-vantage-example'

Please enter your desired stack name.
To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
Stack name (dev): vantage
Created stack 'vantage'

The toolchain to use for installing dependencies and running the program  [Use arrows to move, type to filter]
> pip
  poetry
  uv

Pulumi will create the follow directory structure. The code will go in __main.py__. All the other files are maintained in the configuration details.

pulumi-vantage-example/
├── Pulumi.yaml
├── __main__.py
├── requirements.txt
└── venv/

Generate the Vantage provider as a local package.

pulumi package add terraform-provider vantage-sh/vantage

Obtain your workspace’s token from the /workspaces Vantage API endpoint. (You can also obtain this token from the Workspaces screen in the console.) Configure your Vantage workspace token as a Pulumi secret:

pulumi login
pulumi stack select vantage
pulumi config set --secret workspace_token <WORKSPACE_TOKEN>

The goal of this walkthrough will be to create a final dashboard that shows a hypothetical Marketing team’s Snowflake and AWS costs from the past six months, grouped by month.

Step 2: Import Packages and Define Variables

Within __main.py__, import the pulumi and pulumi_vantage packages. Import the secret you created for the workspace token.

import pulumi
import pulumi_vantage as vantage
config = pulumi.Config()
workspace_token = config.require_secret("workspace_token")

Step 3: Create an Outline of Your Cost Reporting Structure

Next, we’ll create what we want our cost reporting structure to look like. The structure will include:

  • Two Vantage folders—one for each cost provider—AWS and Snowflake

  • Two saved filters

  • Two Cost Reports that’ll go in the corresponding folders and use the corresponding saved filters

Create the report_structure list of dictionaries to consolidate the values for all Vantage resource names.

report_structure = [
    {
        "provider": "aws",
        "folder_title": "AWS Folder",
        "filter_title": "AWS Saved Filter",
        "report_title": "AWS Cost Report",
    },
    {
        "provider": "snowflake",
        "folder_title": "Snowflake Folder",
        "filter_title": "Snowflake Saved Filter",
        "report_title": "Snowflake Cost Report",
    },
]

Step 4: Define Functions to Create the Cost Reporting Structure

The create_cost_structure function will create the folders, saved filters, and Cost Reports. It uses the vantage.Folder, vantage.SavedFilter, and vantage.CostReport resources from the Pulumi provider. We’ll populate each input with the predefined report_structure dictionary values within the list. Once deployed, each resource will be assigned a logical ID that we can use to reference in other functions (i.e., vantage.CostReport("{}Report".format(provider) will translate to snowflakeReport).

def create_cost_structure(provider, folder_title, workspace_token, filter_title, report_title):
    folder = vantage.Folder("{}Folder".format(provider),
        title=folder_title,
        workspace_token=workspace_token)
    saved_filter = vantage.SavedFilter("{}Filter".format(provider),
        workspace_token=workspace_token,
        filter="(costs.provider = '{}')".format(provider),
        title=filter_title)
    report = vantage.CostReport("{}Report".format(provider),
        folder_token=folder.token,
        saved_filter_tokens=[saved_filter.token],
        title=report_title,
        chart_type="bar",
        date_bin="month")

    return folder, saved_filter, report

Use format strings as placeholders for the provider values. Note that the filter input of the vantage.SavedFilter resource uses VQL—or Vantage Query Language—to create the corresponding filter. The function also uses the chart_type and date_bin parameters to specify specific settings for the final reports.

Step 5: Iterate Through Reporting Structure and Create a Dashboard

Finally, we’ll call the create_cost_structure function and iterate through the report_structure list for each provider. The reports list will collect the token that Pulumi generates once each Cost Report is created. You can use this token in other resources. We’ll reference it in the widgetable_token variable so that both resulting Cost Reports are added to the dashboard.

reports = []

for report_info in report_structure:
    provider = report_info["provider"]
    folder, saved_filter, report = create_cost_structure(
        provider,
        report_info["folder_title"],
        workspace_token,
        report_info["filter_title"],
        report_info["report_title"]
    )

    reports.append(report.token)

marketing_dashboard = vantage.Dashboard("marketingDashboard",
    workspace_token=workspace_token,
    date_interval="last_6_months",
    title="Marketing Dashboard",
    widgets=[{
        "settings": { "display_type": "chart" },
        "widgetable_token": token
    } for token in reports])

Step 6: Deploy Your Infrastructure

Deployments are very straightforward in Pulumi. When you are ready to deploy, run pulumi up. You’ll be prompted to confirm the update.

Note: You can run pulumi preview if you want to just see a preview of the resources that’ll be created without actually deploying the infrastructure.

❯ pulumi up
Previewing update (vantage)

View in Browser (Ctrl+O):

     Type                          Name                            Plan
     pulumi:pulumi:Stack           pulumi-vantage-example-vantage
 +   ├─ vantage:index:SavedFilter  snowflakeFilter                 create
 +   ├─ vantage:index:CostReport   awsReport                       create
 +   ├─ vantage:index:CostReport   snowflakeReport                 create
 +   ├─ vantage:index:Dashboard    marketingDashboard              create
 +   ├─ vantage:index:SavedFilter  awsFilter                       create
 +   ├─ vantage:index:Folder       awsFolder                       create
 +   └─ vantage:index:Folder       snowflakeFolder                 create

Resources:
    + 7 to create
    1 unchanged

Do you want to perform this update?  [Use arrows to move, type to filter]
> yes
  no
  details

Once deployed, you’ll have a dashboard with two reports, each stored in the corresponding cost provider’s folder and preconfigured with their corresponding saved filter.

Final cloud cost architecture in Vantage

Conclusion

Pulumi expands the FinOps as Code toolkit with flexible, multi-language IaC management. With the Vantage Pulumi provider, you can easily integrate cost reporting into your existing workflows and ensure financial accountability across all your cloud environments.