Skip to content

feat: resolve webhook secrets from SSM and Secrets Manager#49

Open
mtweeman wants to merge 1 commit intocloudposse-terraform-components:mainfrom
RTBHOUSE:feat/webhooks-secrets
Open

feat: resolve webhook secrets from SSM and Secrets Manager#49
mtweeman wants to merge 1 commit intocloudposse-terraform-components:mainfrom
RTBHOUSE:feat/webhooks-secrets

Conversation

@mtweeman
Copy link
Copy Markdown
Contributor

@mtweeman mtweeman commented Apr 21, 2026

what

Handling webhook secret as sensitive data.

why

Extending the existing ssm:// / asm:// prefix resolution, so that the secret field of var.webhooks is fetched from Parameter Store or Secrets Manager, matching the handling already used for variables, secrets and environments.

Summary by CodeRabbit

  • New Features

    • Webhook configurations now accept AWS Parameter Store and Secrets Manager references and automatically resolve those secrets at deployment while preserving other webhook settings.
  • Security

    • Webhook configuration input is now treated as sensitive to prevent accidental exposure of secret data in logs and outputs.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8c2e632d-ff58-4c2e-90a6-292fea898a51

📥 Commits

Reviewing files that changed from the base of the PR and between 262cf63 and 5bf315b.

📒 Files selected for processing (2)
  • src/main.tf
  • src/variables.tf
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/variables.tf
  • src/main.tf

📝 Walkthrough

Walkthrough

The webhooks input variable is now sensitive. A new locals.webhooks map normalizes webhook fields and conditionally resolves ssm:// and asm:// secrets via SSM Parameter Store and AWS Secrets Manager data sources; module.repository now receives local.webhooks.

Changes

Cohort / File(s) Summary
Webhook Normalization & Secret Resolution
src/main.tf
Introduce local.webhooks that preserves active, events, url, content_type, insecure_ssl; resolves secret when prefixed with ssm:// or asm:// by referencing aws_ssm_parameter / aws_secretsmanager_secret_version data sources (wrapped with nonsensitive), otherwise passes through or null. module.repository input switched to local.webhooks. ssm_parameters and sm_parameters merges extended to include matching secret keys for lookups.
Variable Sensitivity Marking
src/variables.tf
Changed variable "webhooks" to include sensitive = true; type, default, and nullable semantics unchanged.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Dev as "Terraform Config"
  participant Loc as "locals.webhooks"
  participant SSM as "AWS SSM Data Source\n(aws_ssm_parameter)"
  participant ASM as "AWS Secrets Manager Data Source\n(aws_secretsmanager_secret_version)"
  participant Mod as "module.repository"

  Dev->>Loc: Evaluate webhooks map
  alt secret starts with ssm://
    Loc->>SSM: lookup parameter key
    SSM-->>Loc: return value
  else secret starts with asm://
    Loc->>ASM: lookup secret version
    ASM-->>Loc: return secret_string
  else secret is plain or null
    Loc-->>Loc: passthrough or null
  end
  Loc->>Mod: pass normalized webhooks (secrets resolved/nonsensitive-wrapped)
  Mod-->>Dev: module configured with resolved webhooks
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 In fields of code I hop and peep,

