Skip to content

fix(aws): gate /api/scheduled/* with bearer mode + Secrets Manager#203

Merged
cristim merged 1 commit intofeat/multicloud-web-frontendfrom
fix/aws-scheduled-auth-mode-disabled
Apr 30, 2026
Merged

fix(aws): gate /api/scheduled/* with bearer mode + Secrets Manager#203
cristim merged 1 commit intofeat/multicloud-web-frontendfrom
fix/aws-scheduled-auth-mode-disabled

Conversation

@cristim
Copy link
Copy Markdown
Member

@cristim cristim commented Apr 30, 2026

Hotfix for the failing Lambda health check on feat/multicloud-web-frontend after #161 merged: https://github.com/LeanerCloud/CUDly/actions/runs/25148590105/job/73714185103.

Root cause

#161 made SCHEDULED_TASK_AUTH_MODE required at startup (fail-closed LoadConfig) but only wired the env var on the GCP and Azure compute modules. AWS Lambda was missed → boot fails:

scheduledauth: invalid configuration: SCHEDULED_TASK_AUTH_MODE is unset

Why not SCHEDULED_TASK_AUTH_MODE = "disabled"

That was my first attempt (force-pushed away). It would have shipped a production auth bypass: ModeDisabled lets every /api/scheduled/* request through, and the Lambda Function URL has authorization_type = NONE (the same module documents this). Even though pre-#161 the bearer check was a no-op when the secret was empty, codifying that state under the new validator is actively wrong.

Fix: bearer mode + Secrets Manager (Azure-pattern)

  • terraform/modules/secrets/aws/ — provision a random_password + aws_secretsmanager_secret + version for the scheduled-task bearer (gated by var.create_scheduled_task_secret, default true). Include in secret_read policy. Expose scheduled_task_secret_arn + _name outputs.
  • terraform/modules/compute/aws/lambda/ — set SCHEDULED_TASK_AUTH_MODE = "bearer" + SCHEDULED_TASK_SECRET_NAME = var.scheduled_task_secret_name on the Lambda env block. Add the secret ARN to the secrets_access IAM policy. Add the corresponding variables.
  • terraform/modules/compute/aws/fargate/ — same wiring on the task definition env block + IAM policy + variables, so Fargate doesn't regress when selected.
  • terraform/environments/aws/compute.tf — pass module.secrets.scheduled_task_secret_arn / _name into both compute_lambda and compute_fargate.

Runtime path (already in place from #161)

internal/server/app.go reads SCHEDULED_TASK_SECRET_NAME, resolveScheduledTaskSecret fetches the plaintext from AWS Secrets Manager via the SecretResolver, and buildScheduledAuth overrides saCfg.Bearer with that value before calling scheduledauth.New. The plaintext never lives in Lambda env or Terraform state.

Result

  • /api/scheduled/* on the public Lambda URL rejects every request that doesn't carry the resolved bearer secret.
  • AWS schedulers (EventBridge → direct lambda:InvokeFunction) bypass the HTTP middleware entirely and are unaffected.
  • Runtime IAM (Lambda task role) gains secretsmanager:GetSecretValue on the new secret only — least privilege.

Validation

  • terraform validate clean for terraform/modules/{secrets/aws, compute/aws/lambda, compute/aws/fargate} and terraform/environments/aws/
  • Pre-commit hooks all passed locally
  • Branch name remains fix/aws-scheduled-auth-mode-disabled for PR continuity, but the title now accurately reflects the implemented fix

Summary by CodeRabbit

  • New Features
    • Introduced bearer token authentication for scheduled tasks, with secrets securely managed in cloud secret storage rather than embedded in configuration
    • Added configurable option to enable or disable scheduled task authentication across Lambda and Fargate deployment platforms
    • Enhanced security for scheduled task endpoints

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 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: a8e47542-d0dd-4544-b10e-4519e4a6bf19

📥 Commits

Reviewing files that changed from the base of the PR and between 37efe20 and f001f83.

📒 Files selected for processing (8)
  • terraform/environments/aws/compute.tf
  • terraform/modules/compute/aws/fargate/main.tf
  • terraform/modules/compute/aws/fargate/variables.tf
  • terraform/modules/compute/aws/lambda/main.tf
  • terraform/modules/compute/aws/lambda/variables.tf
  • terraform/modules/secrets/aws/main.tf
  • terraform/modules/secrets/aws/outputs.tf
  • terraform/modules/secrets/aws/variables.tf
🚧 Files skipped from review as they are similar to previous changes (1)
  • terraform/modules/compute/aws/lambda/main.tf

📝 Walkthrough

Walkthrough

Adds optional scheduled-task bearer secret creation and propagation: a Secrets Manager secret is conditionally created and exported; compute modules (Lambda and Fargate) receive new inputs and set environment variables to enable bearer-mode scheduled-task auth; IAM permissions are expanded to allow reading the scheduled-task secret.

Changes

Cohort / File(s) Summary
Secrets module
terraform/modules/secrets/aws/main.tf, terraform/modules/secrets/aws/outputs.tf, terraform/modules/secrets/aws/variables.tf
Add conditional creation of a scheduled-task Secrets Manager secret, outputs for secret ARN/name, and a create_scheduled_task_secret input; update IAM policy data to grant GetSecretValue/DescribeSecret for the new secret.
Lambda module
terraform/modules/compute/aws/lambda/main.tf, terraform/modules/compute/aws/lambda/variables.tf
Add SCHEDULED_TASK_AUTH_MODE and SCHEDULED_TASK_SECRET_NAME env vars to Lambda and new input variables scheduled_task_secret_arn / scheduled_task_secret_name; expand IAM Secrets Manager read permissions to include scheduled-task secret ARN (and wildcard).
Fargate module
terraform/modules/compute/aws/fargate/main.tf, terraform/modules/compute/aws/fargate/variables.tf
Set container env vars SCHEDULED_TASK_AUTH_MODE=bearer and SCHEDULED_TASK_SECRET_NAME; add variables for scheduled-task secret ARN/name; extend task role Secrets Manager permissions to include the scheduled-task secret ARN (and -* variant).
Environment wiring
terraform/environments/aws/compute.tf
Pass scheduled-task secret ARN and name from module.secrets into compute modules, coercing to "" when unset (so downstream modules can opt-out).

Sequence Diagram(s)

sequenceDiagram
participant SecrMod as Secrets Module (Terraform)
participant TF as Root Terraform
participant CompMod as Compute Modules (Lambda/Fargate)
participant IAM as IAM Policy
participant Runtime as Lambda / Fargate Runtime
participant SM as AWS Secrets Manager

SecrMod->>TF: create secret (conditional) & outputs ARN/name
TF->>CompMod: pass secret ARN/name (or "")
CompMod->>IAM: include secret ARN in GetSecretValue/DescribeSecret policy
TF->>Runtime: set env vars SCHEDULED_TASK_AUTH_MODE, SCHEDULED_TASK_SECRET_NAME
Runtime->>SM: DescribeSecret / GetSecretValue using secret name (at startup)
SM-->>Runtime: secret value (bearer token)
Runtime->>Runtime: use bearer token for /api/scheduled/* auth
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

triaged, priority/p0, severity/high, urgency/now, impact/few, effort/m, type/security, type/bug

Poem

🐰 I hid a secret, soft and small,
In vaults where only runtimes call,
Tokens fetched at dawn's first light,
Schedules hop and run just right,
A rabbit cheers—secure and tall! 🥕

🚥 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 bearer mode authentication with AWS Secrets Manager for the /api/scheduled/* endpoint on AWS compute resources (Lambda and Fargate).
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
  • Commit unit tests in branch fix/aws-scheduled-auth-mode-disabled

Review rate limit: 4/5 reviews remaining, refill in 12 minutes.

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

@cristim
Copy link
Copy Markdown
Member Author

cristim commented Apr 30, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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 `@terraform/modules/compute/aws/lambda/main.tf`:
- Around line 58-70: The module currently sets SCHEDULED_TASK_AUTH_MODE =
"disabled", which leaves the public Lambda URL unprotected; change
SCHEDULED_TASK_AUTH_MODE to "bearer" and wire SCHEDULED_TASK_SECRET to a Secrets
Manager value (ensure you reference the secret resource used in this module,
e.g., the aws_secretsmanager_secret / aws_secretsmanager_secret_version you're
using) so bearer token validation is enforced, or alternatively remove/exclude
the public Lambda URL exposure for this function; update any related references
to SCHEDULED_TASK_SECRET and the Lambda URL configuration to ensure the URL is
not publicly reachable if you cannot immediately use bearer mode.
🪄 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: e842fc79-6f27-4210-b998-625370aea0e2

📥 Commits

Reviewing files that changed from the base of the PR and between 903ff85 and 37efe20.

📒 Files selected for processing (1)
  • terraform/modules/compute/aws/lambda/main.tf

Comment thread terraform/modules/compute/aws/lambda/main.tf Outdated
PR #161 made SCHEDULED_TASK_AUTH_MODE required at startup but the env
var was only wired on GCP and Azure. AWS Lambda was missed and the
post-merge deploy crashed with:

    scheduledauth: invalid configuration: SCHEDULED_TASK_AUTH_MODE is
    unset (set to oidc, bearer, or disabled)

(See https://github.com/LeanerCloud/CUDly/actions/runs/25148590105 .)

The "obvious" fix — wire SCHEDULED_TASK_AUTH_MODE=disabled to mirror
the pre-#161 reality where the bearer check was a no-op when the
secret was empty — is wrong. ModeDisabled lets every /api/scheduled/*
request through, and the Lambda Function URL has authorization_type =
NONE (the same comment in this module's main.tf explicitly notes the
URL is public). That would ship a production auth bypass.

Instead, run AWS in bearer mode with the secret resolved from Secrets
Manager at runtime — same model Azure already uses.

Changes:

* terraform/modules/secrets/aws — provision a random_password +
  aws_secretsmanager_secret + version for the scheduled-task bearer
  (gated by var.create_scheduled_task_secret, default true). Include
  it in the secret_read policy and expose ARN + name outputs.

* terraform/modules/compute/aws/lambda — set
  SCHEDULED_TASK_AUTH_MODE=bearer +
  SCHEDULED_TASK_SECRET_NAME=var.scheduled_task_secret_name on the
  Lambda env block. Add the secret ARN to the secrets_access IAM
  policy. Add the corresponding scheduled_task_secret_arn /
  scheduled_task_secret_name variables.

* terraform/modules/compute/aws/fargate — same wiring on the task
  definition env block + IAM policy + variables. Fargate isn't the
  default platform but should not regress when selected.

* terraform/environments/aws/compute.tf — pass
  module.secrets.scheduled_task_secret_arn / _name into both
  compute_lambda and compute_fargate.

Runtime path (already in place from #161): app.go reads
SCHEDULED_TASK_SECRET_NAME, resolveScheduledTaskSecret fetches the
plaintext from AWS Secrets Manager via the SecretResolver, and
buildScheduledAuth overrides saCfg.Bearer with that value before
calling scheduledauth.New. The plaintext never lives in Lambda env or
Terraform state.

Validation: terraform validate clean for all four touched modules.
Once deployed, /api/scheduled/* on the public Lambda URL will reject
every request that doesn't carry the resolved bearer secret. AWS
schedulers (EventBridge -> direct Lambda invocation) bypass the HTTP
middleware entirely, so they are unaffected.
@cristim cristim force-pushed the fix/aws-scheduled-auth-mode-disabled branch from 37efe20 to f001f83 Compare April 30, 2026 06:31
@cristim cristim changed the title fix(aws): set SCHEDULED_TASK_AUTH_MODE=disabled on Lambda to unblock boot fix(aws): gate /api/scheduled/* with bearer mode + Secrets Manager Apr 30, 2026
@cristim
Copy link
Copy Markdown
Member Author

cristim commented Apr 30, 2026

Force-pushed 37efe206ef001f832d. The disabled approach was wrong — that ships an auth bypass on the public Lambda URL. Replaced with bearer mode + Secrets Manager (Azure-pattern), wired through Lambda + Fargate + the AWS secrets module. PR title and body updated to match. Force-push was acceptable here since the prior commit was actively wrong and no review/work was based on it; force-with-lease guarded against races.

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

@cristim — understood. The rationale is sound: shipping disabled on a public Lambda URL would have been a real auth bypass, so the pivot to bearer mode + Secrets Manager is the right call. I'll kick off a fresh review of f001f832d now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim cristim merged commit 853c3c6 into feat/multicloud-web-frontend Apr 30, 2026
4 checks passed
@cristim cristim added type/security Security finding severity/high Significant harm urgency/now Drop other things impact/all-users Affects every user effort/s Hours priority/p0 Drop everything; same-day fix triaged Item has been triaged labels Apr 30, 2026
@cristim cristim deleted the fix/aws-scheduled-auth-mode-disabled branch April 30, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/all-users Affects every user priority/p0 Drop everything; same-day fix severity/high Significant harm triaged Item has been triaged type/security Security finding urgency/now Drop other things

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant