Skip to main content

Overview

Tinfoil’s own stack is fully open source, which is how anyone can audit what runs inside our enclaves. But your application doesn’t need to be. When an enclave boots, the hardware fingerprints everything inside it and signs that fingerprint with the chip manufacturer’s key. On every connection, the client can verify that the code actually running is exactly the code that was committed to. If you’re open source, anyone can inspect that code themselves. If you’re not, you can choose to have a third-party auditor review it and certify that a given image hash meets their requirements. The fingerprint is public and permanently committed to, even if the source code is not available. Attestation is performed against the pinned SHA256 digest in your configuration, so verification works the same way whether your image is public or private. If your image isn’t public, you can have a third-party auditor review it and certify that a given hash meets their requirements; the fingerprint stays public and permanently committed to either way. A Tinfoil Container has two artifacts, and they follow different visibility rules:
  • The config repo must be public. Tinfoil measures tinfoil-config.yml at the tag you deploy and publishes the measurement to the Sigstore transparency log. Clients verify against that log, so the repo’s contents need to be inspectable.
  • The Docker image can be private. Your config pins the image by SHA256 digest, and the enclave’s attestation commits to that exact digest. Whether the image bytes are publicly pullable doesn’t affect verifiability; the digest already pins them.
The rest of this page covers authentication for private image registries.

Registry authentication

Private registry support is included with every container subscription. If your Docker images are stored in a private registry, you need to add registry credentials so Tinfoil can pull them during deployment. Supported registries are GitHub Container Registry (ghcr.io), Google Artifact Registry (*-docker.pkg.dev) / Container Registry (gcr.io), Docker Hub (docker.io), Amazon Elastic Container Registry (private ECR), and any other registry that speaks the Docker Registry V2 API over public HTTPS, such as Harbor.

Adding credentials

  1. Go to the Registry Credentials tab in the Containers section of the dashboard
  2. Click Configure for your registry type
  3. Enter your authentication credentials
  4. Click Save
Credentials are stored encrypted and scoped to your organization. Once configured, any container in your org can pull images from that registry.

Debug instances

A production instance receives credentials only for the registries its images come from. A debug instance receives credentials for every registry configured in your org, so you can switch images with tindbg boot. Anyone with SSH access to a debug instance can read those credentials, so use read-only tokens. A registry added after the debug instance was created is not available inside it until you update the instance.

GitHub Container Registry (ghcr.io)

Tinfoil needs a personal access token with read access to your packages.

Creating a classic PAT

Classic PATs are the most reliable option for ghcr.io because they work with all packages, including those not linked to a specific repository. See GitHub’s guide to creating a classic PAT for full details.
  1. Go to github.com/settings/tokens
  2. Click Generate new token > Generate new token (classic)
  3. Give it a descriptive name (e.g. “Tinfoil registry read-only”)
  4. Set an expiration (90 days is a reasonable default)
  5. Under scopes, check only read:packages
  6. Click Generate token and copy it immediately
If your GitHub organization uses SAML SSO, you must authorize the token for your org after creating it. Go to github.com/settings/tokens, find the token, click Configure SSO, then click Authorize next to your organization name. Without this step, pulls from your org’s packages will fail with a 403. See GitHub’s SSO authorization guide.

What to enter in the dashboard

  • Username: Your GitHub username
  • Token: The personal access token you just created
GitHub’s fine-grained personal access tokens do not support GitHub Packages (including ghcr.io). You must use a classic PAT for pulling container images.

Google Artifact Registry / Container Registry

Tinfoil supports Google Artifact Registry images at *-docker.pkg.dev URLs and gcr.io URLs backed by Artifact Registry. Tinfoil needs a service account JSON key with read access to your container images. See Google’s service account creation guide and Artifact Registry authentication docs for full details.

Creating a service account

  1. Open the Google Cloud Console
  2. Select your project
  3. Go to IAM & Admin > Service Accounts
  4. Click Create Service Account
  5. Name it (e.g. “tinfoil-registry-reader”) and click Create and Continue
  6. Grant Artifact Registry Reader (roles/artifactregistry.reader):
    • At the project level for project-wide access.
    • On a specific Artifact Registry repository to limit access to that repository.
  7. Click Done

