Skip to content

[aws] Migrate Security Hub findings data streams to CEL via run_as_cel - #20818

Open
kcreddy wants to merge 13 commits into
elastic:mainfrom
kcreddy:httpjson2cel-aws-sh
Open

kcreddy wants to merge 13 commits into
elastic:mainfrom
kcreddy:httpjson2cel-aws-sh

Conversation

@kcreddy

@kcreddy kcreddy commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

Proposed commit message

[aws] Migrate Security Hub findings data streams to CEL via run_as_cel

Migrate the securityhub_findings and securityhub_findings_full_posture
data streams from the httpjson input to the CEL input using run_as_cel.
The existing auth.aws configuration (static keys, session token, shared
credentials, assume role, and Identity Federation / Cloud Connectors) and
the persisted collection cursor are preserved; service_name and
default_region are added so SigV4 signing targets the Security Hub
endpoint explicitly.

httpjson re-evaluates request transforms, including now(), on every
pagination page, so the hour-truncated UpdatedAt window start could
change mid-pagination and invalidate NextToken, forcing collection to
restart with HTTP 400/403 "Invalid NextToken". The CEL program pins the
window start in state once per collection interval and only appends
NextToken between pages. This fix depends on CEL state and cannot be
made in httpjson, so it lands together with the migration rather than
as a separate bugfix.

The error path clears the pagination state so a failed page does not
replay a stale NextToken on the next interval.

Add a filters variable to both data streams so operators can apply
server-side AwsSecurityFindingFilters to GetFindings. For Findings the
managed UpdatedAt filter takes precedence; for Findings Full Posture the
variable defaults to the existing RecordState/WorkflowStatus exclusions.
A cleared value renders an empty object instead of null.

Add a max_executions variable to bound pagination per interval. Findings
keeps the input default of 1000 because it resumes incrementally via its
cursor; Findings Full Posture defaults to 10000 (about one million
findings per cycle) because it re-reads the entire current posture with
no cursor. Document the cap and how to raise it.

Changes:
- Replace httpjson.yml.hbs with httpjson_as_cel.yml.hbs for both streams
- Add filters and max_executions variables to both manifests
- Document the Findings Filters setting and CEL execution cap
- Bump package version and add changelog entries

Note

Note on bugfix/enhancement separation. Per the backport policy agreed in #20040, bugfixes should land separately from enhancements so they can be cherry-picked to backport branches. That isn't possible here: the Invalid NextToken fix depends on the migration itself. httpjson re-evaluates request.transforms on every page and has no way to pin a value computed on page 1 for later pages, so the now-derived Start can drift mid-pagination. The CEL program fixes this by holding start in state and only recomputing it when neither want_more nor page.next_token is set. Making End static was the furthest httpjson could go and was already in place.

So this PR intentionally keeps both changelog entries under one version. If the NextToken fix ever needs backporting, it means backporting the migration, which would be an exception to the bugfix-only rule and would need run_as_cel support on the target line's minimum agent version.

Checklist

  • I have reviewed tips for building integrations and this pull request is aligned with them.
  • I have verified that all data streams collect metrics or logs.
  • I have added an entry to my package's changelog.yml file.
  • I have verified that Kibana version constraints are current according to guidelines.
  • I have verified that any added dashboard complies with Kibana's Dashboard good practices

How to test this PR locally

Migrate the securityhub_findings and securityhub_findings_full_posture
data streams from the legacy httpjson input with hand-rolled SigV4
signing to the CEL input using run_as_cel with native AWS
authentication (auth.aws).

The previous templates signed each request in an httpjson transform and
re-evaluated the request body (including now()) on every pagination
page. Because the UpdatedAt window and the SigV4 signature were
recomputed per page, a paginated GetFindings call could invalidate its
NextToken and fail. The CEL programs pin the request body once per
collection interval and only append NextToken between pages, so the
window and signed request stay stable across pagination.

Also add a `filters` variable to both data streams so operators can
apply server-side AwsSecurityFindingFilters to GetFindings and collect
only matching findings. For Findings the managed UpdatedAt filter takes
precedence; for Findings Full Posture the variable defaults to the
existing RecordState/WorkflowStatus exclusions.

These two data streams now require Elastic Agent 9.4.0+ (or 8.19.18+ on
8.x) for the httpjson-to-CEL redirector; the aws package already
requires Kibana ^9.4.0.

Changes:
- Replace httpjson.yml.hbs with httpjson_as_cel.yml.hbs for both streams
- Add filters and max_executions variables to both manifests
- Document the Findings Filters setting and version requirement
- Bump package version to 7.2.0 and add a changelog entry
@github-actions

