Skip to content
Notifications
Clear all

Walkthrough: Creating custom compliance reports for our auditors.

42 Posts
41 Users
0 Reactions
165 Views
(@data_pipeline_guy_42)
Reputable Member
Joined: 3 months ago
Posts: 271
Topic starter   [#23159]

Alright, let's get this straight. Orca's built-in compliance dashboards are fine for a high-level glance, but when the auditors show up with their 50-point checklist, you need something exact and exportable. The generic views don't cut it. I had to build custom reports to map our cloud assets (AWS, Azure) directly to specific control requirements, and here's the pattern that worked.

The core of it is leveraging Orca's Data Lake. You're not going to get far just clicking around the UI. You need the raw findings and asset data. I set up a daily export from the Orca Data Lake to our Snowflake. The key tables are `public.assets` and `public.findings`. Once you have that, it's a SQL game.

Here's a simplified example for a report on unencrypted S3 buckets, mapped to control CIS AWS 2.1.1. You build a view that the auditors can query directly.

```sql
CREATE VIEW compliance.s3_encryption_audit AS
SELECT
a.asset_id,
a.account_name,
a.region,
a.name as bucket_name,
f.finding_id,
'CIS AWS 2.1.1' as control_id,
'Ensure all S3 buckets employ encryption-at-rest' as control_description,
CASE
WHEN f.state = 'OPEN' THEN 'FAIL'
ELSE 'PASS'
END as compliance_status,
f.severity,
f.first_seen
FROM
orca_data.public.assets a
JOIN
orca_data.public.findings f ON a.asset_id = f.asset_id
WHERE
a.type = 'AWS S3 Bucket'
AND f.rule_id = 's3_bucket_no_encryption' -- Orca-specific rule identifier
AND f.state IN ('OPEN', 'RESOLVED');
```

The process is:

* Identify the Orca `rule_id` for the specific compliance check you need.
* Join assets to findings on `asset_id`.
* Tag each row with your internal control framework ID and description.
* Export this view to CSV/PDF per audit period, or better yet, give the auditors read access to this schema.

The real work is curating the mapping of Orca rules to your compliance controls. I ended up creating a mapping table in our warehouse to manage this relationship, because one Orca finding can map to multiple controls (e.g., a single unencrypted RDS instance might fail multiple CIS and PCI controls). Without that mapping table, you'll drown in manual work.

Biggest pitfall? Orca's Data Lake schema isn't always intuitive. The `asset_inventory` field in the findings table is a JSON blob that sometimes holds the critical details you need (like specific configuration settings that failed). You'll need to parse that with `JSON_EXTRACT_PATH_TEXT()` or similar. If your data team isn't comfortable with that, you'll hit a wall. This isn't a point-and-click solution; it's a pipeline. Build it once, run it daily, and have the report ready before the audit even starts.


garbage in, garbage out


   
Quote
(@data_diver_dan)
Honorable Member
Joined: 6 months ago
Posts: 455
 

That's the right approach, moving from the UI to the Data Lake for reproducibility. I'd suggest taking it a step further by materializing that view as a table in your ELT layer, like with dbt. Auditors will run the same query repeatedly; a table scan is cheaper than a view that joins large fact and dimension tables on-demand.

Also, consider building a mapping table for controls. Hard-coding `'CIS AWS 2.1.1'` in every view becomes a maintenance problem. We maintain a `dim_compliance_controls` table that maps Orca finding categories to our internal control IDs and framework requirements. Then your view just joins to it.

Your CASE statement logic is solid, but double-check that `f.state = 'OPEN'` is the only failure condition for that specific control. Sometimes you need to factor in `risk_level` or `status` from the findings table to avoid false positives from remediated but not yet closed findings.


Garbage in, garbage out.


   
ReplyQuote
(@carlam)
Reputable Member
Joined: 2 months ago
Posts: 234
 

Great point on the mapping table, that's a game-changer for anyone juggling multiple frameworks. We set one up last quarter and it cut our report development time in half.

Your note about checking `risk_level` is spot on. We got burned by that exact scenario - auditors flagged "closed" findings that were actually low-risk informational items from our internal scans. Had to add `AND f.risk_level IN ('HIGH', 'CRITICAL')` to the filter.

How are you handling version drift in the frameworks? When CIS updates a control ID, do you retire the old mapping or keep both active for historical reports?


Benchmarking my way to better decisions


   
ReplyQuote
(@henryj)
Reputable Member
Joined: 2 months ago
Posts: 224
 

You're right about the mapping table, it's the only sane way to do it. But let's not gloss over the cost.

Materializing views and running a full ELT pipeline means you're now paying for Orca's Data Lake export, plus Snowflake compute and storage, plus dbt Cloud or a runner. That's three vendor bills instead of one, and the data gravity starts to pull you in. What happens when Orca changes their schema? You're now responsible for the entire data engineering pipeline, not just the report logic.

The real question is why we have to build all this ourselves. If their UI dashboards aren't sufficient for auditors, that's a product gap they should fix, not a consultancy opportunity for their customers.


Show me the data


   
ReplyQuote
(@hudsonh)
Estimable Member
Joined: 2 months ago
Posts: 210
 

Starting with the Data Lake is the only viable path, I agree. Your SQL approach is solid, but the `CASE` statement logic has a subtle edge case. An S3 bucket could be encrypted with SSE-KMS, but if the KMS key is disabled or deleted, Orca might flag that as 'OPEN' for a different finding category. Your view would incorrectly label it a pass for CIS 2.1.1. You need to join on `finding_type` or `category` as well to isolate the exact encryption-at-rest finding.


Measure twice, spend once


   
ReplyQuote
(@brianh)
Honorable Member
Joined: 3 months ago
Posts: 407
 

That's an excellent technical catch. You're absolutely right that relying solely on the state and a generic asset filter isn't enough. The finding category is the primary key for mapping to a control.

We structure our joins to include the `finding_category` from the mapping table, and the logic in the `CASE` statement becomes explicit about which failure condition it's checking. For the S3 encryption example, the join condition would specifically include `AND f.finding_category = 'aws_s3_bucket_encryption_disabled'`.

This also helps with performance, as it allows the query optimizer to filter findings much earlier in the plan, before the expensive CASE evaluation.


brianh


   
ReplyQuote
(@contrarian_kevin)
Honorable Member
Joined: 3 months ago
Posts: 418
 

Sure, start with the Data Lake. You're already locked in. Their API changes, your pipeline breaks. That's a vendor project disguised as your engineering work.


Just saying.


   
ReplyQuote
(@emilya)
Reputable Member
Joined: 3 months ago
Posts: 323
 

Your SQL view is missing the closing END for the CASE statement and the FROM clause. It won't run as posted.

Agree on the Data Lake approach. But you should also timestamp your views. An auditor will ask when the data snapshot was taken. Add a `report_date` column defaulted to `CURRENT_DATE()`.

Materializing this as a table is better for performance, but then you need a process to refresh it.


Prove it with a benchmark.


   
ReplyQuote
(@gregoryt)
Reputable Member
Joined: 2 months ago
Posts: 418
 

Good catch on the missing END, I'm glad you spotted it before someone tried to run it. The report_date column is a smart addition. Do auditors ever compare snapshots? Like, do they want to see if a control was failing on day X but passed on day Y, or is the snapshot just for audit trail?



   
ReplyQuote
(@integrations_jane)
Reputable Member
Joined: 5 months ago
Posts: 319
 

Oh, they absolutely compare snapshots. That's the whole point of a corrective action plan - you need to prove a finding was remediated between the initial audit and the follow-up. We append a `snapshot_date` to every materialized table name, like `compliance_cis_aws_2024_05_15`. It's a pain to manage, but it's non-negotiable.

The real trick is making sure your snapshot logic is deterministic. If you're pulling from the Data Lake, you need to know if the underlying data represents a point-in-time state or is just the current live state. Sometimes the "date" column is when the finding was *created*, not when it was *current*. That's caused us a few late nights reconciling.

Also, some frameworks require evidence you've maintained compliance over a period, not just on a single day. You'll need a time-series view, not just a snapshot.


APIs are not magic.


   
ReplyQuote
(@eliot77)
Reputable Member
Joined: 2 months ago
Posts: 244
 

Ah, the old risk_level trap. Everyone learns that one the hard way. A filter for 'HIGH' and 'CRITICAL' is a good start, but just wait until you get a 'MEDIUM' finding that's a compliance failure because it's tied to a specific regulatory control. The auditors don't always care about your risk matrix, they care about the control's text.

On version drift, we keep the old mapping active but flag it with an `effective_to` date. Retiring it breaks your historical snapshots, which as the later posts point out, is the entire game. The real fun begins when a control splits into two, or gets merged. Then your clean mapping table turns into a logic puzzle.


Show me the data


   
ReplyQuote
(@integrations_jane)
Reputable Member
Joined: 5 months ago
Posts: 319
 

You're missing the closing `END` and `FROM` clause, but the bones are right. This approach will work, but you're signing up for maintenance. Wait until Orca changes `state` from 'OPEN'/'RESOLVED' to a tri-state 'ACTIVE','INACTIVE','SUPPRESSED' in six months, and your entire view breaks silently. Ask me how I know.

Your `CASE` statement also needs to account for `finding_category`. An 'OPEN' finding for 'aws_s3_bucket_public_read_access' shouldn't fail the encryption control. The join is the easy part, the taxonomy mapping is where you'll spend your weekends.


APIs are not magic.


   
ReplyQuote
(@bearclaw)
Reputable Member
Joined: 3 months ago
Posts: 397
 

You forgot the FROM clause. Classic. Also, that CASE statement will tag any OPEN finding as a fail for this control, even if it's a public bucket finding. You need to filter on the specific finding category or you'll hand your auditors a false positive.

And you're signing up for a maintenance nightmare. Orca will rename a column or change an enum value and your view goes red. Ask me how I know.


Prove it.


   
ReplyQuote
(@hiroyuki)
Estimable Member
Joined: 2 months ago
Posts: 156
 

I hadn't even thought about the vendor lock-in for the pipeline itself, that's a really good point.

So you're basically paying Orca, then paying again to use your data somewhere else, and then you're the one who has to keep the plumbing working? That seems backwards.

Do you know if anyone has gotten their sales team to give a discount on the Data Lake export because you need it to fix their reporting?


Still learning.


   
ReplyQuote
(@cloud_rookie_em)
Honorable Member
Joined: 6 months ago
Posts: 563
 

Wait, you just need the raw assets and findings tables for this? That's way simpler than I expected.

I've been stuck trying to use their dashboard builder for custom reports and it's a nightmare. So you're saying skip their UI entirely and go straight to the data lake tables with SQL? That makes so much sense.

But how do you handle it if your team doesn't have a data warehouse like Snowflake set up? Is there a way to run these queries directly in Orca, or do you *have* to export it somewhere else first?



   
ReplyQuote
Page 1 / 3