Figment.so
Mac hostingWebsite hostingGuidesHow to usePricing

Rotate Agent API Keys on a Hosted Mac Safely

A rotation that breaks the running agent is worse than no rotation. Issue the new key, verify it works, swap it into the agent, and only then revoke the old one — with a timed rollback window in case the new credential misbehaves in production.

Choose a Mac Plan for Agent Key Management

The Figment virtual Intel macOS environment at $29/month (2 vCPU, 8 GiB RAM, 80 GiB disk) is enough to run automation scripts, call vendor APIs and manage credentials. It runs real macOS, so the security CLI, the login Keychain and launchd all work. Compatible Intel toolchains (Xcode 26 or earlier) are usable on it; it is not just a relay to another Mac.

Upgrade to an M-series Mac from $95/month if the agent needs to execute ARM-only binaries, run Xcode 27, or use frameworks that require Apple silicon. The specific chip, RAM and disk at that entry price are confirmed in the quote rather than fixed in the catalog, and physical M-series requests are queued until supply is confirmed. For a small team with several agents and an on-call contact, the Managed Mac Team at $999/month includes two M-series Macs, two CI runners, team setup, backups, monitoring and one hour of monthly support.

For a quick entry-price sanity check against a dedicated-Mac vendor, CloudMac lists a dedicated M4 (16 GB / 256 GB) at $99.99/month or $999/year on cloudmac.org/pricing. The annual option is lower than 12 × $95; $29 and $95 are Figment's lower entry prices for different hardware classes, not the same M4 configuration. Pick the plan by the job: the $29 VM for credential work and scripting, M-series for ARM execution, Managed for the included CI setup and support time.

The VM is reached through the browser console. Run key-management scripts from the desktop terminal or from an outbound CI runner you connect to your own service. Do not type key values on a shell command line where they would land in history.

Store Keys in the macOS Keychain, Not in Files

The security command manages the Keychain from the terminal with no GUI. Apple's Keychain Services documentation describes the storage model and access control; run man security on your deployed macOS version to confirm flags for that release.

Store an API key interactively:

# Add a generic-password item to the login keychain.
# -s service  -a account  -T pre-authorises a binary  -w prompts for the value
security add-generic-password \
  -s "openai-agent" \
  -a "prod" \
  -T /usr/bin/python3 \
  -w

-T pre-authorises the named binary so background launchd jobs do not trigger a GUI prompt ("User interaction is not allowed"). -w with no argument makes the shell prompt for the value, so the secret never appears in history.

Read the key in a script:

key=$(security find-generic-password -s "openai-agent" -a "prod" -w)

Never dump the secret to a .env file, and never export the entire environment to disk — it will contain other credentials. If a key has to move to a CI service, transfer the secret name, then paste the value into that CI's secret manager by hand.

Staged Rotation Checklist with Rollback

Work the stages in order. Verify each row before moving on.

StageActionVerifyRollback if it fails
1 — GenerateCreate a new key in the provider dashboardKey ID appears in the dashboardDelete it in the dashboard
2 — Store newsecurity add-generic-password -s "openai-agent" -a "staging" -wfind-generic-password … -a "staging" -w returns a valuesecurity delete-generic-password -s "openai-agent" -a "staging"
3 — Smoke testRun one agent job against the staging account labelJob exits 0, API returns a valid responseFix the key or config; do not continue
4 — PromotePoint the agent config at staging; restart the agentFirst production job exits 0Revert config to prod; restart
5 — MonitorLet the agent run through the rollback window (at least 2 hours; 24 hours for critical jobs)No auth errors in the agent logRevert config; keep prod key alive
6 — Revoke oldRevoke the old key in the provider dashboardOld key returns 401 on a direct requestNone — rollback is no longer possible
7 — Remove entrysecurity delete-generic-password -s "openai-agent" -a "prod"find-generic-password for prod reports the item is missingNone
8 — RenameDelete staging; re-add the same value under account prodRetrieval under prod succeedsNone

Do not compress stages 3–5 on a Friday afternoon. If you cannot watch the rollback window, delay stage 6 to the next business day.

Rotate Immediately on These Triggers

  • A teammate with key access leaves the project.
  • The key appears in a log line, error, screenshot or commit.
  • The provider flags unusual usage on the key.
  • You rebuild the hosted Mac image or re-provision the VM.

Also rotate on a schedule — every 90 days is a reasonable floor. Use a launchd calendar reminder so the deadline never drifts.

Redact Secret Values From Logs

Your agent will log metadata. Make sure the secret is not one of the fields.

What belongs in a log line:

2026-11-10T14:32:01Z job=openai-agent account=prod status=200 tokens_in=1240 tokens_out=380 cost_usd=0.00052

What must never appear:

# BAD — key value is visible
Authorization: Bearer sk-proj-abc123...
OPENAI_API_KEY=sk-proj-abc123...

Retrieve the key into a local variable, use it only in the HTTP header, and keep it out of loggers. In Python, silence noisy HTTP debug with logging.getLogger("urllib3").setLevel(logging.WARNING) so request headers are not echoed.

Add a log-scan test to the pipeline: match every line against your key prefix (for example sk-proj-[A-Za-z0-9]{40,}). If the pattern ever hits, fail the job and fix the logging path before the next rotation.

Schedule a launchd Reminder

Drop a lightweight reminder into ~/Library/LaunchAgents/. Apple's launchd Creating Jobs guide covers StartCalendarInterval; when it is an array of dicts, each dict fires independently.

<!-- com.example.key-rotation-reminder.plist -->
<plist version="1.0"><dict>
  <key>Label</key><string>com.example.key-rotation-reminder</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/bin/osascript</string>
    <string>-e</string>
    <string>display notification "90-day API key rotation due" with title "Agent maintenance"</string>
  </array>
  <key>StartCalendarInterval</key>
  <array>
    <dict><key>Hour</key><integer>9</integer><key>Minute</key><integer>0</integer><key>Day</key><integer>1</integer><key>Month</key><integer>1</integer></dict>
    <dict><key>Hour</key><integer>9</integer><key>Minute</key><integer>0</integer><key>Day</key><integer>1</integer><key>Month</key><integer>4</integer></dict>
    <dict><key>Hour</key><integer>9</integer><key>Minute</key><integer>0</integer><key>Day</key><integer>1</integer><key>Month</key><integer>7</integer></dict>
    <dict><key>Hour</key><integer>9</integer><key>Minute</key><integer>0</integer><key>Day</key><integer>1</integer><key>Month</key><integer>10</integer></dict>
  </array>
</dict></plist>

Load it with launchctl load ~/Library/LaunchAgents/com.example.key-rotation-reminder.plist. The notification is a prompt to run the checklist above by hand — automatic rotation without stages 3–5 skips the human smoke test and is the main way rotations silently break production.

Migrate an Existing .env-Based Agent

  1. Add the current key to the Keychain with security add-generic-password -w (prompted value).
  2. Change the agent to read it with security find-generic-password … -w into a local variable — not os.environ, not a temp file.
  3. Delete the .env and remove the variable from any shell profile, Dockerfile or systemd unit.
  4. Run one manual job on the hosted Mac and confirm the agent authenticates.
  5. Only after that run succeeds, remove the old value from any CI secret manager you previously synced it to.

Once the agent reads from the Keychain, the rotation workflow above replaces every "edit .env and restart" scramble.

Request a Mac hosting configuration or browse plan options.

Related reading


Subscribe for Figma design and website publishing guides.


Figment.so

Contact

Twitter

Website pricing

Compute index

About

Privacy

Terms