Copy link
Copy Markdown
Contributor

Elastic Docs Style Checker (Vale)

Summary: 2 suggestions found

💡 Suggestions (2): Optional style improvements. Apply when helpful.
File Line Rule Message
packages/aws/data_stream/securityhub_findings/manifest.yml 36 Elastic.WordChoice Consider using 'can, might' instead of 'may', unless the term is in the UI.
packages/aws/data_stream/securityhub_findings_full_posture/manifest.yml 20 Elastic.WordChoice Consider using 'can, might' instead of 'may', unless the term is in the UI.

The Vale linter checks documentation changes against the Elastic Docs style guide. To use Vale locally or report issues, refer to Elastic style guide for Vale.

@elastic-vault-github-plugin-prod

elastic-vault-github-plugin-prod Bot commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

🚀 Benchmarks report

To see the full report comment with /test benchmark fullreport

@kcreddy kcreddy self-assigned this Aug 20, 2026
@kcreddy
kcreddy marked this pull request as ready for review August 20, 2026 05:58
@kcreddy
kcreddy requested a review from a team as a code owner August 20, 2026 05:58
Copilot AI lite review requested due to automatic review settings August 20, 2026 05:58
@kcreddy
kcreddy requested review from a team as code owners August 20, 2026 05:58
@kcreddy kcreddy added the Team:Security-Service Integrations Security Service Integrations team [elastic/security-service-integrations] label Aug 20, 2026
@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

Pinging @elastic/security-service-integrations (Team:Security-Service Integrations)

@kcreddy kcreddy added Integration:aws AWS enhancement New feature or request labels Aug 20, 2026
@kcreddy
kcreddy marked this pull request as draft August 20, 2026 05:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the AWS Security Hub Findings and Findings Full Posture data streams from legacy httpjson (with custom SigV4 signing) to CEL execution via run_as_cel with auth.aws, aiming to stabilize pagination and enable server-side filtering.

Changes:

  • Switch both Security Hub findings streams to httpjson_as_cel.yml.hbs templates using run_as_cel + auth.aws.
  • Add filters (AwsSecurityFindingFilters) and hidden max_executions variables to both streams.
  • Update Security Hub docs and bump the aws package version + changelog.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/aws/manifest.yml Bumps the aws package version to 7.3.0.
packages/aws/changelog.yml Adds a 7.3.0 changelog entry describing the CEL migration + filters.
packages/aws/docs/securityhub.md Documents CEL-based GetFindings collection, incremental behavior, and Findings Filters.
packages/aws/_dev/build/docs/securityhub.md Mirrors the Security Hub documentation updates for the built docs.
packages/aws/data_stream/securityhub_findings/manifest.yml Switches stream template to httpjson_as_cel.yml.hbs and adds filters / max_executions.
packages/aws/data_stream/securityhub_findings/agent/stream/httpjson.yml.hbs Removes the legacy httpjson template with hand-rolled SigV4 signing.
packages/aws/data_stream/securityhub_findings/agent/stream/httpjson_as_cel.yml.hbs Adds CEL program for stable UpdatedAt window + pagination with native auth.aws.
packages/aws/data_stream/securityhub_findings_full_posture/manifest.yml Switches stream template to httpjson_as_cel.yml.hbs and adds filters / max_executions.
packages/aws/data_stream/securityhub_findings_full_posture/agent/stream/httpjson.yml.hbs Removes the legacy httpjson template with hand-rolled SigV4 signing.
packages/aws/data_stream/securityhub_findings_full_posture/agent/stream/httpjson_as_cel.yml.hbs Adds CEL program for pagination with native auth.aws and configurable server-side filters.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/aws/docs/securityhub.md Outdated
Comment thread packages/aws/_dev/build/docs/securityhub.md Outdated
Comment thread packages/aws/data_stream/securityhub_findings/manifest.yml Outdated
Comment thread packages/aws/data_stream/securityhub_findings_full_posture/manifest.yml Outdated
Comment thread packages/aws/_dev/build/docs/securityhub.md Outdated
@kcreddy
kcreddy marked this pull request as ready for review August 20, 2026 07:36
Copilot AI review requested due to automatic review settings August 25, 2026 17:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread packages/aws/_dev/build/docs/securityhub.md Outdated
Comment thread packages/aws/manifest.yml Outdated
Comment thread packages/aws/docs/securityhub.md Outdated
@kcreddy
kcreddy marked this pull request as draft August 26, 2026 07:54
Migrate the securityhub_findings and securityhub_findings_full_posture
data streams from the legacy httpjson input with hand-rolled SigV4
signing to the CEL input using run_as_cel with native AWS
authentication (auth.aws).

