Skip to content

[CFT] Report the Workload Identity role to Kibana from the WII template - #9186

Open
bhapas wants to merge 2 commits into
elastic:mainfrom
bhapas:feat/wii-template-kibana-callback
Open

bhapas wants to merge 2 commits into
elastic:mainfrom
bhapas:feat/wii-template-kibana-callback

Conversation

@bhapas

@bhapas bhapas commented Oct 15, 2026 •

Copy link
Copy Markdown

Summary of your changes

The Workload Identity template (deploy/cloudformation/federated-identity-wii-aws.yml) can now send the role it creates back to Kibana. The user no longer has to copy the Role ARN and the Stack ARN from the stack outputs into Kibana.

Two new optional parameters. Kibana sets them when it launches the stack. Both default to empty, and CloudFormation validates both.

  • ElasticCallbackUrl: the complete URL of the Kibana callback this stack reports to. Must be empty or an https URL with a path. Kibana builds it from the route it owns, so a route change stays on the Kibana side.
  • ElasticApiKey: a single-use API key with no privileges, used only for this report. Must be empty or base64. Hidden in the console (NoEcho).

When both are set, the stack creates a Lambda function and a custom resource. The function sends a POST with {"role_arn": ..., "stack_arn": ...} to ElasticCallbackUrl, authenticated with the API key. The custom resource runs after the role and all of its policies are created.

When either is empty, the stack does not create these resources and behaves as before.

How the function behaves:

  • It always answers SUCCESS to CloudFormation. A failed report never fails or rolls back the stack, and the user can still copy the outputs by hand.
  • It reports when the custom resource is created or updated. On delete it answers without calling Kibana.
  • It tries Kibana up to four times, waiting 2, 4 and 8 seconds between tries. Each request times out after 10 seconds.
  • It does not retry a 4xx answer from Kibana.
  • It stops retrying when less than 40 seconds of its 90-second timeout remain, so it always has time to answer CloudFormation. The custom resource times out after 120 seconds.
  • It logs callback result <status>, for example connected or failed: http 404. When Kibana could not be reached it logs the reason, for example a certificate the function does not trust. It never logs the event, the request headers or the API key, and an exception that could quote a header is logged by its type alone.
  • Its role only has the AWS Lambda basic execution policy, which lets it write logs.

The Lambda code is byte for byte the callback.py that elastic/cloud-iac-provisioner#434 adds to the generated template, so both templates behave the same way. Keep the two identical.

Related Issues

Related: elastic/kibana#297690, elastic/cloud-iac-provisioner#434, https://github.com/elastic/security-team/issues/12714

Checklist

  • cfn-lint 1.57.2 passes on the template.
  • rain fmt --verify reports one blank line to add between WiiOidcProviderFunctionRole and WiiOidcProviderFunction, which is outside this change and already in main.
  • The inline Lambda code is identical to callback.py from elastic/cloud-iac-provisioner#434 and compiles with Python 3.13 (py_compile).
  • The 14 unit tests from elastic/cloud-iac-provisioner#434 (test/blueprints/test_callback.py) pass against the code extracted from this template, on Python 3.13 and 3.14.
  • The custom resource's DependsOn lists every AWS::IAM::Policy in the template (17).
  • The inline code is 3,867 bytes, within the CloudFormation limit for ZipFile.

…emplate

Add three optional parameters, ElasticKibanaUrl, ElasticApiKey and
ElasticCallbackId, that Kibana sets when it launches the stack. When all
three are set, a Lambda-backed custom resource posts the role ARN and the
stack ARN to Kibana, so the user does not have to paste them. When any of
them is empty, the stack behaves as before.

The function always answers SUCCESS to CloudFormation, so a failed report
never fails or rolls back the stack. It does not retry a 4xx answer and
retries other failures with backoff while enough time remains.

Co-authored-by: Cursor <cursoragent@cursor.com>
@mergify mergify Bot assigned bhapas Oct 15, 2026
@mergify

mergify Bot commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

This pull request does not have a backport label. Could you fix it @bhapas? 🙏
To fixup this pull request, you need to add the backport labels for the needed
branches, such as:

  • backport-v./d./d./d is the label to automatically backport to the 8./d branch. /d is the digit
  • backport-active-all is the label that automatically backports to all active branches.
  • backport-active-8 is the label that automatically backports to all active minor branches for the 8 major.
  • backport-active-9 is the label that automatically backports to all active minor branches for the 9 major.

@bhapas
bhapas marked this pull request as ready for review October 15, 2026 05:06
@bhapas
bhapas requested a review from a team as a code owner October 15, 2026 05:06
@bhapas bhapas added the Team:Security-Cloud-Service Previously Cloud Services team. label Oct 15, 2026
@mergify

mergify Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

Kibana now passes the callback as ElasticCallbackUrl, the complete URL of
the record the stack reports to, next to ElasticApiKey. The template took
ElasticKibanaUrl and ElasticCallbackId and built the route itself, so a
launch from Kibana left CallbackEnabled false and the stack never reported.

The handler is the one the IaC Provisioner blueprint ships, byte for byte,
so it also carries that handler's later fixes: it logs why Kibana could not
be reached, and logs only the exception type when the exception could quote
a header. ElasticApiKey gets an AllowedPattern so a malformed key is
rejected at launch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@seanrathier seanrathier 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.

Added comment for discussion

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 am commenting here mainly for a discussion.

This is a publicly available, unsigned S3 CFT. Do we want to have this detail of how we do our frictionless onboarding out in the public?

To be clear, I mean this ONLY for the static template; the IACP-generated one is signed so the risk is not there.

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

Labels

backport-skip Team:Security-Cloud-Service Previously Cloud Services team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants