Pulumi-Webhook-Kind header identifying the event and is signed with HMAC-SHA256 (Pulumi-Webhook-Signature header) using the webhook secret Kestrel generates at connect time, and Kestrel verifies the signature before evaluating workflows.
Prerequisites
- Organization Admin role in Kestrel
- A Pulumi Cloud organization with at least one stack
- A Pulumi Cloud access token with access to the organization — an organization token or team token is recommended over a personal token
- Deployment actions (Run Deployment, Cancel, Pause/Resume) require Pulumi Deployments to be configured on the target stacks
Setup
1
Create an access token
In Pulumi Cloud (
app.pulumi.com), go to your organization’s Settings → Access Tokens. Create an organization token (or a team token scoped to the stacks your workflows manage). Copy the token — it is shown only once.2
Connect in Kestrel
- Navigate to Integrations → Pulumi Cloud in your Kestrel dashboard.
- Paste your access token.
- Enter your Organization name (e.g.
my-org). - Optionally set a custom API base URL for self-hosted Pulumi (defaults to
https://api.pulumi.com). - Click Connect Pulumi Cloud — Kestrel validates the token by listing your organization’s stacks and generates a webhook secret for delivery verification.
3
Register webhooks (for triggers)
Actions work as soon as the token is connected. To have Pulumi Cloud events trigger workflows, add a webhook at the organization level (all stacks) or per stack:
- On the Kestrel Pulumi Cloud integration page, copy the Webhook URL and the Webhook secret.
- In Pulumi Cloud, open your organization’s Settings → Integrations, scroll to the Webhooks section, and click Add webhook (for per-stack events, use the stack’s Settings → Webhooks instead).
- Under Destination, choose Webhook (not Slack or Microsoft Teams) and give it a display name (e.g.
kestrel). - Set the Payload URL to the copied webhook URL and paste the webhook secret into the Secret field. The secret is required — Kestrel rejects unsigned deliveries.
- Under Triggers, check these boxes — Kestrel needs all of these event groups:
- All Stack events — powers Stack Created, Stack Deleted, Update Succeeded, Update Failed, Preview Failed, and Destroy Succeeded.
- All Deployment events — powers Deployment Started / Succeeded / Failed, Drift Detected, and Drift Run Failed (the drift detection and remediation checkboxes live in this section).
- All Policy events — powers Policy Violation (both mandatory and advisory violations).
- All Environment events and All Change requests — also needed; Kestrel consumes these event groups as well.
- Click Create. Pulumi Cloud sends a
pingdelivery on creation, which Kestrel acknowledges — the integration page’s webhook event counter increments once the first delivery is verified.
Deployment and drift events (
deployment_*, drift_detected) require Pulumi Deployments with drift detection schedules configured on the stack (Pulumi Cloud Team/Enterprise). Update events (update_succeeded, update_failed) fire for any pulumi up, including CLI-driven updates.How It’s Used
In Workflows
Trigger blocks (webhook):- Update Succeeded — fires when a stack update (
pulumi up) succeeds - Update Failed — fires when a stack update, refresh, or destroy fails
- Preview Failed — fires when a stack preview fails (broken program or config before anything is applied)
- Destroy Succeeded — fires when a stack destroy succeeds (all managed resources torn down)
- Deployment Started / Succeeded / Failed — fire as a Pulumi Deployments run progresses
- Drift Detected — fires when a scheduled drift detection run finds infrastructure drift from the declared program state
- Drift Run Failed — fires when a drift detection or remediation run fails to complete
- Policy Violation — fires when a CrossGuard policy violation is detected during a stack operation
- Stack Created / Stack Deleted — fire when stacks are created or removed in the organization
{{signal.stack}}, {{signal.project}}, {{signal.operation}}, {{signal.result}}, {{signal.update_version}}, {{signal.deployment_id}}, {{signal.organization}}, {{signal.user}}, and {{signal.update_url}} for downstream steps.
Action blocks:
- List Stacks / Get Stack — inventory (last update time, resource counts, version, tags, in-flight operations)
- List Updates / Get Update — update history and an update’s result plus resource change counts (great for Slack notifications and approval context)
- Run Deployment — start a Pulumi Deployments run (update, preview, refresh, destroy, detect-drift, or remediate-drift) using the stack’s saved deployment settings (gate destroy and remediate-drift behind an Approval node)
- Get Deployment / Wait for Deployment — check a deployment’s status, or poll it until it reaches a terminal state (succeeded, failed, skipped) and branch on the result
- Cancel Deployment — cancel a queued or running deployment
- Pause Deployments / Resume Deployments — freeze or unfreeze a stack’s deployment queue during incidents and maintenance windows
- Get Stack Outputs — read the stack’s current outputs from its latest state (secret outputs are redacted) to wire infrastructure values into later steps
- Get Drift Status — check the latest drift detection runs for a stack
- Set Stack Tag / Delete Stack Tag — mark stacks (e.g. quarantined, incident ID) or clean up tags
- Investigate Pulumi — run a read-only AI investigation across stacks, updates, deployments, outputs, and drift
{{signal.stack}} and {{signal.deployment_id}} from the trigger.
Example (failure triage — the flagship Pulumi flow): When an update fails on a production stack, run an AI investigation, post the findings to Slack with approve/reject buttons, then Run Deployment (update) to retry on approval.
Example (drift): When drift is detected, fetch the drift status, post a summary to Slack and ask for approval, then Run Deployment with the remediate-drift operation on approval.
Example (incident): When a deployment fails, investigate the failure with AI, page on-call via PagerDuty with the summary and update URL, and Pause Deployments on the stack until the incident is resolved.
Disconnecting
- Navigate to Integrations → Pulumi Cloud
- Click Disconnect
- Confirm the disconnection