The previous templates signed each request in an httpjson transform and
re-evaluated the request body (including now()) on every pagination
page. Because the UpdatedAt window and the SigV4 signature were
recomputed per page, a paginated GetFindings call could invalidate its
NextToken and fail. The CEL programs pin the request body once per
collection interval and only append NextToken between pages, so the
window and signed request stay stable across pagination.

Wire the full auth.aws credential set (access keys, session token,
shared credentials, and assume role) to match the other migrated AWS
streams, so the Assume Role and Shared Credentials setup options the
Security Hub policy template still offers are honoured rather than
silently falling back to the ambient credential chain.

Reset next_token on the non-2xx error path. Without this, a failure
part-way through pagination left a stale NextToken in the CEL state that
was replayed on every later interval; because Security Hub pagination
tokens are short-lived the request kept failing and the stream stayed
wedged until the agent restarted.

Add a filters variable to both data streams so operators can apply
server-side AwsSecurityFindingFilters to GetFindings and collect only
matching findings. For Findings the managed UpdatedAt filter takes
precedence; for Findings Full Posture the variable defaults to the
existing RecordState/WorkflowStatus exclusions. Guard the variable so a
cleared value renders an empty object instead of null.

Add a max_executions variable to both streams to bound pagination per
interval. Findings keeps the input default of 1000 because it resumes
incrementally via its cursor; Findings Full Posture defaults to 10000
(about one million findings per cycle) because it re-reads the entire
current posture with no cursor. Document the cap and how to raise it in
a troubleshooting section.

Changes:
- Replace httpjson.yml.hbs with httpjson_as_cel.yml.hbs for both streams
- Add filters and max_executions variables to both manifests
- Document the Findings Filters setting and CEL execution cap
- Bump package version and add a changelog entry
@kcreddy
kcreddy marked this pull request as ready for review August 26, 2026 09:58
Copilot AI review requested due to automatic review settings August 26, 2026 09:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new CEL templates can emit request.tracer.enabled: null when unset and the documented/manifested max_executions constraints are inconsistent with other repo streams, both of which should be reconciled before merge.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 5
  • Review effort level: Lite

Comment thread packages/aws/data_stream/securityhub_findings/manifest.yml
Comment thread packages/aws/docs/securityhub.md Outdated
Copilot AI review requested due to automatic review settings September 8, 2026 05:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The migration and supporting manifest/docs/test updates look consistent, with only minor documentation wording nits noted.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

packages/aws/_dev/build/docs/securityhub.md:32

  • Grammar: “data streams collect from the GetFindings API” reads awkwardly; use “collect data from” to make the sentence clear.
    packages/aws/docs/securityhub.md:32
  • Grammar: “data streams collect from the GetFindings API” reads awkwardly; use “collect data from” to make the sentence clear.
  • Files reviewed: 14/14 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@kcreddy
kcreddy requested a review from efd6 September 8, 2026 06:27
Copilot AI review requested due to automatic review settings September 8, 2026 07:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The updated Security Hub documentation introduces/retains incorrect guidance about required credentials, minimum Agent version, and interval-based mitigation for the full-posture stream.

Review details

Suppressed comments (4)

Previously missed (4) — in code that hasn't changed since the last review.

packages/aws/_dev/build/docs/securityhub.md:31

  • This new note about using auth.aws conflicts with (and is undermined by) the earlier documentation that says access keys are compulsory and that the module supports Elastic Agent 8.4.0. Since these streams now use run_as_cel + auth.aws (and the package manifest requires Agent >= 9.4.0), please update the Compatibility/Credentials wording so it reflects the supported credential methods and the actual minimum agent version.
    packages/aws/_dev/build/docs/securityhub.md:41
  • The troubleshooting advice to "shorten the collection interval so each run has fewer pages to fetch" is true for the incremental Findings stream, but it doesn't reduce paging for Findings Full Posture, which re-reads the full posture each run. This guidance should distinguish between the two streams (and optionally point users to Findings Filters for Full Posture).
    packages/aws/docs/securityhub.md:31
  • This new note about using auth.aws conflicts with (and is undermined by) the earlier documentation that says access keys are compulsory and that the module supports Elastic Agent 8.4.0. Since these streams now use run_as_cel + auth.aws (and the package manifest requires Agent >= 9.4.0), please update the Compatibility/Credentials wording so it reflects the supported credential methods and the actual minimum agent version.
    packages/aws/docs/securityhub.md:41
  • The troubleshooting advice to "shorten the collection interval so each run has fewer pages to fetch" is true for the incremental Findings stream, but it doesn't reduce paging for Findings Full Posture, which re-reads the full posture each run. This guidance should distinguish between the two streams (and optionally point users to Findings Filters for Full Posture).
  • Files reviewed: 14/14 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@efd6 efd6 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the copilot comments look valid. After that, LGTM

Copilot AI review requested due to automatic review settings September 10, 2026 07:47
@kcreddy
kcreddy requested a review from efd6 September 10, 2026 07:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Both CEL requests omit the required Content-Type: application/json header.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment on lines +84 to +86
?"NextToken": state.?page.next_token,
}.encode_json()
).do_request().as(resp, (resp.StatusCode == 200) ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. I would recommend using post_request, then you can include the content type in the request call, rather than the approach suggested by Vera.

Comment on lines +61 to +63
?"NextToken": state.?page.next_token,
}.encode_json()
).do_request().as(resp, (resp.StatusCode == 200) ?
Copilot AI review requested due to automatic review settings September 17, 2026 06:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The authentication and pagination migration is broad and warrants final human review.

Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 22, 2026 08:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

No unresolved review issues were identified.

Review effort: Lite
Findings: 2 High severity

Open (2)

@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

✅ All changelog entries have the correct PR link.

@vera-review-bot

Copy link
Copy Markdown

🟢 No issues across the latest commits bdcae55.

Review summary

Issues found across earlier commits 7ca81fd — 3 high, 3 medium, 1 low
  • 🟠 The non-200 branch does not clear next_token, so a failure part-way through pagination leaves a stale NextToken in state that is re-sent on every later interval (link)
  • 🟠 Same stale-token problem as the findings stream: the error branch leaves next_token set, so a failed page is retried with an expired NextToken every 24 hours (link)
  • 🟠 The new auth.aws block only wires access keys and session token, so the Assume Role and Shared Credentials options the Security Hub policy template still offers silently produce a config with no credentials (link)
  • 🟡 The Maximum Executions description tells users to set 0 for unlimited, but the CEL input rejects a non-positive max_executions at config validation, so following the instruction stops the input from starting (link) (Outdated)
  • 🟡 A 1000-execution cap on the full-posture sweep silently truncates collection at roughly 100k findings per cycle, and the var is hidden so operators cannot raise it (link) (Outdated)
  • 🟡 filters is an optional yaml var rendered unguarded, so clearing the Findings Filters field puts a null under cel.state and state.?filters.orValue({}) yields null rather than {} (link)
  • 🔵 The new note claims these data streams need agent 9.4.0+ or 8.19.18+ on 8.x, but the package already pins conditions.agent.version and conditions.kibana.version to ^9.6.0, so the 8.x path cannot exist (link) (Outdated)

A new commit triggers another review — at most once every 15 minutes. I skip the PR while it's approved or has merge conflicts.

🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills

⚠️ Automated review — verify suggestions before applying.

@kcreddy

kcreddy commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

@efd6 can I get another review on this?

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

History

cc @kcreddy


## Troubleshooting

### "reached maximum number of CEL executions"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to say that we can avoid raising this in agent health updates by using remaining_executions conditions in the CEL, but the signal is genuinely useful here, so I don't think using that would be a good idea.

Comment on lines +84 to +86
?"NextToken": state.?page.next_token,
}.encode_json()
).do_request().as(resp, (resp.StatusCode == 200) ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. I would recommend using post_request, then you can include the content type in the request call, rather than the approach suggested by Vera.

}.encode_json()
).do_request().as(resp, (resp.StatusCode == 200) ?
resp.Body.decode_json().as(body,
body.?NextToken.orValue("").as(next,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
body.?NextToken.orValue("").as(next,
body.?NextToken.as(next,

but equally (possibly better), this as binding could be dropped since we're not doing anything expensive to get it.

body.?NextToken.orValue("").as(next,
{
"events": body.?Findings.orValue([]).map(e, {"message": e.encode_json()}),
"page": (next == "") ? {} : {"next_token": next},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"page": (next == "") ? {} : {"next_token": next},
"page": {?"next_token": next},

or

Suggested change
"page": (next == "") ? {} : {"next_token": next},
"page": {?"next_token": body.?NextToken},

if the binding is removed.

{
"events": body.?Findings.orValue([]).map(e, {"message": e.encode_json()}),
"page": (next == "") ? {} : {"next_token": next},
"want_more": next != "",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"want_more": next != "",
"want_more": next.hasValue(),

or

Suggested change
"want_more": next != "",
"want_more": has(body.NextToken),

@@ -0,0 +1,141 @@
config_version: 2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
config_version: 2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments here.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request Integration:aws AWS Team:Security-Service Integrations Security Service Integrations team [elastic/security-service-integrations]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants