ssmm 0.1.0

AWS SSM Parameter Store helper for team-scoped .env sync (systemd friendly)
ssmm-0.1.0 is not a library.

ssmm — AWS SSM Parameter Store helper for team-scoped .env sync

build license

A small Rust CLI that treats AWS SSM Parameter Store as the source of truth for a team's .env files, with a flat-key convention and tag-based overlays.

ssmm is intentionally narrow-scoped: it assumes you run Linux services (typically via systemd ExecStartPre) that consume a generated .env file with EnvironmentFile=. If that matches your setup, the tool is opinionated enough to remove a lot of shell-script boilerplate.

Why another SSM wrapper?

Existing tools (e.g. chamber) inject secrets as env vars at exec time. ssmm instead materializes a .env file on disk (mode 0600) that systemd loads via EnvironmentFile=. That makes it a drop-in replacement for plaintext .env in existing systemd-based deployments without changing the apps themselves.

Other opinions baked in:

  • Parameters live under /<team>/<app>/<key> — the first segment is your team namespace (for IAM policy scoping), the second is the app, and the key is flat (kintone-api-token, not kintone/api/token).
  • SecureString vs String is auto-detected from the key name (conservative: unknown keys default to SecureString). _path / _url / _channel / _name / _host / _port / _region / _endpoint / _dir suffixes map to String; anything containing webhook stays SecureString.
  • Each parameter is automatically tagged app=<app> so you can filter cross-namespace by tag later.

Install

Requires Rust 1.77+ (or whatever supports edition = "2024").

cargo install --git https://github.com/dmm-com/ssmm

Your IAM role needs: ssm:PutParameter, ssm:GetParametersByPath, ssm:GetParameters, ssm:DescribeParameters, ssm:DeleteParameter(s), ssm:AddTagsToResource, ssm:RemoveTagsFromResource, ssm:ListTagsForResource. SSM SecureString uses the AWS-managed key (alias/aws/ssm) by default.

Configure your team's prefix

# option 1: env var (recommended for systemd services)
export SSMM_PREFIX_ROOT=/myteam

# option 2: per-invocation flag
ssmm --prefix /myteam list --all

# default (no config) is /amu-revo

All subcommands operate under this root prefix. Parameters end up at /<prefix>/<app>/<key>.

Quick tour

# Put a whole .env file
cd your-app/
ssmm put --env .env
# ↳ /myteam/your-app/kintone-api-token (SecureString)
# ↳ /myteam/your-app/slack-channel     (String)

# List (CWD auto-detects app name via basename)
ssmm list
ssmm list --keys-only
ssmm list --all                    # across every app under /myteam
ssmm list --tag env=prod

# Sync SSM → .env (systemd ExecStartPre friendly)
ssmm sync --out ./.env
# wrote 10 variables to ./.env (mode 0600)

# Show one
ssmm show kintone-api-token

# Manage tags on an existing parameter
ssmm tag add kintone-api-token shared=true owner=backend
ssmm tag list kintone-api-token
ssmm tag remove kintone-api-token owner

# Dashboard of every app namespace
ssmm dirs

# Find duplicates (same key across apps, or identical values)
ssmm check --duplicates --values

# Migrate parameters between prefixes
ssmm migrate /old-prefix/app /myteam/app --delete-old

systemd integration

# ~/.config/systemd/user/myapp.service
[Service]
Environment=SSMM_PREFIX_ROOT=/myteam
ExecStartPre=/home/you/.cargo/bin/ssmm sync --app myapp --out /opt/myapp/.env
EnvironmentFile=/opt/myapp/.env
ExecStart=/opt/myapp/run.sh

ssmm sync is idempotent: if the generated content matches the existing file byte-for-byte, it's a no-op (ssmm: no change).

Shared namespace and tag overlays

Values shared across multiple apps have two expressions in ssmm:

# Put a cross-app value directly under /<prefix>/shared/*
ssmm put --app shared --env /path/shared.env

# Or tag an existing per-app parameter as shared
ssmm tag add kintone-api-token shared=true

# sync automatically overlays /<prefix>/shared/* (disable with --no-shared)
# and any tag-matched parameter via --include-tag
ssmm sync --include-tag shared=true

Precedence when the same key name appears in multiple layers: app > include-tag > shared. Conflicts are logged to stderr.

Auto-detection

When --app is omitted, ssmm picks the name from the current directory:

  • /home/you/services/my_api/my-api (snake_case → dash-case)
  • /home/you/services/billing-svc/billing-svc

Override with --app <name> any time.

Concurrency and throttling

SSM's PutParameter has a low per-account TPS (~3/s for standard parameters). ssmm caps concurrent writes to 3 and uses AWS SDK adaptive retry (max_attempts=10), so a 300-parameter bulk import completes without manual backoff.

Comparison

ssmm chamber dotenv-vault
Backend AWS SSM PS AWS SSM PS / S3 hosted
Output model .env file env vars at exec .env.vault file
systemd EnvironmentFile ✅ native needs chamber exec no
Key namespace convention <team>/<app>/<key> <service>/<key> env profile
Tag management ✅ (tag add/remove/list)
Cross-app shared values /shared/ + tag overlay
Language Rust Go Node.js

License

MIT. See LICENSE.