Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/pages/docs/api.astro
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ curl -s -H "Authorization: Bearer $OM_API_SECRET" \\
}`}</code></pre>
<p>
<code>GET /v1/graph/query?name=internet-to-datastore</code> returns <code>query</code>,
<code>summary</code>, and <code>paths</code>. Each path is an array of nodes. Unknown names
<code>summary</code>, and <code>paths</code>. Each path is an array of nodes. When a
CloudTrail management event’s resource node is on a path, <code>audits</code> lists that
event with <code>index</code> set to the path’s position. Unknown names
are 400. The six names are listed by <code>GET /v1/graph/queries</code> as
<code>{`{"queries":[{"name":"...","description":"..."}]}`}</code>. See
<a href="/docs/attack-paths/">Attack paths</a> for depth and row limits.
Expand Down
3 changes: 2 additions & 1 deletion src/pages/docs/architecture.astro
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
<p>
Core is one Go module. The CLI and the API share <code>internal/graph</code>,
<code>internal/rules</code>, and the collectors. PostgreSQL is the graph store. Phase 3 adds
the plugin SDK, the embedded rule pack, and a Helm chart on top of the Phase 2 feature set.
the plugin SDK, the embedded rule pack, a Helm chart, and CloudTrail management events on
the AWS collector, on top of the Phase 2 feature set.
</p>
<pre><code>{`Cloud / Kubernetes APIs
│
Expand Down
27 changes: 26 additions & 1 deletion src/pages/docs/attack-paths.astro
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';

