-
Notifications
You must be signed in to change notification settings - Fork 10
fix(cd): Update to support multiple secret values #1205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7360cb5
17006e5
a504c7c
2087ce4
9669807
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -1,37 +1,51 @@ | ||||||||
| #!/usr/bin/env sh | ||||||||
| # | ||||||||
| # Fetch a JSON secret from AWS Secrets Manager and write it as a docker-compose | ||||||||
| # env_file (.env.secrets). Run on the EC2 host at deploy time, BEFORE | ||||||||
| # `docker compose up`. Never run at image build time — that would bake secrets | ||||||||
| # into image layers. | ||||||||
| # Fetch one or more JSON secrets from AWS Secrets Manager and write them as a | ||||||||
| # docker-compose env_file (.env.secrets). Run on the EC2 host at deploy time, | ||||||||
| # BEFORE `docker compose up`. Never run at image build time — that would bake | ||||||||
| # secrets into image layers. | ||||||||
| # | ||||||||
| # Auth: relies on the EC2 instance IAM role (no static AWS keys). | ||||||||
| # | ||||||||
| # Required env: | ||||||||
| # SECRET_ID Secret name or ARN, e.g. kaapi/staging | ||||||||
| # SECRET_ID Comma-separated secret names or ARNs, e.g. | ||||||||
| # "kaapi-staging-rds, kaapi-staging-rabbitmq". | ||||||||
| # Secrets are appended in order; on a duplicate key the | ||||||||
| # last secret wins (docker compose reads the last line). | ||||||||
| # Optional env: | ||||||||
| # AWS_DEFAULT_REGION AWS region (default: ap-south-1) | ||||||||
| # SECRETS_ENV_FILE Output path (default: .env.secrets) | ||||||||
|
|
||||||||
| set -e | ||||||||
|
|
||||||||
| SECRET_ID=${SECRET_ID:?SECRET_ID not set} | ||||||||
| SECRET_IDS=${SECRET_ID:?SECRET_ID not set} | ||||||||
| AWS_REGION=${AWS_DEFAULT_REGION:-ap-south-1} | ||||||||
| OUT=${SECRETS_ENV_FILE:-.env.secrets} | ||||||||
|
|
||||||||
| command -v aws >/dev/null 2>&1 || { echo "[fetch-secrets] aws CLI not found on host" >&2; exit 1; } | ||||||||
| command -v jq >/dev/null 2>&1 || { echo "[fetch-secrets] jq not found on host" >&2; exit 1; } | ||||||||
|
|
||||||||
| echo "[fetch-secrets] Fetching secret | id: ${SECRET_ID} | region: ${AWS_REGION}" | ||||||||
| umask 077 | ||||||||
| TMP="${OUT}.tmp" | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Create a unique temporary file for each invocation. If two deployments run concurrently, both processes write to Proposed fix-TMP="${OUT}.tmp"
+TMP=$(mktemp "${OUT}.XXXXXX")
+trap 'rm -f "$TMP"' EXIT📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsSource: Learnings |
||||||||
| printf '# Generated by fetch-secrets.sh — do not edit, do not commit.\n' > "${TMP}" | ||||||||
|
|
||||||||
| SECRET_JSON=$(aws secretsmanager get-secret-value \ | ||||||||
| --secret-id "${SECRET_ID}" \ | ||||||||
| --region "${AWS_REGION}" \ | ||||||||
| --query SecretString --output text) | ||||||||
| OLD_IFS=$IFS | ||||||||
| IFS=',' | ||||||||
| for ID in ${SECRET_IDS}; do | ||||||||
| # Secret names and ARNs never contain whitespace, so " a, b" splits cleanly. | ||||||||
| ID=$(printf '%s' "${ID}" | tr -d '[:space:]') | ||||||||
| [ -n "${ID}" ] || continue | ||||||||
|
|
||||||||
| umask 077 | ||||||||
| printf '# Generated by fetch-secrets.sh — do not edit, do not commit.\n' > "${OUT}" | ||||||||
| echo "${SECRET_JSON}" | jq -r 'to_entries[] | "\(.key)=\(.value)"' >> "${OUT}" | ||||||||
| echo "[fetch-secrets] Fetching secret | id: ${ID} | region: ${AWS_REGION}" | ||||||||
| SECRET_JSON=$(aws secretsmanager get-secret-value \ | ||||||||
| --secret-id "${ID}" \ | ||||||||
| --region "${AWS_REGION}" \ | ||||||||
| --query SecretString --output text) | ||||||||
| echo "${SECRET_JSON}" | jq -r 'to_entries[] | "\(.key)=\(.value)"' >> "${TMP}" | ||||||||
| done | ||||||||
| IFS=$OLD_IFS | ||||||||
|
|
||||||||
| mv "${TMP}" "${OUT}" | ||||||||
|
|
||||||||
| COUNT=$(echo "${SECRET_JSON}" | jq 'length') | ||||||||
| COUNT=$(grep -c '=' "${OUT}") | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Do not let an empty secret set fail the deploy. If every fetched JSON secret is Proposed fix-COUNT=$(grep -c '=' "${OUT}")
+COUNT=$(awk 'index($0, "=") { count++ } END { print count + 0 }' "${OUT}")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
| echo "[fetch-secrets] Wrote ${COUNT} keys | file: ${OUT}" | ||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use
printfto normalizeSECRET_ID.If
STAGING_SECRET_IDis the valid secret name-n,echotreats it as an option and emits no value. The remote script then fails becauseSECRET_IDis empty. AWS permits-in secret names and requires only one character. (docs.aws.amazon.com)📝 Committable suggestion
🤖 Prompt for AI Agents