<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: auditing-api-key-management
description: >-
  Audit API key lifecycle management including creation, rotation, scope
  enforcement, exposure detection, and revocation. Covers cloud provider
  API keys (AWS, GCP, Azure), SaaS API tokens (GitHub, Slack, Stripe),
  secret scanning in repositories, and key hygiene policies.
domain: cybersecurity
subdomain: identity-access-management
tags:
  - api-keys
  - secrets-management
  - key-rotation
  - secret-scanning
  - aws-iam
  - gcp
  - github
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1552.004"]
---

# Auditing API Key Management

## Overview

API keys are bearer credentials — anyone possessing the key has the associated
permissions. Unlike user accounts, API keys often lack MFA, have no session
expiry, and accumulate excessive permissions over time. Exposed keys in source
code, CI logs, and configuration files are the leading cause of cloud account
compromise. Effective key management requires inventory, rotation enforcement,
least-privilege scoping, and continuous exposure monitoring.

Mode: `[MODE: BLUE]` for key hygiene audit; `[MODE: RED]` for key exposure hunting.

MITRE ATT&CK: T1552.004 (Private Keys), T1552.001 (Credentials in Files)

## Prerequisites

- AWS IAM access (credential reports, access advisor)
- GCP IAM and Service Account admin access
- GitHub organization admin (secret scanning alerts)
- truffleHog or gitleaks for repository scanning
- Python 3.10+ for agent tooling

## Key Concepts

### API Key Risk Matrix

| Risk Factor | Impact | Example |
|-------------|--------|---------|
| No rotation policy | Indefinite exposure window | 3-year-old AWS access key |
| Over-scoped permissions | Blast radius amplification | Admin key used for read-only task |
| Hardcoded in source | Exposed in repository history | API key in config.py committed |
| No IP restriction | Usable from anywhere | Stripe key without IP allowlist |
| Missing usage logging | Undetectable abuse | Key with no CloudTrail logging |
| Shared across services | Attribution impossible | One key used by 5 microservices |

### AWS Access Key Audit

```bash
# Generate IAM credential report
aws iam generate-credential-report
aws iam get-credential-report --output text --query Content | base64 -d > cred-report.csv

# Find access keys older than 90 days
aws iam list-users --query 'Users[].UserName' --output text | while read user; do
  aws iam list-access-keys --user-name "$user" \
    --query "AccessKeyMetadata[?Status=='Active' && \
      CreateDate<='$(date -d '-90 days' -u +%Y-%m-%dT%H:%M:%SZ)'].\
      {User:UserName,KeyId:AccessKeyId,Created:CreateDate}" \
    --output table
done

# Check last-used date for access keys
aws iam get-access-key-last-used --access-key-id AKIAEXAMPLE

# Find keys with no usage in 90 days
aws iam list-users --query 'Users[].UserName' --output text | while read user; do
  aws iam list-access-keys --user-name "$user" --output json | \
    jq -r '.AccessKeyMetadata[] | select(.Status=="Active") | .AccessKeyId' | \
    while read key; do
      LAST=$(aws iam get-access-key-last-used --access-key-id "$key" \
        --query 'AccessKeyLastUsed.LastUsedDate' --output text)
      echo "$user $key $LAST"
    done
done
```

### GCP Service Account Key Audit

```bash
# List all service account keys
gcloud iam service-accounts list --format=json | \
  jq -r '.[].email' | while read sa; do
    echo "=== $sa ==="
    gcloud iam service-accounts keys list \
      --iam-account="$sa" \
      --format="table(name.basename(), keyType, validAfterTime, validBeforeTime)"
  done

# Find user-managed keys (should be minimized)
gcloud iam service-accounts keys list \
  --iam-account="SA_EMAIL" \
  --managed-by=user \
  --format=json | jq '.[] | {keyId: .name, created: .validAfterTime}'
```

### GitHub Secret Scanning

```bash
# List secret scanning alerts for organization
gh api /orgs/ORG/secret-scanning/alerts \
  --jq '.[] | {number, state, secret_type, created_at, push_protection_bypassed}'

# List alerts for a specific repository
gh api /repos/OWNER/REPO/secret-scanning/alerts \
  --jq '.[] | {number, secret_type, state, created_at, resolved_at}'
```

### Repository Secret Scanning

```bash
# Scan repository with truffleHog
trufflehog git https://github.com/org/repo --json --only-verified

# Scan with gitleaks
gitleaks detect --source . --report-path gitleaks-report.json --report-format json

# Scan for specific patterns
gitleaks detect --source . --config='{
  "rules": [
    {"id": "aws-access-key", "regex": "AKIA[0-9A-Z]{16}"},
    {"id": "stripe-key", "regex": "sk_live_[a-zA-Z0-9]{24,}"},
    {"id": "github-pat", "regex": "ghp_[a-zA-Z0-9]{36}"}
  ]
}'
```

## Workflow

1. **Inventory** — Enumerate all API keys across cloud providers and SaaS
2. **Age Check** — Flag keys older than rotation policy (default: 90 days)
3. **Usage Audit** — Identify unused keys via access advisor / last-used data
4. **Scope Review** — Verify keys have minimal required permissions
5. **Exposure Scan** — Run secret scanning on all repositories and CI systems
6. **Rotate** — Replace aged keys, deactivate old, verify no breakage
7. **Automate** — Implement key rotation automation (Vault, AWS Secrets Manager)

## Detection

```yaml
title: Auditing Api Key Management Detection
id: f417b643-a973-4911-9ee3-eedaaa73dbcb
status: experimental
description: Detects suspicious activity related to auditing api key management techniques in identity access management context
logsource:
  category: authentication
  product: windows
detection:
  selection:
    EventType: authentication
    Status: failure
  condition: selection
level: medium
tags:
  - attack.t1552.004
  - attack.credential_access
falsepositives:
  - Automated password rotation by privileged access management tools
```

## Verification

- [ ] All API keys inventoried with owner, purpose, and rotation schedule
- [ ] No access keys older than 90 days (AWS CIS Benchmark 1.14)
- [ ] Unused keys (> 90 days no usage) deactivated and scheduled for deletion
- [ ] GitHub secret scanning enabled with push protection on all repositories
- [ ] CI/CD pipelines use dynamic credentials (OIDC federation) not static keys
- [ ] API keys scoped to minimum required permissions
- [ ] Key rotation automated via secrets manager
- [ ] Secret scanning runs in pre-commit hooks and CI pipeline

## References

- [AWS — IAM Best Practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
- [CIS AWS Benchmark — Access Key Rotation](https://www.cisecurity.org/benchmark/amazon_web_services)
- [GitHub Secret Scanning](https://docs.github.com/en/code-security/secret-scanning)
- [truffleHog Documentation](https://github.com/trufflesecurity/trufflehog)
- [MITRE ATT&CK T1552.004](https://attack.mitre.org/techniques/T1552/004/)
