Store secrets in SSM Parameter Store instead of Secrets Manager (breaking) - #154
Merged
Conversation
Secrets Manager charges $0.40 per secret per month, so the two secrets this tool keeps cost ~$0.80/month per region. Standard-tier Parameter Store parameters are free, and nothing in our usage (no rotation, no resource policies, three API calls total) needed Secrets Manager. Swap SotoSecretsManager for SotoSSM and replace GetSecretValue / PutSecretValue / CreateSecret with GetParameter / PutParameter. PutParameter with overwrite: true is an upsert, so createSecret and the executeRequestAndCreateWhenNotExist retry loop are no longer needed. Values are stored as SecureString, encrypted with the account default aws/ssm managed key, so no kms:* permission is required. Parameters use Intelligent-Tiering. Measured session secrets are 2282 bytes right after authenticate and 2808 bytes once the download flow adds its cookies, against a 4096-byte standard-tier limit. That fits today, but mergeCookies never prunes expired entries and the MFA path adds an aasp cookie that has not been measured, so Intelligent-Tiering keeps the parameter free while it is small and promotes it rather than failing if it ever crosses 4 KB. Secrets are renamed to a hierarchy, /xcodeinstall/apple-credentials and /xcodeinstall/apple-session-token, so a single IAM resource covers both. The -s/--secretmanager-region flag and the secretManagerRegion config key keep their names so existing ~/.xcodeinstall/config.json files keep working. Nothing migrates from Secrets Manager: users re-run storesecrets and authenticate, as documented in the README.
The backend is no longer Secrets Manager, so the flag name should not mention it. The long form becomes --secret-region and the short form -s is unchanged, so existing `-s <region>` invocations keep working. The saved config key is renamed to match, which means the region in ~/.xcodeinstall/config.json is dropped on first run after upgrading and re-saved by the next command that passes -s. The profile is unaffected. Note that the ArgumentParser `.short` specifier derives the short flag from the property name, so renaming the property to parameterStoreRegion would have silently produced -p and collided with --profile. Keeping the "secret" prefix keeps -s correct without an explicit customShort. The README migration section now lists the three things an existing user has to do: update the IAM policy, re-create the secrets, and rename the flag in their scripts.
sebsto
force-pushed
the
feat/parameter-store
branch
from
August 12, 2026 10:34
ee9e6ce to
7ae1818
Compare
Owner
Author
Code Review — Migrate from Secrets Manager to SSM Parameter StoreOverall VerdictClean, well-scoped migration. The diff removes more code than it adds (−235 / +188 net), which is always a good sign for a simplification. SSM Parameter Store with SimplicityGood:
Minor:
Duplicated Code
Both prompt for username + password using Suggestion: Extract a shared helper that takes the display message as a parameter. SecurityGood:
Observation (not a blocker):
Other
Summary
Ready to merge. Duplicated prompt will be consolidated in a follow-up commit on this branch. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Moves the AWS secrets backend from Secrets Manager to SSM Parameter Store. Secrets Manager bills $0.40 per secret per month, so the two secrets this tool keeps cost about $0.80/month per region. Standard-tier Parameter Store parameters are free, and nothing in our usage needed Secrets Manager: no rotation, no resource policies, and only three API calls in total.
This is a breaking change and warrants a major version bump. Existing users must update their IAM policy, re-create their secrets, and rename one flag in their scripts. See Migration below.
Plan and measurements:
.claude/plans/parameter-store-migration.mdWhat changed
SotoSecretsManager→SotoSSM.GetSecretValue/PutSecretValue/CreateSecret→GetParameter/PutParameter.PutParameterwithoverwrite: trueis an upsert, socreateSecretand theexecuteRequestAndCreateWhenNotExistretry loop are gone. That is most of the deleted lines.SecureString, encrypted with the account's defaultaws/ssmmanaged key, so nokms:*permission is required./xcodeinstall/apple-credentialsand/xcodeinstall/apple-session-token, so one IAM resource covers both.AuthenticateCommandnow catchesSSMErrorType.parameterNotFoundin place ofSecretsManagerErrorType.resourceNotFoundException, keeping the transparent "credentials not stored yet, prompt for them" path working.--secretmanager-regionrenamed to--secret-regionsince the backend is no longer Secrets Manager.-sis unchanged.IAM permissions shrink from three actions to two:
{ "Sid": "xcodeinstall", "Effect": "Allow", "Action": [ "ssm:PutParameter", "ssm:GetParameter" ], "Resource": "arn:aws:ssm:*:000000000000:parameter/xcodeinstall/*" }Migration
Three things are required of an existing user:
ssm:*actions above. Nothing works until this is done.storesecretsandauthenticate, then delete the old Secrets Manager secrets so they stop being billed.--secretmanager-region→--secret-region. Scripts using the short-sform need no change.Also,
~/.xcodeinstall/config.jsonuses a new key name for the region, so a saved region is dropped on the first run after upgrading and re-saved by the next command that passes-s. The saved profile is unaffected.The README has all of this in a dedicated migration callout.
Why Intelligent-Tiering
Standard-tier parameters cap the value at 4096 bytes, where Secrets Manager allowed 64 KB. Measured against a real account:
apple-credentialsapple-session-tokenright afterauthenticateapple-session-tokenafter a laterdownloadThe 526-byte jump is the download flow adding
ADCDownloadAuth(384) andDSESSIONID(137). Peak observed is 69% of the limit, so standard tier would fit today. Two things make that an unsafe assumption:mergeCookiesreplaces same-name cookies but never prunes expired ones, so the value only grows; and no measured session contains theaaspcookie thatidmsa.apple.comsets on the two-factor path, which would likely land a session around 3.3–3.8 KB.Intelligent-Tieringkeeps the parameter in the free standard tier while it is small and promotes it to advanced ($0.05/parameter/month, 8 KB) only if it ever crosses 4 KB, instead of hard-failing. Worst case is still 8x cheaper than Secrets Manager. Note the promotion is one-way.Testing
swift buildclean.swift test: 203 tests in 19 suites pass.-s, --secret-regionon bothauthenticateandstoresecrets, with-p, --profileintact.Package.resolvedunchanged.iam/ec2-policy.jsonvalidated as JSON.Not yet verified against a live account, and worth doing before merge:
storesecrets+authenticatethrough a real MFA prompt, thenlist/download, to confirm the session round-trips.kms:*, using a least-privilege role rather than an admin profile.Notes for the reviewer
ArgumentParser's
.shortspecifier derives the short flag from the property name. Renaming the property to something likeparameterStoreRegionwould have silently emitted-pand collided with--profile. Keeping thesecretprefix (secretRegion) keeps-scorrect without an explicitcustomShort.Drive-by: the README anchor
#using-aws-secrets-manager-1was already a dead link onmain(only one matching heading, so no-1suffix is generated). Since the line was being edited anyway, it now points at#using-aws-parameter-store.