AWS SSM Parameter Store — Secrets-Konvention

Statt 1Password (haben wir nicht) nutzen wir AWS Systems Manager Parameter Store als zentralen Secrets-Vault. AWS-nativ, gratis fuer Standard-Parameter, KMS-encrypted bei SecureString, IAM-kontrolliert.

Wann SSM, wann woanders

SSM Parameter Store fuer:

  • AWS-Service-Account-Credentials (Access Key ID + Secret Access Key)
  • Drittanbieter-API-Tokens die Apps in AWS brauchen (Anthropic, Replicate, Runway, Papierkram, TicketPAY)
  • DB-Connection-Strings fuer App-zu-DB
  • OAuth-Client-Secrets fuer hosted MCPs

Lokal .env.local (gitignored) fuer:

  • MCP-Server-Tokens auf Marvins Laptop (Papierkram, TicketPAY, M365, etc.)
  • Dev-Credentials die nur lokal gebraucht werden
  • Schnelle Iteration ohne SSM-Roundtrip

macOS Keychain fuer:

  • Persoenliche Browser-Saved-Logins (kein Vault-relevantes Material)
  • macOS-System-Credentials

Naming-Konvention

/agentic-ventures/<account-slug>/<service>/<key-name>
  • <account-slug> — AWS-Account-Alias aus _index: av-mgmt, av-production, av-becker, mk-privat
  • <service> — Tool/Service: bas-bedrock-pilot, papierkram, ticketpay, replicate, mcp-vf-hosted
  • <key-name> — konkreter Wert: access-key-id, secret-access-key, api-token, oauth-client-secret, db-connection-string

Beispiele:

PfadType
/agentic-ventures/av-becker/bas-bedrock-pilot/access-key-idString
/agentic-ventures/av-becker/bas-bedrock-pilot/secret-access-keySecureString
/agentic-ventures/av-production/papierkram/api-tokenSecureString
/agentic-ventures/av-mgmt/scalekit/owner-credentialsSecureString

Schreiben

# String (nicht-sensible Werte wie Account-IDs, Key-IDs)
aws ssm put-parameter \
  --name "/agentic-ventures/av-becker/bas-bedrock-pilot/access-key-id" \
  --value "AKIA..." \
  --type String \
  --region eu-central-1 \
  --profile av-becker
 
# SecureString (alles geheime)
aws ssm put-parameter \
  --name "/agentic-ventures/av-becker/bas-bedrock-pilot/secret-access-key" \
  --value "<paste hier, NICHT in Chat>" \
  --type SecureString \
  --region eu-central-1 \
  --profile av-becker

SecureString nutzt automatisch den AWS-managed KMS-Key alias/aws/ssm — gratis. Eigener KMS-Key nur wenn fuer Compliance noetig.

Lesen

# Direkt
aws ssm get-parameter \
  --name "/agentic-ventures/av-becker/bas-bedrock-pilot/secret-access-key" \
  --with-decryption \
  --query Parameter.Value \
  --output text \
  --region eu-central-1 \
  --profile av-becker
 
# In Shell-Variable
export BEDROCK_SECRET=$(aws ssm get-parameter --name "..." --with-decryption --query Parameter.Value --output text)
 
# In .env.local automatisch generieren
aws ssm get-parameters-by-path --path "/agentic-ventures/av-becker/bas-bedrock-pilot/" --with-decryption \
  --query "Parameters[*].[Name,Value]" --output text | \
  awk -F/ '{print toupper($NF)"="$2}' > .env.local

App-Integration

Boto3 (Python):

import boto3
ssm = boto3.client("ssm", region_name="eu-central-1")
secret = ssm.get_parameter(
    Name="/agentic-ventures/av-becker/bas-bedrock-pilot/secret-access-key",
    WithDecryption=True
)["Parameter"]["Value"]

AWS SDK (Node.js):

import { SSMClient, GetParameterCommand } from "@aws-sdk/client-ssm";
const ssm = new SSMClient({ region: "eu-central-1" });
const { Parameter } = await ssm.send(new GetParameterCommand({
  Name: "/agentic-ventures/av-becker/bas-bedrock-pilot/secret-access-key",
  WithDecryption: true,
}));

ECS/Lambda Env-Var-Injection: ECS Task Definition oder Lambda Environment kann SSM-Parameter direkt als ENV mounten — kein Code-Change noetig:

"secrets": [{
  "name": "BEDROCK_SECRET_KEY",
  "valueFrom": "arn:aws:ssm:eu-central-1:<account>:parameter/agentic-ventures/av-becker/bas-bedrock-pilot/secret-access-key"
}]

IAM-Permissions

Reader-Pattern fuer Apps (Service-Account/Lambda/ECS):

{
  "Effect": "Allow",
  "Action": ["ssm:GetParameter", "ssm:GetParameters", "ssm:GetParametersByPath"],
  "Resource": "arn:aws:ssm:eu-central-1:<account>:parameter/agentic-ventures/<account-slug>/*"
}

KMS-Decrypt zusaetzlich noetig wenn SecureString:

{
  "Effect": "Allow",
  "Action": "kms:Decrypt",
  "Resource": "arn:aws:kms:eu-central-1:<account>:key/aws/ssm"
}

Keine Wildcards ueber Account-Boundaries — pro Account-Service-Pair eigene Reader-Policy.

Rotation

  • Quartalsweise (alle 90 Tage): API-Tokens (Papierkram, TicketPAY, M365-Secret, Replicate, Runway). Siehe token-hygiene.
  • AWS Access Keys: alle 90 Tage rotieren oder bei Verdacht. Two-key-Pattern fuer no-downtime: neuen Key erstellen → Apps umstellen (SSM-Wert ueberschreiben) → alten Key deaktivieren → 24h warten → alten Key loeschen.
  • OAuth-Refresh-Tokens (Google): keine Rotation noetig wenn Consent-Screen “Published”.

Bei Token-Leak

  1. Sofort widerrufen beim Anbieter (AWS IAM → Access Key deaktivieren, Papierkram → API-Settings, Google → Drittanbieter-Zugriff)
  2. Neuen Token generieren, in SSM ueberschreiben (gleicher Pfad → automatisches Versioning, alte Version bleibt fuer Audit)
  3. Apps neustarten wenn ENV-injected, sonst neu lesen
  4. Postmortem in intern/runs/ dokumentieren

Was gehoert NICHT in SSM

  • Kunden-PII (Email-Adressen, Telefonnummern, Adressen) — separates Pattern (verschluesselt unter ~/source/.secrets/<repo>-pii/, gemaess t5-pii-in-repo—backup)
  • Beleg-PDFs / Vertraege — kommen nach assets/finanzen/<jahr>/ (gitignored) bzw. extern/inbound/vertraege/
  • Secrets fuer reine Dev-Maschine ohne AWS-Bezug — .env.local reicht

Migrationspfad fuer existierende Secrets

Wenn neue Service-Credentials anfallen, direkt in SSM. Bestehende lokale .env.local-Werte muessen nicht migriert werden, ausser sie werden auch von Cloud-Apps gebraucht.

Aktueller Migrations-Backlog (Stand 2026-05-08):

SecretAktuell woSoll-SSM-Pfad
BAS Bedrock Pilot Access KeyTODO migrieren/agentic-ventures/av-becker/bas-bedrock-pilot/{access-key-id,secret-access-key}
Papierkram-Token.env.local lokalspaeter, wenn Cloud-App das braucht
TicketPAY-Key.env.local lokalspaeter