Skip to main content

What automatic unlock means

Automatic unlock delivers the same volume key on every authorized, non-debug enclave boot. Your private keyserver verifies the enclave, reads the key from your secret store, and releases it directly to the enclave. The guest must unlock and mount the disk before the workload starts. You do not send a decrypt command after each Deploy. This requires setup. A disk attachment, a named mount, or a saved CLI profile alone does not enable automatic unlock or prove that the filesystem is unlocked. Without an unlocked volume mounted at the application’s configured path, writes to the enclave’s ephemeral filesystem do not survive Stop followed by Deploy or replacement during Update. The CLI provisioning workflow uses customer-owned AWS Secrets Manager. It is not a Tinfoil-managed key service. You operate the private keyserver, its TLS endpoint, and its release policy. There is no shortcut that uploads the volume key to Tinfoil’s secret store.
An existing volume needs its original key. Never generate a new key to enable automatic unlock for an existing disk. Changing the secret value does not re-encrypt its contents; see volume-key rotation.

Prepare customer infrastructure

Before provisioning a key, arrange:
  • A customer AWS account, region, and secret-name prefix, with durable retention and a recovery plan for the original key. Do not enable automatic rotation for volume secrets.
  • A reachable private keyserver with a publicly trusted TLS certificate. Its /challenge and /fetch endpoints must be served directly, without redirects. Keep it available for unattended boots.
  • A keyserver configured with the AWS backend, the same region and prefix as the CLI profile, and a customer-controlled policy loaded at keyserver startup.
  • The exact config repository, intended release tag, and instance domain. The policy must pin all three; do not guess a domain or remove a pin to make a boot succeed.
  • An application image and a declared named volume mount in tinfoil-config.yml. Preparing unlock configuration does not replace your application image or copy ephemeral files to disk.

Separate provisioning from release permissions

Use separate customer identities for setup and the running keyserver: Existing-key setup needs Describe/Get access, not Create/Tag. Reading an existing secret encrypted with a customer-managed KMS key also requires kms:Decrypt. New secrets use AWS’s default Secrets Manager encryption key; the helper does not offer custom KMS key selection. The customer grants permissions. Local preflight is not an AWS write-permission dry run: Create/Tag authorization remains unproven until the actual CreateSecret call succeeds. CLI configuration does not create IAM roles, grant access, or deploy the keyserver. Scope permissions to the intended secrets and KMS key rather than granting account-wide secret administration. The CLI uses the AWS SDK to create a new secret, not a plaintext shell command. It does not overwrite an existing secret with an update/upsert operation. Keep key values out of command arguments, logs, Git, and support messages. AWS documents the permission requirements for CreateSecret, DescribeSecret, and GetSecretValue, and the exposure risks of plaintext command arguments.

Local profiles and key custody

A project storage profile is scoped to the normalized controlplane URL, authenticated organization ID, and canonical config repository. A per-volume receipt also binds the volume UUID. Switching organizations, controlplanes, or repositories does not reuse another scope’s profile. Setup requires an organization login, not a personal context. Profiles and receipts contain metadata, not volume keys or AWS credentials. An AWS profile name is only a reference to your AWS credential configuration. The files live in a separate storage/ directory beside the effective CLI config file; the directory uses mode 0700 and JSON files use mode 0600. Login and logout do not rewrite this storage metadata. Only new auto-unlock volume creation generates a random 64-byte key. The key is stored in AWS Secrets Manager as a JSON string with exactly one field, value, containing the standard base64 encoding. Plain volume creation does not generate a key. For an existing disk, supply a reference to the original key already stored in that format under the configured AWS prefix. If the original key is held elsewhere, import those exact bytes through your customer-controlled secret-management process first. Do not print them or put them in shell arguments. Selecting an existing secret validates its format and identity, not whether it can decrypt the disk. Rotation must be disabled.

Configure once per project

These helpers require a CLI build with project storage configure, volume auto-unlock, and volume create --auto-unlock, in addition to the lifecycle prerequisites. The published v0.18.9 CLI does not include them. Until a release contains them, use a build supplied for the Containers rollout. Confirm tinfoil project storage configure --help and tinfoil volume auto-unlock configure --help show those exact commands, and that tinfoil volume create --help lists --auto-unlock. With an organization admin login, save the provider metadata:
Replace the example repository, endpoint, region, prefix, and AWS profile with your own. An explicit owner/repo works before the first instance exists; an existing project ID also works. The CLI verifies organization identity and repository access without creating an instance or project. Repeating identical setup is safe; different saved custody metadata is refused. With --output json, setup reports configuration: PROFILE_SAVED and policy: not_applied; neither field means AWS access or remote approval was verified. The helper requires an HTTPS origin, without a path, credentials, query, or fragment. Configure your keyserver with BACKEND=aws, the same AWS_REGION, and AWS_SECRETS_PREFIX matching --aws-prefix. Use --aws-prefix="" explicitly for no prefix. The CLI and keyserver must access the same customer AWS account and region; policy resolves secrets by name under that prefix, not by a cross-account ARN. Omit --aws-profile to use the standard AWS credential chain. Vault and file provisioning are not implemented by this helper. You can save an exact domain with --domain; otherwise supply it during volume setup. Missing required values prompt only in an interactive terminal. Scripts must supply them.

Prepare a volume

Use your actual local tinfoil-config.yml, retaining its application image and other settings. The example assumes a top-level volume named data already exists and is mounted by your application. --mount data selects that name, not a filesystem path. Choose a new config release tag to publish after reviewing the generated config; v1.2.3 below is an example, not a guest version. Supply the exact known instance domain (or a verified custom domain you will use), not a guessed hostname. The helper’s --domain pins policy; it does not configure DNS or assign a domain to an instance.

New disk: generate the key once

This allocates a new disk, generates its key once, stores it in your AWS account, and prepares local artifacts. It does not attach, deploy, or unlock the disk. Keep the returned volume UUID for later attachment and recovery. With the example prefix, the AWS secret name is tinfoil/volumes/<UUID>/key; the generated private reference is VOLUME_<UUID_WITH_UNDERSCORES>_KEY.

Existing disk: select only the original key

Do not run the new-disk command for an existing volume. Use its UUID and original secret:
--existing-secret is a name or full ARN, never the raw or base64-encoded 64-byte key. Do not paste key bytes into command arguments: shell history and process arguments can expose them before any CLI validation. The reference is required even when local metadata is missing. The CLI rejects recognizable raw-key encodings before network requests or metadata writes; this cannot undo exposure in shell history or process arguments. This path reads the original secret; it does not generate or rotate a key. The selected secret must be under the configured prefix. An ARN is resolved to its actual name before the policy path is derived. An imported secret must belong to this disk and storage scope. Do not reuse one tagged for another volume or change its provenance tags to bypass a mismatch. Format validation alone cannot establish that an untagged imported key is the original key for the disk.

Review the artifacts

The helper adds a missing keyserver-url and the selected mount’s key-secret, retaining an existing disk’s declared secret reference. It preserves other config fields and comments and refuses conflicting values. The policy pins the repository, tag, and domain, and maps the private reference to the AWS secret’s path and value field. Key bytes are not in either file. Pass --policy-file policy.yml to prepare an additive copy of an existing policy. Without that input, prepared-policy.yml is a fragment for manual review and merging, not a replacement for the keyserver’s full policy. Include mappings for all private secrets the release requests, not only the volume key. Setting keyserver-url selects private delivery for all declared container, model, and volume secrets in a non-debug instance. This helper provisions only the selected volume key. Store the other required values in your customer secret store and map them in the reviewed policy; missing values fail boot rather than falling back to Tinfoil-managed secrets. Input and output paths must differ, output parent directories must exist, and new-volume outputs must not already exist. Existing-volume setup can reuse identical outputs but refuses to overwrite different contents. Choose fresh output filenames when preparing a new release.

Keep approval explicit

The CLI prepares local configuration and policy artifacts. It does not remotely approve a release, install or reload policy, deploy a keyserver, or observe a guest filesystem unlock. Adding keyserver-url or volumes[].key-secret changes measured configuration. Review the config, publish a new measured release, and authorize that exact repository, tag, and domain on your keyserver before Deploy. Editing local YAML does not change an already published release. Review and install the policy through your own deployment process, then restart the keyserver so it loads the policy at startup. Propose the prepared config, then review and merge the returned pull request:
Only after merging, publish the exact tag used in the policy:
Wait for both release workflow phases and a published release for that tag; a queued workflow or a Git tag alone is not deployable. Independently install and load the reviewed policy on your keyserver. Then use the normal create/attach/deploy workflow with the returned disk UUID, selected mount, and exact approved repository, tag, and domain. The reference keyserver permits only one workload entry per repository/tag pair, with one exact domain. Merge new secret mappings into that entry only when its domain also matches. Do not add duplicate repository/tag entries for different domains or broaden an existing policy. Different instance domains need distinct released config tags or independently operated keyservers. For instances switching from managed secrets, explicitly clear their saved managed-secret selection. Never add a volume key to Tinfoil-managed secrets to satisfy a validation failure.

Authorize another release without changing the volume key

Reuse the existing volume UUID and original secret ARN when preparing another application release. First edit ./tinfoil-config.yml to contain the intended new release’s changes, including its intended image. Preserve keyserver-url, the selected mount’s name and key-secret, and the application’s persistent mount mapping. Merely assigning a new tag to an unchanged v1 config does not update the application image. Use a trusted local copy of the currently installed full keyserver policy as ./installed-policy-v1.yml. In this example, it contains the existing release’s approval, and v2.0.0 is the new config release tag you intend to publish:
These output paths are distinct from the inputs and the previous release’s outputs. The CLI reads the original secret and retains its reference, AWS path, ARN, and version. It does not create or rotate a secret, allocate another disk, or reformat the volume. The candidate policy retains v1 and adds the exact v2 repository/tag/domain approval. An already matching entry is reused. Otherwise, the CLI first tries volume-<UUID>; when that name is occupied, it uses a deterministic suffix containing the full SHA-256 hash of the repository/tag/domain tuple. A conflicting derived name is refused, never overwritten. The name is not the authorization boundary: the exact pins still apply. Repeating preparation with the same inputs produces byte-identical outputs without duplicate entries. A new approval maps only the selected volume key. Review and add mappings for any other private secrets the new release needs; they are not copied automatically from the old approval. The one-domain-per-repository/tag restriction still applies. Review the generated config and open its pull request:
After reviewing and merging that PR, publish the exact new tag:
Wait for both release workflows and the published release. Separately approve and install the reviewed merged ./prepared-policy-v2.yml through your keyserver deployment process, then restart the keyserver to load it. Only then Update the instance to the new tag, retaining the same disk and original key. The CLI neither installs the policy nor verifies that it was loaded; CONFIGURED_LOCAL is not remote approval or observed unlock. Adding v2 does not revoke v1. The old release remains authorized until you explicitly remove its policy entry and reload/restart the keyserver. Retain that approval through the rollback window and while any instance may still need to boot or Deploy the old release. Retiring an approval is a separate operator decision, not an automatic part of preparing v2. Do not delete or rotate the volume key when retiring an approval.

What each phase proves

Status reads local evidence, not guest unlock state. Its configuration field can be:
  • CONFIGURED_LOCAL: the saved metadata and prepared artifact hashes agree.
  • INCOMPLETE: setup stopped before both artifacts were recorded; inspect the recovery phase.
  • STALE: an artifact is missing or changed, or local metadata disagrees.
  • UNKNOWN: this scope has no profile or receipt; it does not mean the disk is locked or its key is lost.
The receipt’s phase records allocated, secret_create_attempted, verifying_existing_secret, secret_stored, or prepared. These are setup checkpoints, not remote deployment or unlock states. Failed secret verification marks reconfiguration incomplete. Artifact conflicts preserve the prior receipt; they do not confirm that the new release has been configured successfully. The JSON unlock field is not_observed. Even CONFIGURED_LOCAL carries awaiting publication/policy load; unlock not observed. The CLI does not confirm remote publication or policy loading, so completing those steps does not turn this into an unlock check. Confirm the workload’s unlock result and that its durable-data path is backed by the expected unlocked filesystem before relying on writes. Keyserver HTTP health alone is not unlock proof.

Stop, Deploy, and recovery

Stop followed by Deploy retains the disk and its saved attachment. Reuse the actual disk, the intended measured application release, and the original key. Do not substitute an example image, create another disk, or generate a replacement key to recover data. Preserve a backup of the original key outside the enclave, and keep the authorized private keyserver available. For an Update, publish and authorize the new measured release while retaining the same disk and key. Updates with persistent volumes replace the running enclave and require downtime. If setup fails after allocation, retain the reported volume UUID, secret reference, and phase. Use the existing-disk command with that original reference and reviewed artifact flags; do not retry by creating a replacement disk. Recovery checks the original secret’s identity and version and does not generate another key. If the first key never reached AWS, setup remains incomplete and needs operator investigation. If allocation itself has an uncertain outcome, inspect tinfoil volume list before retrying. Debug mode is not automatic private unlock. It ignores keyserver-url and uses host-supplied managed secrets. Never expose a production volume key or use a production disk in debug mode; use disposable test disks and test secrets instead.

Manual unlock is an advanced alternative

Omit key-secret only if your application implements the supported runtime unlock flow. The application uses the volume’s control socket at /run/tinfoil/volumes/<mount-name>/control.sock; this is an application integration, not a generic CLI unlock command. Verify the enclave before delivering the original key, and wait for successful unlock before using the mounted path for durable writes. Boot-time private-secret unlock is supported with cvm-version 0.14.4 or later. The locked-volume write guard makes a locked mount’s placeholder read-only, but requires a newly published measured guest release and an explicit update of the approved guest release/measurement pin. That release has not been published; do not assume the 0.14.4 minimum includes the guard or rely on it for write protection. Installing the CLI does not publish a guest image, deploy it, or update runtime pins. The guard prevents writes from silently landing in ephemeral storage at a locked volume path. It does not make other application paths persistent. Files outside the unlocked mounted filesystem remain ephemeral across Stop and Deploy or replacement during Update.