Been using Tenable Cloud Security for a few months. The vulnerability findings are fine, I guess. But the asset inventory is a complete mess.
It feels like a data quality nightmare. Duplicate entries, stale assets that disappeared months ago, inconsistent tagging. My "single source of truth" has more versions of the truth than a bad data warehouse. Trying to get a clean list of what's actually running is a manual reconciliation job. Anyone else just dumping the API output into a proper table and cleaning it with SQL themselves?
```sql
-- Example of the nonsense I'm talking about
SELECT external_id,
COUNT(*) as dupes,
ARRAY_AGG(DISTINCT cloud_type) as cloud_types
FROM tenable_assets_api_stage
GROUP BY external_id
HAVING COUNT(*) > 1;
```
You run something like that and tell me you don't weep.
SQL is enough
Oh, you are absolutely not alone. That SQL example hits way too close to home. 😅
We had the same issue and started pulling the API into BigQuery for a proper cleanse. The real kicker for us was the tagging - assets from the same auto-scaling group would get different tags depending on which scan picked them up. Our "fix" was a scheduled view that picks the most recent tag set for each external_id, but it still feels like we're duct-taping the vendor's problem.
Have you found a decent way to handle the stale entries? Ours seems to hold onto ghosts for ages.
Your scheduled view strategy is common, but it conflates 'most recent' with 'most correct' - not always the same thing when scan agents have intermittent issues.
For stale entries, we set a hard rule based on last seen time and tie it to a decommissioning workflow. Anything not observed in our cloud provider's API for 45 days gets flagged for archival in Tenable via a script, then removed from our reporting views. It's an extra integration, but it stopped the ghost assets.
Does your team have that luxury, or are you stuck with the tool's native retention logic?
independent eye
You've perfectly described the core issue with every cloud asset inventory tool I've evaluated. They're built to ingest, not to reconcile. The SQL example is a reality check - when the same external_id appears with multiple cloud_types, your source system has already failed as an authoritative inventory.
My team encountered identical duplication, primarily from scan timing windows overlapping with auto-scaling events. We took your approach a step further and built a deduplication key logic outside the tool. It uses a hierarchy: active state in the cloud provider's API first, then most recent scan with a valid network route, finally the oldest created entry as a tie-breaker. This logic runs in a separate data store, and we treat the vendor's output purely as a feed, not a source of truth.
The weep-worthy part is paying for a platform feature that requires you to rebuild its core function externally. Have you calculated the data storage cost overhead within Tenable for keeping those duplicate and stale records? In our case, it was a non-trivial percentage of the subscription fee.
Always check the data transfer costs.
That SQL snippet is painful to read, but also weirdly validating, right? It's the universal proof of the problem.
I've seen this duplication happen most when different scanning methods (agent-based, network, cloud connector) converge on the same asset at slightly different times. The tool registers them as separate discoveries instead of matching and merging.
Your manual reconciliation comment hits home. If the tool's own merging logic can't handle basic deduplication, then treating its output as just another raw feed is the only sane approach. It's frustrating that we have to build the "source of truth" part ourselves.
— isabel
Oh man, that exact SQL query made me laugh because I just ran something like it last week. It's my first time dealing with this and seeing it here is weirdly comforting.
How do you even decide which "cloud_type" to trust when you get two different ones back for the same ID? I've been staring at duplicates for days trying to guess which scan to believe.
Is there a setting somewhere to control the merging, or is the API feed just always this noisy?
Oh, you're looking for a *setting*? That's cute.
There's no setting. The merging logic is usually garbage and you can't fix stupid. You have to pick your own winner.
My rule: cloud provider's API always wins over any scan. If AWS says it's an EC2 instance, Tenable calling it 'unknown' doesn't matter. Build your own hierarchy and override their noise.
Treating the vendor feed as truth is your first mistake.
Cloud provider's API as the source of truth is fine, but that just shifts the problem. Now you're on the hook for building and maintaining that reconciliation layer, which is its own cost center.
Your "rule" assumes you have programmatic access and clean API data for every asset. That's not a given for everyone, especially in hybrid setups or with SaaS apps. The vendor should at least provide a reliable merging key.
show me the bill
That query is the universal "welcome to the integration layer" moment. You're right to treat it as a raw feed.
Your approach is sound, but you need to bake in a merging key strategy from the start. I'd suggest extending that staging table with a process that builds a composite key beyond just external_id. For cloud assets, we use `COALESCE(provider_account_id, '') || '|' || COALESCE(external_id, '')` and a last_seen timestamp from the cloud provider's own metadata, not the scan time. This gives you a stable handle for deduplication even when the vendor's data is inconsistent.
The real time-saver was adding a materialized view on top that applies our winner logic, so every downstream consumer gets a clean slate without knowing the mess underneath. It's extra ETL, but it stops the weeping.
IntegrationWizard
You're spot on about the cloud API being the definitive source. That "treat the vendor feed as truth" mistake is one we all make once.
But that hierarchy gets tricky when the provider API itself is inconsistent, like Azure sometimes returning null or placeholder values for certain tags during maintenance events. You still need a fallback logic for those gaps, which means you're not just picking a winner, you're building a whole arbitration layer.
We ended up with a three-tiered rule set: cloud API first, then the most recent credentialed scan, *then* the vendor's classification. It's more code, but it cut our manual cleanup by about 80%.
Automate all the things.
Exactly, building that arbitration layer is the real work. It's never just picking a winner, it's managing the fallback cascade.
We hit a similar snag with AWS Instance Metadata Service v2 cutting off some scan paths. Our tiered rule had to account for that - most recent *successful* credentialed scan, not just most recent. If the scan status was a failure, we'd skip to the next priority tier, even if it was older data.
It adds complexity, but that 80% reduction sounds right. The cost shifts from endless manual triage to maintaining a few dozen lines of merging logic.