<DocsLayout
title="OpenSourceOM attack path queries"
description="The six named attack-path queries, and the attack-path finding a rules run writes for a workload that can reach a datastore."
description="The six named attack-path queries, attack-path findings, and CloudTrail events shown on a path."
faq={[
{
question: 'Which attack path queries does OpenSourceOM run?',
Expand All @@ -23,6 +23,11 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
answer:
'After the control rules, om rules run writes one finding per existing finding on an internet-reachable workload that can reach a datastore. The finding stores the path as ordered node ids. GET /v1/findings returns that path on the row.',
},
{
question: 'Where do CloudTrail events show up on a path?',
answer:
'om scan aws stores recent management events on the identity and resource they name. GET /v1/graph/query returns those events in audits when the resource node is on a path. om paths run prints the same lines under the path.',
},
]}
related={[
{ href: '/blog/attack-path-analysis-cloud-security/', label: 'Attack path analysis' },
Expand Down Expand Up @@ -173,6 +178,26 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
ids on the card. SIEM export includes the same list.
</p>

<h2>CloudTrail on a path</h2>
<p>
<code>om scan aws</code> reads CloudTrail management events from the last 24 hours and
stores a match as <code>audit_events</code> on the identity and the resource the event
names. A match requires both nodes to already be in the scan, and the resource has to sit
on an exposed path: an internet-reachable workload, something that workload assumes or can
access, a public datastore, or an identity that can access one. At most five events are
kept on a node, newest first. A failed lookup leaves the property off and the rest of the
scan still ingests.
</p>
<p>
<code>GET /v1/graph/query</code> copies an event into <code>audits</code> when that
resource node is on the returned path. <code>index</code> is the path’s position in
<code>paths</code>. The same event stored on two nodes of one path is listed once.
<code>om paths run</code> prints the time, event name, principal, and resource under that
path. The console does the same. <code>GetObject</code> is an S3 data event and is not in
this slice. Azure and GCP audit logs are not collected. See the
<a href="/docs/collectors/aws/">AWS collector</a>.
</p>

<h2>Reading an empty result</h2>
<p>
An empty path list means the edges are not there, not that the account is safe. The walk
Expand Down
4 changes: 2 additions & 2 deletions src/pages/docs/cli.astro
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
</tr>
<tr>
<td><code>om scan aws</code></td>
<td>EC2, security groups, IAM, and S3 in <code>AWS_REGION</code>.</td>
<td>EC2, security groups, IAM, and S3 in <code>AWS_REGION</code>, plus CloudTrail management events from the last 24 hours.</td>
</tr>
<tr>
<td><code>om scan azure</code></td>
Expand Down Expand Up @@ -77,7 +77,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
</tr>
<tr>
<td><code>om paths run &lt;name&gt;</code></td>
<td>Run one named query and print paths.</td>
<td>Run one named query and print paths. A CloudTrail event whose resource is on a path is printed under that path.</td>
</tr>
<tr>
<td><code>om graph stats</code></td>
Expand Down
32 changes: 30 additions & 2 deletions src/pages/docs/collectors/aws.astro
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';

<DocsLayout
title="AWS security collector"
description="What om scan aws collects from EC2, IAM, S3, and security groups, and how those APIs become attack-path edges."
description="What om scan aws collects from EC2, IAM, S3, security groups, and CloudTrail, and how those APIs become attack-path edges."
>
<h1>AWS security collector</h1>
<p>
Expand Down Expand Up @@ -51,6 +51,10 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
<td>S3 bucket list, public access block, encryption, versioning</td>
<td><code>Datastore</code> with <code>service: s3</code>, <code>public_access</code>, <code>public_access_block</code> (<code>disabled</code> or enabled), <code>encryption</code>, <code>versioning</code>, and <code>sensitivity</code> when a bucket tag names it.</td>
</tr>
<tr>
<td>CloudTrail <code>LookupEvents</code></td>
<td>Up to five <code>audit_events</code> on the identity and the resource the event names. See below.</td>
</tr>
</tbody>
</table>
</div>
Expand Down Expand Up @@ -98,11 +102,35 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
account-wide. EC2 and security groups are the one region in <code>AWS_REGION</code>.
</p>

<h2>CloudTrail</h2>
<p>
After inventory is built, the scan calls <code>cloudtrail:LookupEvents</code> for the last 24
hours in <code>AWS_REGION</code>. IAM and S3 management events are recorded in
<code>us-east-1</code>, so a scan of another region also looks there. Each lookup stops after
four pages. A failed lookup omits <code>audit_events</code> and does not fail the scan.
</p>
<p>
An event is kept when its name is on a fixed management-event list (for example
<code>AssumeRole</code>, <code>PutBucketPolicy</code>, <code>AuthorizeSecurityGroupIngress</code>)
and it names an identity already in the batch plus a resource on an exposed path. Exposed
means an internet-reachable workload, a node that workload assumes or can access, a network
that workload affects, a public datastore, or an identity that can access a public datastore.
The same event is stored on both nodes, newest first, at most five per node.
<code>GetObject</code> is an S3 data event. <code>LookupEvents</code> does not return it, so
this slice does not.
</p>
<p>
<code>GET /v1/graph/query</code> and <code>om paths run</code> list those events in
<code>audits</code> when the resource node is on the returned path. The console prints the
same lines under the path. Azure Activity Log and GCP Cloud Audit Logs are not collected.
</p>

<h2>Read-only actions</h2>
<p>
A least-privilege policy for this collector needs read access for the calls above, including
<code>iam:GetInstanceProfile</code>, <code>iam:ListAttachedRolePolicies</code>,
<code>iam:ListRolePolicies</code>, <code>iam:GetRolePolicy</code>, <code>iam:GetPolicy</code>,
<code>iam:GetPolicyVersion</code>, and <code>s3:GetBucketTagging</code>. The scan does not call mutating APIs.
<code>iam:GetPolicyVersion</code>, <code>s3:GetBucketTagging</code>, and
<code>cloudtrail:LookupEvents</code>. The scan does not call mutating APIs.
</p>
</DocsLayout>
2 changes: 1 addition & 1 deletion src/pages/docs/collectors/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
<tbody>
<tr>
<td><a href="/docs/collectors/aws/"><code>om scan aws</code></a></td>
<td>EC2, security groups, IAM roles and users, S3, instance-profile access to S3</td>
<td>EC2, security groups, IAM roles and users, S3, instance-profile access to S3, recent CloudTrail management events</td>
<td>AWS default chain, one region</td>
</tr>
<tr>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/docs/console.astro
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
<li>Read node and edge counts in the stats strip. Those numbers come from <code>GET /v1/graph/stats</code>.</li>
<li>Scan the findings list from <code>GET /v1/findings</code>. Each card shows severity, title, and the affected resource. An attack-path card also prints the <code>path</code> node ids. Choosing a card highlights the affected resource when it is in the current snapshot.</li>
<li>The dropdown loads every named query. On first paint it selects <code>internet-to-datastore</code> when that query exists, then draws those paths. Choose <strong>Full graph snapshot</strong> to call <code>GET /v1/graph/snapshot</code> instead (500 nodes and 2000 edges).</li>
<li>A named query still uses the snapshot’s edge list to label each hop. If the connecting edge is past that 2000-edge cap, the hop is drawn as type <code>PATH</code> and any <code>reason</code> property is missing. The nodes themselves come from the query, not from the snapshot cap.</li>
<li>A named query still uses the snapshot’s edge list to label each hop. If the connecting edge is past that 2000-edge cap, the hop is drawn as type <code>PATH</code> and any <code>reason</code> property is missing. The nodes themselves come from the query, not from the snapshot cap. CloudTrail events returned in <code>audits</code> are listed under that path.</li>
<li>Select an identity node to load <code>GET /v1/identity/blast-radius</code>. The panel shows the summary and the reachable nodes. See <a href="/docs/blast-radius/">Blast radius</a>. Other node types do not open that panel.</li>
<li>Refresh reloads stats, findings, and the current view after you ingest from the CLI. The page does not poll.</li>
</ul>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/docs/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
<ul>
<li><a href="/docs/the-graph/">The graph</a> — nodes, edges, and how findings attach</li>
<li><a href="/docs/schema/">Schema</a> — node types, edge types, and ID format</li>
<li><a href="/docs/attack-paths/">Attack paths</a> — the six named queries and attack-path findings</li>
<li><a href="/docs/attack-paths/">Attack paths</a> — the six named queries, attack-path findings, and CloudTrail events on a path</li>
<li><a href="/docs/blast-radius/">Blast radius</a> — what an identity can reach</li>
<li><a href="/docs/prioritization/">Prioritization</a> — how graph context changes a score</li>
</ul>
Expand Down
6 changes: 4 additions & 2 deletions src/pages/docs/open-source.astro
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,10 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
</table>
</div>
<p>
Cloud provider audit APIs (for example CloudTrail) are Phase 3 graph context: evidence of
exposure and attack paths. <strong>Platform audit logs</strong> — operator actions in the
<code>om scan aws</code> stores CloudTrail management events from the last 24 hours on the
identity and resource they name, when that resource is on an exposed path. Path queries
return those events with the path. Azure Activity Log and GCP Cloud Audit Logs are not
collected yet. <strong>Platform audit logs</strong> — operator actions in the
console/API, SSO identity, retention, and auditor export — belong in the commercial offering.
</p>

Expand Down
1 change: 1 addition & 0 deletions src/pages/docs/schema.astro
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
<li><code>mfa</code>, <code>unused_access_keys</code> — IAM user pack rules</li>
<li><code>public_ip</code>, <code>imdsv2</code> — workload exposure and metadata rules</li>
<li><code>packages</code>, <code>image</code>, <code>images</code> — workload inventory that <code>om enrich cve</code> matches. Rules do not read these keys. See <a href="/docs/enrichment/">CVE enrichment</a>.</li>
<li><code>audit_events</code> — recent CloudTrail management events on an identity or resource. Each item has <code>id</code>, <code>name</code>, <code>time</code>, <code>principal</code>, <code>resource</code>, <code>principal_node_id</code>, <code>resource_node_id</code>, and optional <code>source_ip</code> and <code>read_only</code>. <code>om scan aws</code> writes at most five, newest first, and only when the resource is on an exposed path. A plugin may set the same list. Named path queries copy an event into <code>audits</code> when its resource node is on the path. Rules do not match this key.</li>
<li><code>internet_reachable</code>, <code>path_to_datastore</code>, <code>admin_can_access</code> — graph match keys on YAML rules, computed at run time, not stored by collectors</li>
</ul>

Expand Down
Loading