Creating and downloading the JSON key

See Google’s guide to creating service account keys for full details.
  1. In the Service Accounts list, click on the service account you just created
  2. Go to the Keys tab
  3. Click Add Key > Create new key
  4. Select JSON and click Create
  5. A .json file will download. Store it securely; it can only be downloaded once, and if you lose it you must create a new key.

What to enter in the dashboard

  • Service Account Key: Paste the entire contents of the downloaded JSON key file
Service account JSON keys do not expire by default. However, your organization may enforce key expiration via the constraints/iam.serviceAccountKeyExpiryHours organization policy. If this policy is set, keys will stop working after the configured duration and you’ll need to create a new one.

Docker Hub

Tinfoil needs a personal access token with read permissions. See Docker’s access token documentation for full details.

Creating an access token

  1. Log in to Docker Home
  2. Click your profile avatar > Account settings
  3. Go to Personal access tokens in the left sidebar
  4. Click Generate new token
  5. Enter a description (e.g. “Tinfoil registry read”)
  6. Set the permission to Read
  7. Set an expiration date
  8. Click Generate and copy the token immediately

What to enter in the dashboard

  • Username: Your Docker Hub username
  • Token: The access token you just created
Docker Hub access tokens support an expiration date set at creation time. The expiration cannot be changed after creation. If you need a different expiration, create a new token. If your account has two-factor authentication enabled, PATs are required for CLI access (passwords will not work).

Amazon Elastic Container Registry

Tinfoil supports one private ECR registry per organization, identified by its hostname (<account-id>.dkr.ecr.<region>.amazonaws.com). The region is derived from the hostname. Commercial, GovCloud, and China (amazonaws.com.cn) partitions are supported; Public ECR (public.ecr.aws) is a public registry and needs no credentials. ECR issues short-lived registry passwords rather than long-lived tokens. Tinfoil stores an IAM access key pair and exchanges it for a fresh password whenever an enclave needs to pull, including after reboots. The access key pair never leaves Tinfoil; enclaves only ever receive the short-lived password.

Creating an IAM user and access key

See the ECR authentication docs and IAM policy examples for ECR for full details.
  1. In the AWS console, go to IAM > Users and create a dedicated user (e.g. tinfoil-ecr-pull). Do not use root credentials or an administrator user.
  2. Attach a policy that grants ecr:GetAuthorizationToken on *, plus ecr:BatchGetImage, ecr:GetDownloadUrlForLayer, and ecr:BatchCheckLayerAvailability on the repository ARNs Tinfoil should be able to pull. Scope the repository permissions as narrowly as you can; an ECR password inherits all of the IAM user’s ECR permissions, not just the configured hostname.
  3. Under Security credentials, create an access key for programmatic use and copy both the access key ID and the secret access key.
If the repositories live in a different AWS account than the IAM user, the target account also needs a repository policy that allows that principal to pull.

What to enter in the dashboard

  • Registry hostname: <account-id>.dkr.ecr.<region>.amazonaws.com, with no scheme, port, or repository path
  • Access key ID: The IAM user’s access key ID
  • Secret access key: The corresponding secret
Saving the credentials performs a live exchange with ECR, so an IAM user without ecr:GetAuthorizationToken is rejected immediately. Repository pull permissions are checked separately when you deploy an image.
Temporary credentials (access key IDs starting with ASIA), SSO sessions, and assume-role chains are not supported. Use a long-lived access key for a dedicated IAM user.

Referencing the image

Reference the image by its full ECR path in tinfoil-config.yml. The hostname must match the one you saved exactly.
Rotate the key pair by saving a new one for the same hostname; running enclaves pick up the new keys on their next pull. After changing the hostname or deleting the connection, update any instance that uses it.

Harbor and other registries

Harbor and custom registry support are in beta.
For a registry that is not one of the providers above, configure a custom registry connection with the registry’s hostname, a username, and a secret. This uses standard Docker Registry V2 authentication and works with Harbor, Quay, and any other compatible registry that meets these requirements:
  • Reachable over public HTTPS on port 443, with a certificate trusted by public CAs
  • Hostname only: no scheme, explicit port, path, or IP literal
  • If the registry uses bearer-token authentication, its token service must be on the same hostname
Private-network registries, self-signed or private-CA certificates, and plain HTTP are not supported. Registries whose token service lives on a different hostname, such as GitLab.com (registry.gitlab.com authenticates via gitlab.com), are also not supported. One custom registry hostname is supported per organization.

Harbor robot accounts

Harbor’s recommended way to grant pull-only access is a project robot account. See Harbor’s robot account docs for full details.
  1. In Harbor, open the project that contains your images
  2. Go to Robot Accounts and click New Robot Account
  3. Give it a name and set an expiration
  4. Under permissions, grant Pull Repository only
  5. Click Add and copy the full robot name (e.g. robot$myproject+tinfoil) and the generated secret
Use a system-level robot account only if you need one connection to span multiple projects, and limit its grants accordingly.

What to enter in the dashboard

  • Registry hostname: e.g. harbor.example.com
  • Username: The full robot account name, or the username for another registry
  • Robot secret / access token: The secret Harbor generated, or a pull-only token for another registry
Saving checks that the credentials can authenticate against the registry. Repository-level pull permission is checked when you deploy an image, so a robot account without access to a particular project will pass validation but fail at deploy time with a permissions error.

Referencing the image

Reference the image by its full registry path in tinfoil-config.yml. The hostname must match the one you saved exactly; harbor.example.com and registry.example.com are different connections, and a port suffix does not match a hostname saved without one.
After rotating the secret or changing the hostname, update any instance that uses the connection. Deleting the connection does not revoke the robot account; revoke it in Harbor when you need to cut off access.

Troubleshooting

”Requires authentication” error during deployment

This means the container image is in a private registry but no credentials are configured for that registry type. Fix: Go to the Registry Credentials tab and configure credentials for the registry shown in the error message. The dashboard includes a direct link to the tab in the error.

”Expired or been revoked” error during deployment

This means credentials are configured but the registry rejected them. The token may have expired, been revoked, or lost access. Fix: Go to the Registry Credentials tab and update your credentials with a fresh token. After updating, the expired credentials banner will clear automatically. Common causes:
  • GitHub PAT expired. Classic PATs can be set with an expiration date. Create a new one and update it in the dashboard.
  • GitHub PAT not authorized for SSO. If your org enabled SAML SSO after you created the token, you need to re-authorize it.
  • Google service account key disabled or deleted. Check the service account in Google Cloud Console. Create a new key if needed.
  • Google IAM permissions changed. Verify the service account still has roles/artifactregistry.reader.
  • Docker Hub token expired or revoked. Docker Hub tokens have mandatory expiration dates. Create a new access token in Docker Hub settings.
  • ECR access key deactivated or deleted. Check the IAM user’s access keys in the AWS console and save a new key pair for the same hostname.
  • ECR IAM policy missing repository permissions. Saving credentials only proves ecr:GetAuthorizationToken works. A pull failure on a specific image usually means the policy lacks ecr:BatchGetImage or ecr:GetDownloadUrlForLayer on that repository, or a cross-account repository policy is missing.
  • Harbor robot account expired or lacks project access. Robot accounts have an expiration you set at creation. A robot that authenticates but cannot pull a specific image is missing Pull Repository permission on that project.

”Credentials were rejected for this image” on a custom registry

This means your custom registry credentials are valid but the registry refused to let them pull the specific image. The robot account or token lacks pull permission on that repository or project. Grant it in the registry; no change is needed on the Tinfoil side.

Custom registry validation fails on save

Saving a custom registry connection fails when Tinfoil cannot reach the registry over public HTTPS on port 443, when the certificate is not trusted by public CAs, or when the registry’s bearer-token service lives on a different hostname than the registry itself. Private-network registries and registries behind a corporate CA cannot be used.

Expired credentials banner

When Tinfoil detects that your registry credentials have been rejected during a deployment attempt, an amber banner appears on the Active tab. This banner persists until you update the credentials in the Registry Credentials tab.

Using the CLI

The Tinfoil CLI sets the same per-registry credentials, which is convenient when rotating tokens from a script:
Pass --key-file - to read the GCR key from stdin instead of disk. Once credentials are stored, any container in the org can pull images from that registry. ECR and custom registry connections are configured in the dashboard or through the Admin API.