# AWS Secrets Manager

> Use when working with Aws Secrets Manager — aWS Secrets Manager secret rotation status, access analysis, cost tracking, and lifecycle management. Covers secret inventory, rotation configuration audit, last access tracking, resource policy review, and version management.

- Skill: `cloudthinker-ai/aws-secrets-manager` (Agent Skill)
- Install (CLI): `npx skillmds@latest add cloudthinker-ai/aws-secrets-manager`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cloudthinker-ai/aws-secrets-manager/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: cloudthinker-ai (https://skillmd.com/u/cloudthinker-ai)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/cloudthinker-ai/aws-secrets-manager

---


# AWS Secrets Manager Skill

Analyze AWS Secrets Manager secrets with parallel execution and anti-hallucination guardrails.

**Relationship to other AWS skills:**

- `aws-secrets-manager/` → Secrets Manager-specific analysis (rotation, access, lifecycle)
- `aws/` → "How to execute" (parallel patterns, throttling, output format)

## CRITICAL: Parallel Execution Requirement

**ALL independent operations MUST run in parallel using background jobs (&) and wait.**

```bash
#!/bin/bash
export AWS_PAGER=""

for secret in $secrets; do
  get_secret_metadata "$secret" &
done
wait
```

## Helper Functions

```bash
#!/bin/bash
export AWS_PAGER=""

# List all secrets
list_secrets() {
  aws secretsmanager list-secrets \
    --output text \
    --query 'SecretList[].[Name,RotationEnabled,LastRotatedDate,LastAccessedDate,CreatedDate]'
}

# Get secret metadata (NOT the value)
describe_secret() {
  local secret_id=$1
  aws secretsmanager describe-secret --secret-id "$secret_id" \
    --output text \
    --query '[Name,RotationEnabled,RotationRules.AutomaticallyAfterDays,LastRotatedDate,LastAccessedDate,LastChangedDate,VersionIdsToStages]'
}

# Get rotation configuration
get_rotation_config() {
  local secret_id=$1
  aws secretsmanager describe-secret --secret-id "$secret_id" \
    --output text \
    --query '[Name,RotationEnabled,RotationLambdaARN,RotationRules.AutomaticallyAfterDays,RotationRules.ScheduleExpression]'
}

# Get resource policy
get_resource_policy() {
  local secret_id=$1
  aws secretsmanager get-resource-policy --secret-id "$secret_id" \
    --output text \
    --query '[Name,ResourcePolicy]' 2>/dev/null
}

# List secret versions
list_versions() {
  local secret_id=$1
  aws secretsmanager list-secret-version-ids --secret-id "$secret_id" \
    --output text \
    --query 'Versions[].[VersionId,VersionStages[],CreatedDate]'
}
```

## Common Operations

### 1. Secret Inventory with Rotation Status

```bash
#!/bin/bash
export AWS_PAGER=""
aws secretsmanager list-secrets \
  --output text \
  --query 'SecretList[].[Name,RotationEnabled,LastRotatedDate,LastAccessedDate]' \
  | sort -k2
```

### 2. Rotation Compliance Audit

```bash
#!/bin/bash
export AWS_PAGER=""
SECRETS=$(aws secretsmanager list-secrets --output text --query 'SecretList[].Name')
for secret in $SECRETS; do
  aws secretsmanager describe-secret --secret-id "$secret" \
    --output text \
    --query '[Name,RotationEnabled,RotationLambdaARN,RotationRules.AutomaticallyAfterDays,LastRotatedDate]' &
done
wait
```

### 3. Stale Secrets Analysis (Not Accessed or Rotated)

```bash
#!/bin/bash
export AWS_PAGER=""
THRESHOLD_DAYS=90
THRESHOLD_DATE=$(date -u -d "$THRESHOLD_DAYS days ago" +"%Y-%m-%d" 2>/dev/null || date -u -v-${THRESHOLD_DAYS}d +"%Y-%m-%d")
aws secretsmanager list-secrets \
  --output text \
  --query 'SecretList[].[Name,LastAccessedDate,LastChangedDate,RotationEnabled]' \
  | awk -v thresh="$THRESHOLD_DATE" '$2 < thresh || $2 == "None" {print "STALE\t" $0}'
```

### 4. Resource Policy Review

```bash
#!/bin/bash
export AWS_PAGER=""
SECRETS=$(aws secretsmanager list-secrets --output text --query 'SecretList[].Name')
for secret in $SECRETS; do
  {
    policy=$(aws secretsmanager get-resource-policy --secret-id "$secret" \
      --output text --query 'ResourcePolicy' 2>/dev/null)
    if [ -n "$policy" ] && [ "$policy" != "None" ]; then
      printf "%s\tHAS_POLICY\n" "$secret"
    else
      printf "%s\tNO_POLICY\n" "$secret"
    fi
  } &
done
wait
```

### 5. Secret Version and Staging Labels

```bash
#!/bin/bash
export AWS_PAGER=""
SECRETS=$(aws secretsmanager list-secrets --output text --query 'SecretList[].Name' | head -20)
for secret in $SECRETS; do
  aws secretsmanager list-secret-version-ids --secret-id "$secret" \
    --output text \
    --query "Versions[].[\"$secret\",VersionId,VersionStages[],CreatedDate]" &
done
wait
```

## Anti-Hallucination Rules

1. **Never retrieve secret values in analysis** - Use `describe-secret` and `list-secrets` for metadata. Never call `get-secret-value` during analysis scripts. Secret values must never appear in output.
2. **LastAccessedDate granularity** - This is updated at most once per day and rounded to the date. It does not provide time-of-day precision.
3. **RotationEnabled != actively rotating** - A secret can have `RotationEnabled=true` but fail rotation. Check `LastRotatedDate` and CloudWatch metrics for actual rotation success.
4. **Cost is per secret per month** - $0.40/secret/month + $0.05/10,000 API calls. Secrets are billed regardless of access frequency.
5. **Deletion is scheduled, not immediate** - `delete-secret` schedules deletion (7-30 day window). During this window, the secret can be recovered.

## Output Format

Present results as a structured report:
```
Aws Secrets Manager Report
══════════════════════════
Resources discovered: [count]

Resource       Status    Key Metric    Issues
──────────────────────────────────────────────
[name]         [ok/warn] [value]       [findings]

Summary: [total] resources | [ok] healthy | [warn] warnings | [crit] critical
Action Items: [list of prioritized findings]
```

Target ≤50 lines of output. Use tables for multi-resource comparisons.

## Counter-Rationalizations

| Shortcut | Counter | Why |
|----------|---------|-----|
| "I'll skip discovery and check known resources" | Always run Phase 1 discovery first | Resource names change, new resources appear — assumed names cause errors |
| "The user only asked for a quick check" | Follow the full discovery → analysis flow | Quick checks miss critical issues; structured analysis catches silent failures |
| "Default configuration is probably fine" | Audit configuration explicitly | Defaults often leave logging, security, and optimization features disabled |
| "Metrics aren't needed for this" | Always check relevant metrics when available | API/CLI responses show current state; metrics reveal trends and intermittent issues |
| "I don't have access to that" | Try the command and report the actual error | Assumed permission failures prevent useful investigation; actual errors are informative |

## Common Pitfalls

- **Secrets Manager vs SSM Parameter Store**: Secrets Manager provides rotation, cross-account access, and secret versioning. SSM SecureString is simpler but lacks these features.
- **Rotation Lambda permissions**: The rotation Lambda needs permissions to both Secrets Manager and the target service (e.g., RDS). Missing permissions cause silent rotation failures.
- **Staging labels**: AWSCURRENT is the active version. AWSPENDING exists during rotation. AWSPREVIOUS is the previous version. Custom labels can be added.
- **CloudWatch statistics syntax**: Use spaces not commas: `--statistics Average Maximum`.
- **Cross-region replication**: Secrets can be replicated to other regions. Replica secrets are read-only. Check with `describe-secret` for `ReplicationStatus`.

