InfraWallet logo

Backstage InfraWallet Plugin

Created by Electrolux Group

InfraWallet brings cloud cost visibility into your Backstage portal. It aggregates reports from AWS, Azure, Google Cloud, Confluent Cloud, Datadog, Elastic, GitHub, and MongoDB Atlas. It normalizes provider data so you can view costs in one place. You can group by account, provider, category, service, or tags. Cached data keeps pages fast. You can record custom costs when an integration is not available.

The plugin fits teams that want a shared picture of spend without leaving Backstage. Track monthly trends by team or service. Compare environments during a migration. Validate tag hygiene. Give product owners a simple view of what changed this quarter. Support FinOps workflows where engineers work.

If your goal is to give engineers clear spend data next to the services they own, InfraWallet provides a focused, practical path inside Backstage.

Installation Instructions

These instructions apply to self-hosted Backstage only.

Install the frontend package

  1. Add the package
Copy
yarn --cwd packages/app add @electrolux-oss/plugin-infrawallet
  1. Add the route so the page is visible

Edit packages/app/src/App.tsx

Copy
import React from 'react';
import { Route } from 'react-router';
import { FlatRoutes } from '@backstage/core-app-api';
import { InfraWalletPage } from '@electrolux-oss/plugin-infrawallet';

export const AppRoutes = () => (
  <FlatRoutes>
    {/* your other routes */}
    <Route path="/infrawallet" element={<InfraWalletPage />} />
  </FlatRoutes>
);
  1. Optional. Set a custom title or subtitle
Copy
<Route
  path="/infrawallet"
  element={<InfraWalletPage title="Cloud costs" subTitle="Across all providers" />}
/>
  1. Optional. Add a sidebar item

Edit packages/app/src/components/Root/Root.tsx

Copy
import React from 'react';
import { Sidebar, SidebarGroup, SidebarItem } from '@backstage/core-components';
import MenuIcon from '@material-ui/icons/Menu';
import { InfraWalletIcon } from '@electrolux-oss/plugin-infrawallet';

export const Root = ({ children }: { children?: React.ReactNode }) => (
  <Sidebar>
    {/* your other sidebar groups */}
    <SidebarGroup label="Menu" icon={<MenuIcon />}>
      <SidebarItem
        icon={InfraWalletIcon}
        to="infrawallet"
        text="InfraWallet"
      />
    </SidebarGroup>
  </Sidebar>
);

InfraWallet will be available at path /infrawallet

Install the backend plugin

New backend system

  1. Add the package
Copy
yarn --cwd packages/backend add @electrolux-oss/plugin-infrawallet-backend
  1. Register the plugin in the backend

Edit packages/backend/src/index.ts
Add this before backend.start

Copy
// other imports and setup above

// InfraWallet backend
backend.add(import('@electrolux-oss/plugin-infrawallet-backend'));

backend.start();

Legacy backend system

  1. Add the package
Copy
yarn --cwd packages/backend add @electrolux-oss/plugin-infrawallet-backend
  1. Create a plugin router

Create packages/backend/src/plugins/infrawallet.ts

Copy
import { createRouter } from '@electrolux-oss/plugin-infrawallet-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';

export default async function createPlugin(env: PluginEnvironment): Promise<Router> {
  return await createRouter({
    logger: env.logger,
    config: env.config,
    cache: env.cache.getClient(),
    database: env.database,
  });
}
  1. Wire it into the backend

Edit packages/backend/src/index.ts

Copy
// other imports
import infraWallet from './plugins/infrawallet';

async function main() {
  // other setup
  const infraWalletEnv = useHotMemoize(module, () => createEnv('infrawallet'));

  apiRouter.use('/infrawallet', authMiddleware, await infraWallet(infraWalletEnv));
}

Configure frontend defaults

Add this to app-config.yaml if you want to change the default view

Copy
infraWallet:
  settings:
    defaultGroupBy: none  # none by default, or account, provider, category, service, tag:<tag_key>
    defaultShowLastXMonths: 3  # we recommend less than 12

Configure provider integrations

All provider credentials live under backend.infraWallet.integrations in app-config.yaml

AWS setup

Give the IAM role these permissions

Copy
{
  "Statement": [
    {
      "Action": ["ce:GetCostAndUsage", "ce:GetTags"],
      "Effect": "Allow",
      "Resource": "*",
      "Sid": ""
    }
  ],
  "Version": "2012-10-17"
}

Use one role in the management account to read all member accounts when you use AWS Organizations
If you do not use a management account then create the role in each account and set trust per account

Add the config