secrets tucked where willows sleep,
SSM and ASM I pluck with care,
local maps bind them fair and square,
a gentle guard: sensitive, aware.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: implementing resolution of webhook secrets from AWS SSM and Secrets Manager, which matches the core functionality added in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mergify mergify Bot requested review from a team April 21, 2026 11:30
@mergify mergify Bot added the triage Needs triage label Apr 21, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main.tf`:
- Around line 111-123: The webhook secret resolution currently uses
nonsensitive() to unwrap SSM/ASM values (in the webhooks mapping for
var.webhooks), which exposes secrets; change it to wrap the entire resolution in
sensitive() instead. Locate the webhooks block and the secret expression
referencing data.aws_ssm_parameter.default[...] and
data.aws_secretsmanager_secret_version.default[...] and replace the
nonsensitive(...) calls with sensitive(...) so the resolved SSM/ASM values
remain marked sensitive (preserving var.webhooks sensitive = true semantics) and
return null when v.secret is null.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 66a20ed3-a41c-46b6-a4fa-2aecaeaebfbf

📥 Commits

Reviewing files that changed from the base of the PR and between 22ba453 and 262cf63.

📒 Files selected for processing (2)
  • src/main.tf
  • src/variables.tf

Comment thread src/main.tf
Comment on lines +111 to +123
webhooks = {
for k, v in coalesce(var.webhooks, {}) : k => {
active = v.active
events = v.events
url = v.url
content_type = v.content_type
insecure_ssl = v.insecure_ssl
secret = v.secret != null ? (
startswith(v.secret, "ssm://") ? nonsensitive(data.aws_ssm_parameter.default[v.secret].value) :
startswith(v.secret, "asm://") ? nonsensitive(data.aws_secretsmanager_secret_version.default[v.secret].secret_string) : v.secret
) : null
}
}
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Does Terraform's nonsensitive() function permanently remove the sensitive mark from aws_ssm_parameter value and aws_secretsmanager_secret_version secret_string when passed downstream to a module input?

💡 Result:

Yes, Terraform's nonsensitive function permanently removes the sensitive marking from the specified value, including when that value is passed downstream as a module input. The resulting value is treated as non-sensitive throughout the configuration graph, including in the child module where it becomes a regular (non-sensitive) variable value.

Citations:


🏁 Script executed:

#!/bin/bash
# Verify the code in src/main.tf and check the local.secrets pattern
echo "=== Lines 75-80 (local.secrets pattern) ==="
sed -n '75,80p' src/main.tf
echo ""
echo "=== Lines 111-123 (webhook secrets block) ==="
sed -n '111,123p' src/main.tf
echo ""
echo "=== Check variables.tf for webhooks definition ==="
grep -A 20 "variable.*webhooks" src/variables.tf | head -30

Repository: cloudposse-terraform-components/aws-github-repository

Length of output: 1725


Wrap webhook secret field in sensitive() instead of nonsensitive().

The webhooks block (lines 111–123) uses nonsensitive() to strip the sensitive marker from resolved SSM and ASM values. This contradicts the sensitive = true marking on var.webhooks in variables.tf and exposes resolved secrets in plan output and logs.

The local.secrets block above (lines 75–80) demonstrates the correct pattern: wrap the entire resolution in sensitive() instead of using nonsensitive(). Apply the same approach to the webhook secret field:

Fix
   webhooks = {
     for k, v in coalesce(var.webhooks, {}) : k => {
       active       = v.active
       events       = v.events
       url          = v.url
       content_type = v.content_type
       insecure_ssl = v.insecure_ssl
-      secret = v.secret != null ? (
-        startswith(v.secret, "ssm://") ? nonsensitive(data.aws_ssm_parameter.default[v.secret].value) :
-        startswith(v.secret, "asm://") ? nonsensitive(data.aws_secretsmanager_secret_version.default[v.secret].secret_string) : v.secret
-      ) : null
+      secret = v.secret != null ? sensitive(
+        startswith(v.secret, "ssm://") ? data.aws_ssm_parameter.default[v.secret].value :
+        startswith(v.secret, "asm://") ? data.aws_secretsmanager_secret_version.default[v.secret].secret_string : v.secret
+      ) : null
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
webhooks = {
for k, v in coalesce(var.webhooks, {}) : k => {
active = v.active
events = v.events
url = v.url
content_type = v.content_type
insecure_ssl = v.insecure_ssl
secret = v.secret != null ? (
startswith(v.secret, "ssm://") ? nonsensitive(data.aws_ssm_parameter.default[v.secret].value) :
startswith(v.secret, "asm://") ? nonsensitive(data.aws_secretsmanager_secret_version.default[v.secret].secret_string) : v.secret
) : null
}
}
webhooks = {
for k, v in coalesce(var.webhooks, {}) : k => {
active = v.active
events = v.events
url = v.url
content_type = v.content_type
insecure_ssl = v.insecure_ssl
secret = v.secret != null ? sensitive(
startswith(v.secret, "ssm://") ? data.aws_ssm_parameter.default[v.secret].value :
startswith(v.secret, "asm://") ? data.aws_secretsmanager_secret_version.default[v.secret].secret_string : v.secret
) : null
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main.tf` around lines 111 - 123, The webhook secret resolution currently
uses nonsensitive() to unwrap SSM/ASM values (in the webhooks mapping for
var.webhooks), which exposes secrets; change it to wrap the entire resolution in
sensitive() instead. Locate the webhooks block and the secret expression
referencing data.aws_ssm_parameter.default[...] and
data.aws_secretsmanager_secret_version.default[...] and replace the
nonsensitive(...) calls with sensitive(...) so the resolved SSM/ASM values
remain marked sensitive (preserving var.webhooks sensitive = true semantics) and
return null when v.secret is null.

@mtweeman mtweeman force-pushed the feat/webhooks-secrets branch from 262cf63 to 5bf315b Compare April 21, 2026 18:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage Needs triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant