OpenShip Key Management: Platform Or Server in 2026?

Symptom: The key is not in your source code, but it was copied into a Docker image layer, build log, or client bundle.

Fastest fix: Put normal application secrets in an environment-scoped OpenShip secret store, keep only server-required infrastructure credentials on the target server, and test rotation before calling the setup safe.

This applies when your deployment has separate preview, test, and production environments, or when more than one person can publish releases.

Who should use this runbook

Use it if you are deploying your first model API key through OpenShip and want to avoid committing it to Git.

It is also for small teams that need to stop preview environments from using production credentials, and for release owners who must make rotation, audit, and recovery repeatable.

A key point comes first: OpenShip key management is not a choice between “platform good” and “server bad.” It is a responsibility split. The platform should normally own application-level secrets. The destination server should retain only credentials that must be managed by that machine or operating system.

Start with the leak path, not the storage preference

Consider this failure case: a developer removes MODEL_API_KEY from the source file, adds it to a local .env, and then uses it during a Docker build. The current file looks clean. The final image is not.

Docker documents that build arguments and environment variables are unsuitable for passing build secrets because they can persist in the resulting image. Temporary secret mounts are designed to expose a secret only during the required build instruction. Docker’s official build-secret guidance explains the difference.

Check all four locations:

  • Git history: Removing a key from the latest commit does not remove it from earlier commits. Repository-wide secret scanning should inspect the full history across branches. GitHub’s secret-scanning documentation describes this search scope.
  • Dockerfile and image layers: ARG, ENV, copied configuration files, package-manager credentials, and generated assets can preserve a value.
  • Build output: Debug commands, failed tests, dependency installers, and verbose shell tracing can print credentials.
  • Client bundles: Any variable intentionally exposed to browser code should be treated as public. A model API key must stay behind your server-side API.

Do not accept “the current source file contains no secret” as an incident review. Your review should inspect repository history, image history, build artifacts, deployment logs, and the compiled client package.

If a production key has appeared in any of those locations, revoke it first. Cleanup without revocation leaves the old credential usable.

First step: separate preview, test, and production

The next common failure is not an external attacker. It is a preview deployment calling the production database or spending against the production model account.

OpenShip’s current public documentation describes environment-scoped secrets and preview deployments. It also states that builds produce immutable, versioned artifacts and that production servers do not perform the build in the normal deployment flow. Those are useful design signals, but they are not a substitute for testing your specific deployment shape and version. The OpenShip Quickstart describes the basic deployment model.

Use separate names and values:

  • Preview: MODEL_API_KEY_PREVIEW, sandbox database, restricted quota.
  • Test: test model account, synthetic data, disposable callback endpoints.
  • Production: production model account, production database, approved callback domains.

Avoid copying a production variable set into a new environment and editing only one or two values. That creates silent drift. Instead, define the required variable names once, then assign values per environment.

Will OpenShip environment variables be written into the build image?

Not automatically in every deployment design, but they can be exposed if your application reads them during the build or if your Dockerfile copies a generated configuration file into the image. Treat build-time access and runtime access as different permissions. A server-side model key should normally be injected when the container starts, not baked into the artifact.

How should preview and production use different keys?

Create separate environment scopes and test with a deliberate marker. For example, use a restricted preview credential whose provider-side name clearly identifies the environment. Send one test request from preview and confirm the provider records the preview key, not the production key. Then inspect the running process or health endpoint without returning the secret itself.

Compare storage by responsibility

A server .env file is not inherently unsafe. It becomes unsafe when it is copied between machines, readable by every operator, included in backups without encryption, or treated as the team’s permanent source of truth.

A platform secret store is not automatically safe either. You still need to verify who can view, edit, deploy, export, and audit each value. The public OpenShip feature description currently lists a Secrets Vault, environment scope, encrypted storage, rotation without redeployment, and exportable audit logs. The feature description should be treated as a capability to verify in your installed version or cloud workspace, not as proof that your project has been configured securely. The OpenShip platform overview describes these advertised controls.

Secret type Preferred location Why Main failure to test
Model API key used by the application OpenShip environment secret Central scope, easier replacement, less server drift Preview or test reads the production value
Database password used by the application OpenShip environment secret or external vault Application-level access should follow the deployment environment Rotation updates storage but not the running process
SSH key used to reach a target server Deployment control plane or approved machine credential store It belongs to the deployment path, not the application image Too many developers can export the private key
Host-level backup credential Target server or external secret manager The operating system or backup job may require local access Server recovery cannot reacquire the credential
Short-lived provider token External vault or generated at job start Minimize lifetime and avoid long-term copies Token remains valid after the job ends
High-sensitivity production credential Layered design with external vault Separates application delivery from highest-value secrets One platform administrator can read everything

The general rule is simple: store application secrets where the application environment is controlled; store machine credentials where the machine needs them; use an external Secrets Vault when the blast radius is too large for either location.

Second step: inspect the platform and server boundary

Before migrating values, write down where each secret is created, stored, injected, consumed, rotated, revoked, and recovered.

For OpenShip, verify the current interface for:

  • Environment scope.
  • Project and service scope.
  • Team role boundaries.
  • Secret visibility after creation.
  • Deployment and restart behavior.
  • Audit event detail.
  • Export and backup behavior.
  • Cloud, self-hosted, and hybrid differences.

The current architecture documentation distinguishes cloud-owned project data from a self-hosted gateway model. In that design, cloud project records, deployments, domains, environment values, and logs can live with the cloud control plane, while a local instance acts as a gateway. That distinction matters during recovery because restoring a local dashboard may not restore cloud-owned project data. The OpenShip architecture documentation explains this ownership model.

For a self-hosted installation, also protect the platform’s own data volume and access path. The installation documentation shows a persistent data volume for the self-hosted deployment. Backing up the application database without protecting the encryption material or administrator recovery path may produce an incomplete restore. The OpenShip installation documentation describes the self-hosted data layout.

What is the difference between a server .env file and a platform secret?

A server .env file is usually a local configuration artifact. Its protection depends on Linux permissions, disk encryption, backup handling, shell access, and operator discipline. A platform secret is managed through a control plane and can be attached to a project or environment, but its protection depends on the platform’s role model, audit trail, and recovery design.

The practical difference is not the file extension. It is whether you can prove scope, access, change history, and recovery.

Third step: assign permissions by action

Do not grant “secret access” as one broad team capability. Separate the actions:

  • Developer: deploy to preview, inspect non-sensitive configuration, run tests with restricted credentials.
  • Release operator: promote or deploy approved artifacts, trigger rotation workflows, verify health checks.
  • Administrator: change team membership, configure environments, approve production access, manage recovery.
  • Auditor: read event history and export evidence without viewing secret values.
  • Automation token: perform only the deployment or rotation actions it needs.

OpenShip’s API documentation describes bearer credentials, while its MCP documentation describes scoped tokens and permission checks for agent actions. That is relevant if an AI agent can deploy or manage infrastructure: give it a narrow, read-only, or project-scoped token rather than a personal administrator credential. The OpenShip API reference provides the relevant access details.

Do not assume that a role label tells you enough. Test the actual permissions in a non-production project:

  1. Log in as a developer.
  2. Attempt to view the secret value.
  3. Attempt to edit the value.
  4. Attempt to deploy preview.
  5. Attempt to deploy production.
  6. Check whether each action creates an audit event.
  7. Repeat with a release operator and administrator account.

The expected result is not merely “access denied.” You need a useful audit record showing who attempted the action, what resource was targeted, and whether the operation succeeded.

Use this decision table before deployment

Condition Platform secret Server .env External Secrets Vault
Application reads the value at runtime Yes Sometimes Yes
Preview and production need different values Strong fit Manual and drift-prone Strong fit
The operating system needs the value before the app starts Limited fit Strong fit Strong fit
Multiple teams need different permissions Verify platform roles Difficult to enforce locally Strong fit
You need independent audit evidence Verify current plan and version Usually weak Strong fit
You need recovery after rebuilding the server Must back up platform metadata and recovery path Must back up securely Usually strongest
The credential is short-lived Good if injection is supported Poor unless automated Strongest
The key has a large production blast radius Add an external vault Avoid as the only store Preferred

OpenShip’s public pricing matrix distinguishes role and audit capabilities by deployment tier. Because availability can vary between cloud, hybrid, and self-hosted forms, verify the exact workspace and installation version before promising a compliance workflow. The OpenShip pricing matrix is the starting point for that verification.

Fourth step: rotate without breaking requests

A safe rotation is a procedure, not a successful “Save” message.

Use this sequence:

  1. Create a new provider credential with the smallest required scope.
  2. Keep the old credential active.
  3. Store the new value in the correct environment scope.
  4. Trigger the platform’s secret refresh or restart behavior.
  5. Send a real application request.
  6. Confirm the provider sees the new credential.
  7. Monitor error rates, retries, and quota usage.
  8. Revoke the old credential.
  9. Send another request to confirm the old value is no longer accepted.
  10. Record the operator, timestamp, environment, validation result, and rollback decision.

There are three practical rotation patterns:

  • Direct replacement: overwrite the old value, then restart or refresh the service. This is simple but creates a failure window.
  • Parallel credentials: introduce the new value while the old one remains valid, verify traffic, then revoke the old one. This is safer for production.
  • External lookup: let the application obtain the active value from a Secrets Vault or identity-based provider. This reduces manual copying but adds a dependency that must be tested during an outage.

The rotation standard should be: new requests use the new key, the old key can be revoked, and the application can return to a known-good state if validation fails. OWASP’s Secrets Management Cheat Sheet recommends least privilege, controlled rotation, revocation, lifecycle metadata, and avoiding plaintext exposure in logs.

Does changing a model API key require a new deployment?

Not always. OpenShip currently describes secret rotation without redeploying, but your application still needs to receive the new value. A process that reads the key only at startup may require a restart. A process that fetches the value dynamically may not. Test the actual behavior: change the key, send a request, inspect provider-side usage, and confirm whether the running process changed without a new image.

Fifth step: make recovery part of the design

A disaster recovery test should answer three separate questions:

  • Can you restore application data?
  • Can you restore platform configuration and environment mapping?
  • Can an authorized person reacquire or reauthorize every required secret?

Do not place production keys in an unencrypted backup archive simply because the archive is “off the server.” Back up metadata, secret identifiers, environment names, ownership, rotation instructions, and recovery contacts. Store the actual production value in an approved encrypted system, or ensure the external provider can issue a replacement during recovery.

For a self-hosted OpenShip installation, test a new server rather than restoring over the original one. Reinstall the control plane, restore the required data, reconnect the deployment target, and verify that the application can start without manually searching old laptops or private chat messages.

Your recovery runbook should specify:

  • The person allowed to authorize production recovery.
  • The person allowed to operate the restored deployment.
  • The location of encrypted backups.
  • The process for revoking credentials from the failed host.
  • The order for restoring databases, secret access, application containers, and DNS.
  • The evidence required before production traffic is enabled.

Deployment gate: use this checklist

  • [ ] Search Git history and all branches for model keys, database passwords, SSH keys, and tokens.
  • [ ] Inspect Dockerfile instructions, image history, generated files, and build logs.
  • [ ] Confirm browser bundles contain no server-side model or database credentials.
  • [ ] Create separate preview, test, and production secret scopes.
  • [ ] Give preview credentials restricted provider and database permissions.
  • [ ] Record which values must exist on the target server before the application starts.
  • [ ] Test developer, release, administrator, auditor, and automation permissions.
  • [ ] Confirm secret access and modification events are recorded.
  • [ ] Perform a parallel-key rotation in a non-production environment.
  • [ ] Verify a live request uses the new credential.
  • [ ] Revoke the old credential and confirm failure behavior.
  • [ ] Restore the control plane or server on a clean machine.
  • [ ] Verify recovery without reading production keys from plaintext files.
  • [ ] Document who can reauthorize production access.
  • [ ] Repeat the test after changing the OpenShip deployment shape or version.

The recommendation for a layered setup

For a small AI SaaS, put model API keys, webhook signing secrets, database passwords, and application encryption values in environment-scoped OpenShip storage, provided your permission and audit tests pass.

Keep host-level credentials on the target server only when the operating system, backup agent, or deployment process genuinely requires them. Do not copy those credentials into application images or share one personal SSH key across the team.

For high-sensitivity production systems, use a layered design: OpenShip handles environment delivery, while an external Secrets Vault controls the highest-value credentials, rotation authority, and recovery evidence. This costs more operational effort, but it prevents one dashboard role or one compromised server from becoming the master key to every environment.

Your current setup may work with a server .env, but it usually creates three long-term weaknesses: manual copying between environments, weak visibility into who changed a value, and fragile recovery after a server rebuild. Moving every secret into a platform without testing roles can create a different weakness: centralized access with no proven separation. The better choice is the one you can rotate, audit, revoke, and restore under pressure.

If your deployment also depends on a continuously available remote Mac build environment, review the relevant Mac configuration options and support guidance. The important check is not only whether the build machine is online, but whether personal credentials are being shared and whether the build environment has separate access from production secrets. For a team that needs a temporary or remote build environment, contact Macstripe after you have completed the permission and recovery checks above.