Copy
backend:
  infraWallet:
    integrations:
      aws:
        - name: my-aws
          accountId: '123456789012'  # quoted as a string
          assumedRoleName: infrawallet-reader
          accessKeyId: ${AWS_ACCESS_KEY_ID}  # optional
          secretAccessKey: ${AWS_SECRET_ACCESS_KEY}  # optional

If accessKeyId and secretAccessKey are not set the SDK uses the default credential chain

Azure setup

  1. Register an app in Azure AD
  2. In the subscription grant Cost Management Reader to the app
  3. Create a client secret

Add the config

Copy
backend:
  infraWallet:
    integrations:
      azure:
        - name: my-azure
          subscriptionId: ${AZURE_SUBSCRIPTION_ID}
          tenantId: ${AZURE_TENANT_ID}
          clientId: ${AZURE_CLIENT_ID}
          clientSecret: ${AZURE_CLIENT_SECRET}

GCP setup

Export billing data to Big Query
Create a service account with roles BigQuery Data Viewer and BigQuery Job User
Create a JSON key file for that service account

Add the config

Copy
backend:
  infraWallet:
    integrations:
      gcp:
        - name: my-gcp
          keyFilePath: /secure/path/gcp-key.json  # mount as a file in your runtime
          projectId: my-billing-project
          datasetId: my_bq_dataset
          tableId: gcp_billing_export

Confluent Cloud setup

Create an organization level API key with cloud resource management scope

Add the config

Copy
backend:
  infraWallet:
    integrations:
      confluent:
        - name: my-confluent
          apiKey: ${CONFLUENT_API_KEY}
          apiSecret: ${CONFLUENT_API_SECRET}

MongoDB Atlas setup

Create an organization API key with Organization Billing Viewer permission

Add the config

Copy
backend:
  infraWallet:
    integrations:
      mongoatlas:
        - name: my-mongoatlas
          orgId: ${MONGODB_ATLAS_ORG_ID}
          publicKey: ${MONGODB_ATLAS_PUBLIC_KEY}
          privateKey: ${MONGODB_ATLAS_PRIVATE_KEY}

Multiple accounts example

Copy
backend:
  infraWallet:
    integrations:
      azure:
        - name: fin-team
          subscriptionId: ...
          tenantId: ...
          clientId: ...
          clientSecret: ...
        - name: core-team
          subscriptionId: ...
          tenantId: ...
          clientId: ...
          clientSecret: ...
      aws:
        - name: dev
          accountId: '123456789012'
          assumedRoleName: ...
          accessKeyId: ...
          secretAccessKey: ...
        - name: prod
          accountId: '210987654321'
          assumedRoleName: ...
          accessKeyId: ...
          secretAccessKey: ...

Category mappings

The plugin stores category mappings in the database
If the table is empty it seeds with defaults from plugins /infrawallet-backend/seeds/init.js
You can change that seed file or update the table later

Where you will see it

The page lives at /infrawallet Use the sidebar item if you want quick access from the left menu

Changelog

This changelog is produced from commits made to the InfraWallet plugin since 5 months ago, and based on the code located here. It may not contain information about all commits. Releases and version bumps are intentionally omitted. This changelog is generated by AI.

Breaking changes

  • #167 Rename AWS config key accessKeySecret to secretAccessKey. Update your config to keep things working. 3 months ago
  • #174 Disable autoload by default. If you rely on autoload you need to enable it in your config. 3 months ago

Features

  • #189 Add budget datapoints and breakdowns on the budgets page. 1 month ago
  • #186 Add extension point for EntityReports. The EntityInfraWalletCard can use custom entity data. 1 month ago
  • #163 Add GitHub support. 4 months ago

Bug fixes

  • #197 Fix schema validation for providers in non default setups. Add logging to help debug the transform step. Restore missing icons. 6 days ago
  • #191 Fix number formatting in the cost graph. 1 month ago
  • #188 Fix GCP cost fetching to avoid data loss on fetch errors. 2 months ago

Improvements

  • #177 Improve UI loading for the entity card. 3 months ago

Security

  • #173 Secure GitHub token handling for DevTools. 3 months ago
  • #160 Fix scorecard vulnerabilities. 4 months ago

Documentation

  • #183 Update docs. 3 months ago
  • #182 Update Datadog doc. 3 months ago
  • #175 Update README. 3 months ago
  • #172 Add docs for Elastic Cloud. 3 months ago
  • #195 Add PitchBook to adopters. 1 month ago

Dependencies

  • #161 Upgrade Backstage and dependencies. 4 months ago

Set up Backstage in minutes with Roadie