Get started
MarkdownQuickstart
Create a tenant, seal an OpenAI key and call the API through Seal from your app. About ten minutes, free.
You need Linux or macOS, an OpenAI API key, and Python, Node, Go or Rust. The free Developer plan covers it.
Create your tenant#
Sign up
Sign in at console.seal.zone and create a workspace.
Name the tenant and choose an admin key
Click New tenant. Pick a tenant id like
acme. It can't change later.Your admin key signs every change. Seal never holds it.
- Passkey. The easiest choice.
- Key file.
admin.key, for signing from scripts with--key-file.
Choose who runs the enclave and how long risky changes wait
Pick Seal runs it. For risky changes, None is fine for a trial. Lengthen it before real keys go in (why).
Click Review and sign and sign with your admin key.
Add a backup key
Lose your only admin key and nobody can change the tenant again. Add a second one under Admins.
Set up the CLI#
# with Python 3.9 or later$pip install sealzone# or with Rust$cargo install sealzone-cli$seal login$seal use acmeseal use picks your tenant and verifies its signed settings.
Grant an app#
An app is a name your blobs list. Here it proves who it is with an app key file.
$seal grant app checkout key --generate --out checkout.keyThe CLI opens the console for you to sign, or add --key-file admin.key. In the cloud, use your cloud's identity instead.
Seal your OpenAI key#
$seal secret --to https://api.openai.com/v1 --app checkout > openai.blobPaste your key at the hidden prompt. The CLI checks the enclave's attestation, then encrypts the key on your machine. The blob works only for checkout and only toward that URL. Store it anywhere. Sealing a secret lists the options.
Call OpenAI from your app#
Copy SEAL_TENANT from the console's Connect page or seal status.
$export SEAL_ENDPOINT=https://acme.enclave.seal.zone:8443$export SEAL_TENANT=acme@<root id>$export SEAL_APP_KEY="$(cat checkout.key)"$export OPENAI_API_BLOB="$(cat openai.blob)"Open a session. You get a local URL and a stand-in key that only this process can use.
# pip install sealzone openai
import os, seal
from openai import OpenAI
with seal.session(os.environ["OPENAI_API_BLOB"]) as s:
client = OpenAI(base_url=s.url, api_key=s.key)
reply = client.responses.create(model="gpt-5", input="Say hello")
print(reply.output_text)// npm install @sealzone/sdk openai
import { Client } from "@sealzone/sdk";
import OpenAI from "openai";
const seal = await Client.fromEnv();
const s = await seal.session(process.env.OPENAI_API_BLOB!, { kind: "http" });
try {
const openai = new OpenAI({ baseURL: s.url, apiKey: s.key });
const reply = await openai.responses.create({ model: "gpt-5", input: "Say hello" });
console.log(reply.output_text);
} finally {
await s.close();
}// go get seal.zone/go (needs cgo)
package main
import (
"context"
"fmt"
"io"
"net/http"
"os"
"strings"
seal "seal.zone/go"
)
func main() {
ctx := context.Background()
client, err := seal.FromEnv(ctx)
if err != nil {
panic(err)
}
s, err := client.Session(ctx, os.Getenv("OPENAI_API_BLOB"), seal.WithKind(seal.KindHTTP))
if err != nil {
panic(err)
}
defer s.Close(ctx)
body := strings.NewReader(`{"model": "gpt-5", "input": "Say hello"}`)
req, _ := http.NewRequestWithContext(ctx, "POST", s.URL()+"/responses", body)
req.Header.Set("Authorization", "Bearer "+s.Key())
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(string(out))
}// cargo add sealzone serde_json
// cargo add tokio --features full
// cargo add reqwest --features json
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let seal = seal::Client::from_env().await?;
let blob = std::env::var("OPENAI_API_BLOB")?;
let s = seal.session(&blob).http().await?;
let reply = reqwest::Client::new()
.post(format!("{}/responses", s.url()))
.bearer_auth(s.key())
.json(&serde_json::json!({ "model": "gpt-5", "input": "Say hello" }))
.send()
.await?
.text()
.await?;
println!("{reply}");
s.close().await?;
Ok(())
}The first call can take about a minute while your idle replica starts. Your code never touched the real key. The enclave added it on the way out and masked any copy in the response. Telemetry in the console shows each step.
Next#
- Key ideas: blobs, sessions, tenants and admins.
- Apps and identities: cloud identities and network rules.
- Using a blob: databases, long-running processes and errors.
- What an attacker gets: what root on your server can and can't do.