Security
Trusted access. No surprise remediations.
FinOps tools fail when teams fear automatic changes. SpendPilot earns trust with read-only scanning by default on AWS, Azure, and GCP—and an approve → fix → verify workflow. Optional approve-then-delete only when you opt in.
Free audit or product connect: set up one cloud (AWS, Azure, or GCP). Jump to setup: AWS · Azure · GCP.
Human-gated changes
Scanning stays read-only by default. Optional approve-then-delete (AWS: unattached EBS, idle EIPs, old snapshots; Azure: unattached disks, unused public IPs; GCP: unattached Persistent Disks, unused static IPs) only runs after an engineer clicks Approve & delete on an opted-in account — never on scan, never without confirmation.
Multiple connect methods
AWS: IAM access keys, temporary session credentials, or a cross-account IAM role (role recommended). Azure: service principal (tenant, client ID, secret) with Reader + Cost Management Reader. GCP: service account JSON key with Viewer + BigQuery Data Viewer on the billing export dataset. Secrets are encrypted at rest.
Least-privilege policies
AWS sample policy covers Cost Explorer and describe/list inventory APIs and denies destructive actions. Azure needs Reader + Cost Management Reader for sync/scan; attach the separate remediation role only if you enable auto-delete. GCP needs project Viewer for inventory and BigQuery Data Viewer for billing export; attach the downloadable SpendPilot remediation role only if you enable Approve & delete.
Region / subscription / project control
On AWS and GCP you choose which regions to waste-scan (country presets available). On Azure scans are subscription-scoped via Resource Graph. Cost sync reflects account spend in your display currency across all three clouds.
Tenant isolation & access control
Org data is scoped by organisation ID. Deactivated users cannot sign in or call APIs. Platform support access is audited when staff enter a customer org.
Global FinOps, local tax where needed
Savings and plans in your display currency (USD, INR, EUR, GBP). India billing profiles support GST invoices; other regions use tax invoices suited to your profile as we expand payments.
Report a vulnerability
If you believe you found a security issue in SpendPilot, email security@spendpilot.dev. Please include steps to reproduce and avoid accessing customer data beyond what is needed to demonstrate the issue. We aim to acknowledge reports within two business days.
Engineer docs: docs/security/threat-model.md, incident-response.md, key-rotation.md, data-map-and-privacy.md, subprocessors.md
Setup guides
Cloud access setup
Pick the cloud you want reviewed for the free audit—or connect in the product later. You only need one.
AWS — connect an account
- Prefer a cross-account IAM role (External ID). Access keys or temporary credentials also work.
- Deploy the CloudFormation template below (or attach the read-only policy JSON), then paste the Role ARN + External ID under Cloud accounts → AWS after you register.
- For a free audit, send us the Role ARN / External ID securely—we never need write access.
Sample read-only IAM policy
Works the same in US, EU, APAC, and India commercial partitions. Attach this policy to a dedicated role or user SpendPilot assumes or keys into. Cost Explorer is global; inventory APIs run in the regions you select to scan.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CostExplorerRead",
"Effect": "Allow",
"Action": ["ce:GetCostAndUsage", "ce:GetCostForecast", "ce:GetAnomalies"],
"Resource": "*"
},
{
"Sid": "InventoryDescribe",
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"rds:Describe*",
"elasticloadbalancing:Describe*",
"elasticache:Describe*",
"cloudwatch:GetMetricStatistics",
"compute-optimizer:Get*",
"s3:ListAllMyBuckets",
"s3:ListBucketMultipartUploads"
],
"Resource": "*"
},
{
"Sid": "DenyDestructive",
"Effect": "Deny",
"Action": ["ec2:TerminateInstances", "ec2:Delete*", "rds:DeleteDBInstance"],
"Resource": "*"
}
]
}Cross-account trust (IAM role)
Prefer a role with ExternalId over long-lived access keys. Replace the platform account id and use the ExternalId SpendPilot shows when you connect.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::SPENDPILOT_ACCOUNT_ID:root" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "sts:ExternalId": "YOUR_ORG_EXTERNAL_ID" }
}
}
]
}Downloads
Use these files in the AWS Console. Recommended: deploy the CloudFormation template (creates the role + policy). Use the policy JSON only if you prefer a dedicated IAM user with access keys.
- Download YAML
CloudFormation role template
spendpilot-readonly-role.yaml— createsSpendPilotReadOnlywith trust + read-only policy - Download JSON
IAM policy JSON
spendpilot-readonly-policy.json— attach to an IAM user or role if not using CloudFormation - Download JSON
Optional remediation policy
spendpilot-remediation-policy.json— allows approve-then-delete for unattached EBS, idle EIPs, and old snapshots. Attach separately; remove DenyDestructive for those actions. Then enable auto-delete on the AWS account in SpendPilot.
After the role exists, create an account and paste the Role ARN + External ID under AWS accounts.
Other clouds
- Azure: service principal with Reader + Cost Management Reader. Full Azure setup →
- GCP: service account with project Viewer + BigQuery access on the billing export. Full GCP setup →
Full setup: how it works · free audit.
Azure — connect a subscription
Connect a subscription with a Microsoft Entra app registration(service principal). SpendPilot stays read-only unless you attach the optional remediation role and enable Approve & delete.
- Create an App registration — Azure Portal → Microsoft Entra ID → App registrations → New registration. Name it e.g.
SpendPilot. Note the Application (client) ID and Directory (tenant) ID. - Create a client secret — Certificates & secrets → New client secret. Copy the Value once (it is not shown again).
- Assign roles on the subscription — Subscriptions → your subscription → Access control (IAM) → Add role assignment. Grant the app’s service principal:
- Reader — inventory / Resource Graph waste scan
- Cost Management Reader — Cost Management spend sync
- Connect in SpendPilot — Cloud accounts → Azure. Paste Subscription ID, Tenant ID, Application (client) ID, and client secret. Use Validate & connect, then Sync costs and Scan waste.
- Optional — Approve & delete — Create a custom role from the download below (disk + public IP delete only), assign it to the same service principal, then enable “Allow Approve & delete” on the subscription in SpendPilot.
Downloads
- Download JSON
Optional remediation custom role
spendpilot-remediation-role.json— replace{subscriptionId}in AssignableScopes, then create the custom role in Azure IAM.
After the app registration exists, create an account and connect under Cloud accounts → Azure.
GCP — connect a project
Connect a GCP project with a service account JSON key. Cost sync needs a Cloud Billing → BigQuery export. Waste scan stays read-only unless you attach the optional remediation role.
- Enable APIs — In the target project, enable Cloud Resource Manager, Compute Engine, BigQuery, and (optional) Cloud SQL Admin.
- Billing export to BigQuery — Billing → Billing export → enable BigQuery export (detailed usage). Note the dataset and table names.
- Create a service account — IAM → Service accounts → Create (e.g.
spendpilot-readonly). Grant:- Project: roles/viewer (or Browser) — connection test + inventory
- Export dataset: roles/bigquery.dataViewer + roles/bigquery.jobUser — cost sync
- Download a JSON key — Keys → Add key → JSON. Store it securely; paste into SpendPilot once (encrypted at rest). Prefer rotating keys regularly.
- Connect in SpendPilot — Cloud accounts → GCP. Paste Project ID, billing export dataset/table, and the SA JSON. Use Validate & connect, set scan regions (defaults follow org country), then Sync costs / Scan waste.
- Optional — Approve & delete — Create a custom role from the YAML below (unattached Persistent Disk + unused static IP delete only), bind it to the same SA, then enable “Allow Approve & delete” on the project in SpendPilot.
Downloads
- Download YAML
Optional remediation custom role
spendpilot-remediation-role.yaml— disk + static IP delete only
After the service account exists, create an account and connect under Cloud accounts → GCP.
Ready to connect yourself? Create an account or request a free audit.