SQL tools that read every cloud API are among the most useful defender tools and, in the wrong hands or with the wrong credentials, among the fastest ways to map an estate. CloudQuery and Steampipe both turn cloud and SaaS APIs into tables you can query with SQL, which makes asset inventory, posture checks and investigations far quicker than writing scripts. Both also need broad read credentials across every account they cover, and the query traffic they generate looks much like an intruder's discovery phase. This guide explains how each tool works, how to deploy them with least privilege, how to protect the data they collect, and how to tell sanctioned inventory runs from misuse in CloudTrail and other logs. It is for cloud security engineers, platform teams and detection engineers. Tools are listed alphabetically in the body of the page; order is not a ranking.
This is an independent guide from NHI Mgmt Group, based on CloudQuery's public documentation and Steampipe's public documentation as of November 2026. It is not sponsored or reviewed by CloudQuery or Turbot. Product features change, so confirm settings against each project's current documentation.
Key takeaways
- Two models, one risk. CloudQuery syncs cloud metadata into a destination such as PostgreSQL or a data warehouse, while Steampipe queries the APIs live on demand; both hold read credentials that span every account in scope.
- The collector identity is a high-value non-human identity. A role that can list and describe everything in an organisation is a ready-made reconnaissance kit, so scope it, give it short-lived credentials and monitor it like a privileged account.
- Read-only is not harmless. Steampipe's AWS plugin documentation suggests the AWS ReadOnlyAccess policy, which also covers many data reads; narrow it to what your tables need.
- Protect where the data lands. A CloudQuery destination or a Steampipe service database is a map of your estate, including security group rules and IAM policies, and deserves the same access control as the cloud consoles.
- Baseline the sanctioned runs. Known role names, session names, schedules and source networks make it easy to spot the same discovery pattern coming from anywhere else.
What the two tools do
Both projects map provider APIs to SQL tables through plugins. They differ in when the API calls happen and where the results live.
| Aspect | CloudQuery | Steampipe |
|---|---|---|
| Model | Extract and load: cloudquery sync reads sources and writes to destinations | Live query: a PostgreSQL endpoint calls provider APIs when a query runs |
| Where data lives | Your chosen destination, for example PostgreSQL, BigQuery, Snowflake, S3, ClickHouse or Kafka | Query results in memory, with a result cache (STEAMPIPE_CACHE_TTL default 300 seconds) |
| Scope | AWS, Azure, Google Cloud and, per its README, more than 70 cloud and SaaS sources | Plugins for cloud providers and SaaS services, each configured as a connection |
| Licence | Repository under the Mozilla Public License 2.0; framework, SDK, CLI and some integrations open source | CLI under AGPL-3.0; the AWS plugin under Apache 2.0 |
| Typical use | Scheduled inventory, historical snapshots, joins with other warehouse data | Ad hoc investigation, interactive checks, dashboards over live data |
Where these tools sit among other open source projects is covered in the Open Source Cloud Security Tools Landscape Guide. This page goes deeper on running these two safely.
CloudQuery
CloudQuery describes itself as a cloud asset inventory that syncs infrastructure metadata into your data warehouse, and states that it runs on your infrastructure so the data does not pass through CloudQuery's servers. A sync is driven by YAML specifications for each source and destination. Security-relevant settings from the AWS plugin documentation:
- Authentication: environment variables, shared credential files, a per-account
local_profile, AWS SSO sessions, compute roles on EC2, ECS and Fargate, and role assumption withrole_arn,role_session_nameandexternal_id. - Organisations: the
orgblock takesmember_role_name(defaultOrganizationAccountAccessRole, and the docs advise creating dedicated read-only roles instead),admin_account,organization_unitsandskip_member_accounts. The admin identity needsorganizations:ListAccounts,ListAccountsForParentandListChildren. - Scope reduction:
skip_tables,skip_regionsandskip_specific_apislimit what is called, anduse_paid_apisdefaults to false. - Hub credential:
cloudquery loginis required to download plugins from CloudQuery Hub; for automation an API key is set inCLOUDQUERY_API_KEY, with a choice of "Syncs operations only" or "Read and write" scope and a mandatory expiry date. - Run evidence:
cloudquery sync --summary-locationappends a JSON line per sync with the sync ID, start time and duration, which is useful for reconciling runs with CloudTrail. - Availability: as of November 2026, some integrations are closed source and usage of the AWS plugin counts toward a plan's row quota, per CloudQuery's documentation.
Steampipe
Steampipe exposes plugins as a PostgreSQL-compatible database. Security-relevant settings from the Steampipe and AWS plugin documentation:
- Two run modes:
steampipe querystarts the database on the loopback address only and stops it when the session ends;steampipe service startruns it as a service on port 9193 with usersteampipeand a generated password. - Listen setting: the database
listenoption defaults tonetworkin service mode. Set it tolocal, or pass--database-listen local, unless remote clients genuinely need access; the dashboard has a matching--dashboard-listenoption. - Password: set it with
--database-passwordor STEAMPIPE_DATABASE_PASSWORD and store it in a secrets manager;--show-passwordprints it, so keep that out of shared terminals and logs. - Credentials: the AWS plugin resolves credentials in order from the connection file (
~/.steampipe/config/aws.spc), environment variables, the profile named in AWS_PROFILE, the default profile, then an EC2 instance role. Named profiles allow SSO and role assumption. - Aggregators: an aggregator connection queries many accounts as one. The docs warn that three connections across 16 regions means the same list call runs 48 times, which is also what your detection will see.
- Availability: as of November 2026, Steampipe's docs describe a hosted option, Turbot Pipes, alongside the self-run CLI.
Deployment patterns and their risks
| Pattern | Credential | Main risk | Control |
|---|---|---|---|
| Engineer laptop, ad hoc | Personal SSO profile | Results and credentials on an unmanaged device; queries run with the engineer's full rights | Use a dedicated read-only permission set; local-only listen; no static keys in config files |
| Scheduled job in a security account | Instance or task role assuming member roles | One role reaches every account | Dedicated member role, trust policy limited to the collector role, external ID, SCP guardrails |
| Shared service database | Database password plus cloud role | Network-exposed PostgreSQL with the whole estate's metadata | Private subnet, TLS, per-user database accounts, no public listener |
| Warehouse destination | Destination write credential | Broad analyst access to sensitive configuration data | Separate schema, role-based access, retention policy, audit logging |
| CI pipeline checks | OIDC federated role | Pipeline compromise yields read access to production metadata | Scope to one account, short session, run only on protected branches |
Securing the collector identity
The role or service account that CloudQuery or Steampipe uses is a non-human identity with organisation-wide reach. Treat it with the same care as any privileged machine identity.
- Use a dedicated identity per tool and purpose. Do not reuse
OrganizationAccountAccessRoleor an administrator role. Create a member role whose trust policy names only the collector role, and add an external ID condition. See How to review AWS cross-account trust policies for confused deputy. - Grant metadata reads, not data reads. AWS ReadOnlyAccess includes reads of data such as objects and table items. Start from the narrower AWS managed policies for audit or view-only access, then add the specific actions your tables need, using the per-table permission lists in each plugin's documentation. The AWS IAM Policies and Roles Guide covers policy design.
- Prefer short-lived credentials. Run from a compute role, SSO or OIDC federation instead of static access keys. If a key is unavoidable, keep it in a secrets manager and rotate it. See the AWS Access Keys Security Guide.
- Name sessions consistently. Set
role_session_name(CloudQuery) or a named profile with a fixed session name (Steampipe) so CloudTrail shows a predictable value you can baseline. - Apply the same rules outside AWS. Use the Reader role or narrower custom roles on Azure subscriptions and Viewer or narrower roles in Google Cloud, assigned to a dedicated service principal or service account with federated credentials.
- Protect the tool's own credentials. A CloudQuery Hub API key with "Read and write" scope, or a Steampipe service password, is a secret in its own right. Scope it, expire it and store it centrally.
Organisation-wide guardrails for these roles are covered in the AWS Organizations and SCPs Guide.
Protecting the collected data
An inventory database answers exactly the questions an intruder asks: which security groups allow 0.0.0.0/0, which roles trust external accounts, which buckets are public, which instances run old images. Protect it accordingly.
- Network: no public listener for a Steampipe service or a CloudQuery PostgreSQL destination; private subnets and security groups limited to named clients.
- Access: per-user database roles rather than one shared login, and read access limited to teams that need it.
- Encryption: TLS for client connections and encryption at rest for destination stores and snapshots.
- Sensitive columns: some tables can include values such as environment variables or tags that hold secrets; use skip options to drop tables you do not need and scan the destination for credentials. See the Secrets Management Guide.
- Retention: keep historical CloudQuery snapshots only as long as investigations and audits need them.
Detecting misuse and unsanctioned runs
Inventory tools produce the same API pattern as an intruder's discovery phase: ATT&CK T1580 Cloud Infrastructure Discovery, T1526 Cloud Service Discovery, T1087.004 Cloud Account discovery and T1619 Cloud Storage Object Discovery. The sanctioned run is a known identity from a known place at a known time; anything else is worth a look.
| Signal | Where to see it | Interpretation |
|---|---|---|
| Burst of List, Describe and Get calls across many services and regions | CloudTrail management events | Expected from the collector role on schedule; suspicious from a user or workload role |
| Collector role used from an unexpected source IP, VPC endpoint or outside its schedule | CloudTrail sourceIPAddress, vpcEndpointId, event time | Possible credential theft or an engineer running the tool outside policy |
| Unexpected session name on the member role | CloudTrail userIdentity.arn session component | Someone else assuming the collector role |
| Discovery:IAMUser/AnomalousBehavior finding | Amazon GuardDuty | Anomalous discovery-stage requests such as DescribeInstances, GetRolePolicy or ListAccessKeys from one identity |
| GetCallerIdentity from a new principal followed by wide enumeration | CloudTrail | Classic first step with stolen keys |
| Port 9193 listening on hosts outside the approved list | Vulnerability scanner, EDR network events | A Steampipe service started in network mode on an unapproved host |
| New CloudQuery or Steampipe binaries on endpoints or build agents | EDR software inventory | Shadow use that needs an owner and a sanctioned identity |
The TruffleNet campaign shows why this matters: attackers used GetCallerIdentity and GetSendQuota calls from more than 800 hosts to test stolen AWS keys at scale. A baseline of your own sanctioned discovery traffic makes such calls stand out. See the TruffleNet stolen AWS keys case, the AWS CloudTrail Guide and How to Detect aws access key use from unusual locations.
Rolling out a sanctioned inventory capability
- Decide the model. Choose scheduled sync to a store (historical record, joins with other data) or live query (fresh answers, nothing stored), or both for different teams.
- Pilot in one non-production account. Create the dedicated role, run the tool, and record exactly which API actions it calls from CloudTrail. Use that list to tighten the policy.
- Write the baseline. Document role name, session name, source network, schedule and expected call volume. Turn it into detection allowlist entries scoped to all five attributes, not just the role name.
- Expand by organisational unit. Add accounts in rings, watching for throttling and for alerts from GuardDuty or your SIEM that need tuning.
- Lock down the data store. Apply the network, access and retention controls above before analysts get access.
- Roll back cleanly. If the collector causes throttling or a permission is too broad, disable the schedule, remove the member role from the affected OU through your infrastructure as code, and keep the CloudTrail baseline for comparison.
Decision guidance
- Need history and trends: a sync-and-store model suits compliance evidence and change tracking, at the cost of protecting a new data store.
- Need fresh answers during an incident: live query avoids stale data and stores nothing long-term, at the cost of API load and throttling during large queries.
- Small organisations: one account or a handful of accounts, run interactively from a hardened admin workstation with SSO, local-only listen and no stored results, is usually enough.
- Large organisations: a central security account, dedicated member roles deployed by StackSets or equivalent, a protected destination, and the collector registered as a privileged non-human identity with an owner.
- Already have CSPM or CAASM: use these tools for questions the platform cannot answer and keep their identities as tightly scoped as the platform's. See the Cloud Security Posture Management (CSPM) Guide.
Detection and measurement
- Collector identity scope: number of actions granted versus actions actually used in the last 90 days (target: gap trending to zero).
- Credential age: share of collector credentials that are short-lived (target 100%).
- Coverage: percentage of cloud accounts and subscriptions included in the inventory.
- Exposure: count of inventory databases reachable from outside approved networks (target zero).
- Anomaly rate: discovery-pattern alerts from identities other than the collector, and time to triage each.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev. 5 | CM-8 System Component Inventory; CA-7 Continuous Monitoring; AC-6 Least Privilege; IA-5 Authenticator Management; AU-12 Audit Record Generation | Inventory purpose, collector privilege and credential handling, logging |
| NIST CSF 2.0 | ID.AM-02; ID.AM-08; PR.AA-05; DE.CM-03 | Asset inventories, least privilege, monitoring technology usage |
| CIS Controls v8.1 | Control 1 Inventory and Control of Enterprise Assets; Control 6 Access Control Management; Control 8 Audit Log Management | Inventory, access to the collector, logging of its use |
| ISO/IEC 27001:2022 Annex A | A.5.9 Inventory of information and other associated assets; A.8.2 Privileged access rights; A.8.15 Logging | Inventory, privileged identity, logging |
| MITRE ATT&CK | T1580; T1526; T1087.004; T1619; T1078.004 Cloud Accounts | Discovery techniques the tools resemble; misuse of the collector's cloud account |
| MITRE D3FEND | D3-AI Asset Inventory | The defensive purpose of both tools |
Common failure patterns
- Running as an administrator: using
OrganizationAccountAccessRoleor an admin profile because it is already there, so the inventory tool can change what it reads. - Static keys in config files: access keys pasted into
aws.spcor a sync YAML file and committed to a repository; the EmeraldWhale case shows how quickly exposed configuration files yield cloud credentials. - Service mode left on the network: a Steampipe service on a jump host listening on all interfaces with a shared password.
- Allowlisting by role name only: suppressing discovery alerts for the collector role from anywhere, so a stolen session looks routine.
- Unprotected warehouse: inventory tables in a broadly shared analytics schema.
Practitioner checklist
- Register each CloudQuery or Steampipe deployment with an owner, purpose and identity.
- Replace admin and ReadOnlyAccess grants with a dedicated metadata-read role per account.
- Restrict member role trust to the collector role and add an external ID.
- Remove static keys; use compute roles, SSO or OIDC federation.
- Set Steampipe service listen to local unless remote access is approved, and set a managed password.
- Scope CloudQuery Hub API keys to "Syncs operations only" with an expiry date.
- Put inventory stores on private networks with per-user access and encryption.
- Baseline collector activity by role, session name, source, schedule and volume, and alert on deviations.
- Alert on wide discovery patterns from any identity that is not the collector.
Standards and references
- CloudQuery: AWS source plugin documentation
- CloudQuery: Generate API key
- CloudQuery: Project repository and CLI reference
- Steampipe: Service mode documentation
- Steampipe: Options configuration reference
- Steampipe: AWS plugin documentation
- AWS: GuardDuty IAM finding types
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: Open Source Cloud Security Tools Landscape Guide · Cloud IAM Review Checklist · Asset Inventory and CMDB Security Guide · Cloud Workload Identity Guide · Cross-Account and Cross-Tenant Access Guide