BEGINNERAWS-CLISECRETS

Fetch and Parse a Secret from AWS Secrets Manager

Use aws secretsmanager get-secret-value with jq to fetch a JSON secret and pipe individual fields into shell variables.

Published May 20, 2026
aws-clisecrets-managerjqshellsecurity

aws secretsmanager get-secret-value fetches a secret from AWS Secrets Manager. Combined with jq, you can pull individual fields out of a JSON secret and assign them to shell variables in one line. This is the pattern I use for loading database credentials and API keys into deploy scripts.

Tested on AWS CLI v2.17, jq 1.7.

When to Use This

  • Loading database credentials into a deploy or migration script
  • Fetching an API key for a one-off CLI invocation
  • Bootstrapping environment variables on a non-AWS machine
  • Reading rotated credentials in a CI/CD pipeline

Don't use this when you can use IAM roles directly (always prefer IAM auth over secret-based auth) or when running inside a Lambda or ECS task that supports the Secrets Manager extension natively.

Code

# Fetch the raw secret value
aws secretsmanager get-secret-value \
  --secret-id prod/database \
  --query SecretString \
  --output text
 
# Parse a JSON secret and assign fields to shell vars
SECRET=$(aws secretsmanager get-secret-value \
  --secret-id prod/database \
  --query SecretString \
  --output text)
 
DB_HOST=$(echo "$SECRET" | jq -r '.host')
DB_PORT=$(echo "$SECRET" | jq -r '.port')
DB_USER=$(echo "$SECRET" | jq -r '.username')
DB_PASS=$(echo "$SECRET" | jq -r '.password')
 
# Or in one line per field, no intermediate variable
DB_PASS=$(aws secretsmanager get-secret-value \
  --secret-id prod/database \
  --query SecretString --output text \
  | jq -r '.password')

The -r flag on jq strips the surrounding JSON quotes so you get a raw string. Without it, DB_PASS would be "hunter2" instead of hunter2.

Usage

A deploy script that loads credentials from Secrets Manager and runs a database migration:

#!/usr/bin/env bash
set -euo pipefail
 
SECRET_ID="prod/database"
REGION="ap-south-1"
 
echo "→ Fetching credentials from $SECRET_ID..."
SECRET=$(aws secretsmanager get-secret-value \
  --secret-id "$SECRET_ID" \
  --region "$REGION" \
  --query SecretString --output text)
 
export PGHOST=$(echo "$SECRET" | jq -r '.host')
export PGPORT=$(echo "$SECRET" | jq -r '.port')
export PGUSER=$(echo "$SECRET" | jq -r '.username')
export PGPASSWORD=$(echo "$SECRET" | jq -r '.password')
export PGDATABASE=$(echo "$SECRET" | jq -r '.dbname')
 
echo "→ Running migrations..."
psql -f migrations/2026-05-rotate-keys.sql
 
# Unset so they don't leak into a child process or shell history
unset PGPASSWORD

The unset PGPASSWORD at the end is the small but important detail. Without it, the secret stays in the shell's environment for the lifetime of the session.

Caveats

  • Don't echo the secret. It ends up in shell history, CI logs, and crash dumps. Pipe it directly into the consumer command.
  • set -x (debug mode) prints every variable assignment. That includes secrets. Either set +x before the secret block or read the secret without expansion.
  • --secret-id accepts both names and ARNs. Names are shorter; ARNs work across accounts. Use names for the same-account case.
  • Region matters. Secrets are regional. If your script doesn't specify --region, it uses the default profile region, which may not be where the secret lives.
  • Secrets Manager charges per API call AND per secret per month. Cache the value in your script if you're calling it in a loop.
  • jq -r is essential for shell consumption. Without it, the value is a quoted JSON string and your downstream commands break in confusing ways.

Frequently Asked Questions

Should secrets be stored as JSON or plain strings in Secrets Manager?

Store as JSON when one secret has multiple related fields (database connection string with host, port, user, password). Use plain strings for single-value secrets like API keys. JSON gives you per-field rotation and grouped access; plain strings are simpler.

Why pipe through jq instead of using --query?

--query operates on the AWS CLI response shape (where the secret JSON is a string inside SecretString). jq parses that string as JSON. You need both: --query to extract SecretString, jq to extract fields from inside it.

X (Twitter)LinkedIn