diff --git a/content/docs/get-started/choose-your-stack.mdx b/content/docs/get-started/choose-your-stack.mdx index c333a60..e2c4963 100644 --- a/content/docs/get-started/choose-your-stack.mdx +++ b/content/docs/get-started/choose-your-stack.mdx @@ -84,13 +84,9 @@ A database breach defeats encryption at rest, because the database decrypts on r ## From development to production -| Stage | Credentials | Setup | -|---|---|---| -| Local development | Device-based | `stash init` per developer. No environment variables. | -| CI and staging | Machine | An application client key, plus `CS_*` environment variables. | -| Production | Machine | Same, with the client key held in your secret manager. | + -Device auth gives each developer their own identity, so local decryptions are attributable. There's no interactive device in CI, hence the switch. See [going to production](/stack/deploy/going-to-production). +Device auth gives each developer their own identity, so local decryptions are attributable. There is no interactive device profile in CI, hence the switch to explicit credentials. See [Deployment](/guides/deployment) for build-time availability, environment separation, and rollout gates. ## Still not sure diff --git a/content/docs/get-started/quickstart.mdx b/content/docs/get-started/quickstart.mdx index 38571ec..086fec5 100644 --- a/content/docs/get-started/quickstart.mdx +++ b/content/docs/get-started/quickstart.mdx @@ -182,4 +182,4 @@ You encrypted a field, stored it, queried it without decrypting, and read it bac - **Using an ORM or Supabase?** The [Drizzle](/stack/cipherstash/encryption/drizzle) and [Supabase](/integrations/supabase) integrations wrap your existing client so queries look normal. - **No app changes possible?** [CipherStash Proxy](/reference/proxy) sits in front of Postgres and does this transparently. - **Bind decryption to a user.** [Provable access control](/solutions/provable-access) ties a value to the identity that encrypted it. -- **Ready to deploy?** [Going to production](/stack/deploy/going-to-production) covers the switch from device auth to machine credentials. +- **Ready to deploy?** [Deployment](/guides/deployment) covers credential choices, environment promotion, and production rollout gates. diff --git a/content/docs/guides/deployment/index.mdx b/content/docs/guides/deployment/index.mdx index c2c6d21..e5ef18e 100644 --- a/content/docs/guides/deployment/index.mdx +++ b/content/docs/guides/deployment/index.mdx @@ -21,7 +21,9 @@ For the detailed dual-write, backfill, and cutover procedure for populated colum ## Credentials at build and runtime -An encryption client constructed at module load may authenticate when a build tool imports that module. In that case, `CS_WORKSPACE_CRN`, `CS_CLIENT_ID`, `CS_CLIENT_KEY`, and `CS_CLIENT_ACCESS_KEY` must be available during both the build and runtime phases. + + +An encryption client constructed at module load may authenticate when a build tool imports that module. In that case, the four `CS_*` variables shown above must be available during both the build and runtime phases. Do not let a local `stash auth login` session mask missing deployment credentials. Reproduce the production build in a clean environment that has only the secrets explicitly supplied by the deployment platform. diff --git a/content/docs/guides/migration/encrypt-existing-data.mdx b/content/docs/guides/migration/encrypt-existing-data.mdx index 7cc9975..69c6b0a 100644 --- a/content/docs/guides/migration/encrypt-existing-data.mdx +++ b/content/docs/guides/migration/encrypt-existing-data.mdx @@ -27,7 +27,7 @@ Do not start the backfill until dual-writes are running in every deployed writer - Install EQL and configure your encryption client. For Supabase, complete the [Quickstart](/integrations/supabase/quickstart) against a development table first. - Inventory every writer of the columns: services, jobs, Edge Functions, imports, seeds, RPC functions, webhooks, and administrative tools. -- Make the same CipherStash machine credentials available to the deployed application and the backfill job. +- Make the same CipherStash deployment credentials available to the application and backfill job; see [Credentials at build and runtime](/guides/deployment#credentials-at-build-and-runtime). - Decide which encrypted capability each column needs by following [EQL core concepts](/reference/eql/core-concepts). The examples migrate `patients.name` and `patients.date_of_birth`: @@ -127,7 +127,7 @@ npx stash encrypt backfill --table patients --column date_of_birth The command pages by primary key, encrypts rows in chunks, and records checkpoints. It is resumable and idempotent. For a non-interactive job, acknowledge the deployment gate with `--confirm-dual-writes-deployed`. -Run the backfill with the same CipherStash workspace and credentials as the deployed application. A local CipherStash profile may point to a different workspace, producing values the production application cannot decrypt. +Run the backfill with the same CipherStash workspace and keyset as the deployed application. A local developer profile may point to a different workspace, producing values the production application cannot decrypt. Use the deployed environment's explicit `CS_*` values for the job. diff --git a/content/docs/integrations/drizzle.mdx b/content/docs/integrations/drizzle.mdx index 9d963c4..e099aca 100644 --- a/content/docs/integrations/drizzle.mdx +++ b/content/docs/integrations/drizzle.mdx @@ -31,6 +31,12 @@ npx stash eql install The v3 install (the default) runs directly against the database and cannot generate a Drizzle migration: `--drizzle` is rejected for a v3 install. EQL is therefore not part of your migration history, so a database rebuilt from migrations will not have it. Re-run the install after a rebuild. +## Credentials + + + +The native Stack client used below discovers the four `CS_*` variables first, then falls back to the developer profile. Use separate credentials for each deployed environment. + ## Declare the table The column type *is* the capability. There are no flags to configure. `TextEq` answers equality and nothing else, `IntegerOrd` answers ranges and ordering, `TextMatch` answers free-text containment, and a bare `Text` or `Bigint` is storage-only. diff --git a/content/docs/integrations/supabase/edge-functions.mdx b/content/docs/integrations/supabase/edge-functions.mdx index 485ff2c..84969c0 100644 --- a/content/docs/integrations/supabase/edge-functions.mdx +++ b/content/docs/integrations/supabase/edge-functions.mdx @@ -35,13 +35,15 @@ Map the `wasm-inline` entries in your function's `deno.json`: Provide the four `CS_*` values explicitly through an env file when serving locally and through Supabase secrets when deployed. -Provide the `CS_*` credentials when you serve the function. Generate them with `stash env` rather than assembling the file by hand — it prints the deployment variables for the workspace you are authenticated against, so redirect it straight to the env file: + + +For an Edge Function, use the CLI or Dashboard option; the developer profile cannot cross into the Deno runtime. To create a dedicated local credential set and write it directly to the function's env file: ```bash example-id="supabase-edge-stash-env" -npx stash env > ./supabase/functions/.env.local +npx stash env --name edge-dev --write ./supabase/functions/.env.local ``` -`--write` writes to a file instead of stdout if you would rather not redirect. The command is marked experimental, so read what it emits before committing to it — and never commit the file itself. The [CLI reference](/reference/cli/env) has the full flag set. +Never commit this file. Each successful `stash env` run creates a new credential with a unique name, and the access key cannot be shown again. Then serve the function against that file: @@ -49,14 +51,7 @@ Then serve the function against that file: supabase functions serve --env-file ./supabase/functions/.env.local ``` -```sh title="supabase/functions/.env.local" -CS_WORKSPACE_CRN=crn:ap-southeast-2.aws: -CS_CLIENT_ID=... -CS_CLIENT_KEY=... -CS_CLIENT_ACCESS_KEY=... -``` - -For deployed functions, set the same values as [Edge Function secrets](https://supabase.com/dashboard/project/_/settings/functions). +For deployed functions, add the same four values as [Edge Function secrets](https://supabase.com/dashboard/project/_/settings/functions). Use a separate credential set for production rather than copying the local values. ## Encrypt and decrypt in a function diff --git a/content/docs/integrations/supabase/index.mdx b/content/docs/integrations/supabase/index.mdx index f9efeec..c26fce0 100644 --- a/content/docs/integrations/supabase/index.mdx +++ b/content/docs/integrations/supabase/index.mdx @@ -37,6 +37,7 @@ With EQL 3.0.4, the Supabase wrapper supports encrypted equality, range, and ord | Look up the complete wrapper API | [`encryptedSupabase` reference](/reference/stack/supabase) | | Bind decryption to the signed-in user | [Supabase Auth](/integrations/supabase/auth) | | Encrypt inside Supabase Edge Functions | [Edge Functions](/integrations/supabase/edge-functions) | +| Choose local or deployment credentials | [Workspace credentials](/reference/workspace/configuration#credentials) | | Use an ORM against Supabase Postgres | [Drizzle](/integrations/drizzle) or [Prisma ORM 8](/integrations/prisma) | | Encrypt columns that already contain data | [Encrypt existing data](/guides/migration/encrypt-existing-data) | | Plan a production rollout or rollback | [Deployment guide](/guides/deployment) | diff --git a/content/docs/integrations/supabase/quickstart.mdx b/content/docs/integrations/supabase/quickstart.mdx index f7dd3d4..da64681 100644 --- a/content/docs/integrations/supabase/quickstart.mdx +++ b/content/docs/integrations/supabase/quickstart.mdx @@ -58,7 +58,7 @@ If the command generates a Supabase migration instead of applying EQL directly, npx stash eql status ``` -The native Stack client automatically uses the developer profile created by this login. You do not need `CS_*` machine credentials for local development; those are for deployed environments. +The native Stack client automatically uses the developer profile created by this login. You do not need the four deployment environment variables for local development. When you deploy, [choose a deployment credential source](/guides/deployment#credentials-at-build-and-runtime). **Using an agent?** An agent can drive the same setup. If no developer profile exists, it should start `npx stash auth login --json --region --supabase`, show you the returned verification URL, and leave the command running until authorization completes. It can then run `npx stash init --supabase --region `. diff --git a/content/docs/integrations/supabase/supabase-js.mdx b/content/docs/integrations/supabase/supabase-js.mdx index 246919d..e198479 100644 --- a/content/docs/integrations/supabase/supabase-js.mdx +++ b/content/docs/integrations/supabase/supabase-js.mdx @@ -46,7 +46,11 @@ SUPABASE_ANON_KEY=... DATABASE_URL=postgresql://... ``` -The encryption client also needs a local developer profile created by `stash auth login`, or `CS_*` machine credentials in a deployed environment. The [Quickstart setup](/integrations/supabase/quickstart#initialize-cipherstash) creates and uses the developer profile. +## Credentials + + + +The [Quickstart setup](/integrations/supabase/quickstart#initialize-cipherstash) creates and uses the developer profile. In CI or a deployed application, add the four `CS_*` variables to the same server environment as the Supabase settings above. ## Create the client diff --git a/content/docs/reference/proxy/configuration.mdx b/content/docs/reference/proxy/configuration.mdx index e98b04a..2eac736 100644 --- a/content/docs/reference/proxy/configuration.mdx +++ b/content/docs/reference/proxy/configuration.mdx @@ -48,7 +48,7 @@ docker compose up Unlike the Stack SDK, Proxy **always requires credentials to be supplied explicitly**, because it runs as a separate process or container and cannot use the host's device-based authentication. -For local development, create a client key and access key in the [Dashboard](https://dashboard.cipherstash.com). For production, see [Going to production](/stack/deploy/going-to-production). +Create the four variables with `stash env` or the Dashboard, then supply them to the Proxy container. [Workspace credentials](/reference/workspace/configuration#credentials) shows both options and the complete environment block. ## Setting up the database schema diff --git a/content/docs/reference/workspace/configuration.mdx b/content/docs/reference/workspace/configuration.mdx index 87d6622..74fa37d 100644 --- a/content/docs/reference/workspace/configuration.mdx +++ b/content/docs/reference/workspace/configuration.mdx @@ -7,19 +7,11 @@ components: [platform, encryption] A workspace is identified by its **CRN** and accessed with a **client key** and an **access key**. How those credentials reach your application differs between local development and production. -## Local development +## Credentials -For local development, credentials are handled automatically by device-based authentication. Run `stash init` to set up your device: + -```bash cta cta-type="quickstart" example-id="stash-init-workspace" -npx stash init -``` - -This creates a device-backed client key with access to the workspace's default keyset. No environment variables are needed. - -## Production credentials - -In production and CI/CD, a workspace is configured with explicit credentials: +## What the deployment variables mean | Credential | Description | |---|---| @@ -28,9 +20,7 @@ In production and CI/CD, a workspace is configured with explicit credentials: | Client key | Your half of the dual-party key split | | Access key | Authenticates API calls to CipherStash | -These are the same credentials the [Stack SDK](/reference/stack) and [Proxy](/reference/proxy/configuration) consume. For the full set of environment variables and programmatic options, see the [Stack SDK configuration reference](/reference/stack). - -See [going to production](/stack/deploy/going-to-production) for a step-by-step guide to generating them. +These are the same credentials the [Stack SDK](/reference/stack) and [Proxy](/reference/proxy/configuration) consume. For build-time availability, environment separation, and production rollout gates, see [Deployment](/guides/deployment). ## Keysets diff --git a/src/components/cipherstash-credentials.tsx b/src/components/cipherstash-credentials.tsx index 5fa5c4b..2665cb9 100644 --- a/src/components/cipherstash-credentials.tsx +++ b/src/components/cipherstash-credentials.tsx @@ -1,5 +1,29 @@ +"use client"; + +import type { CodeBlockProps } from "fumadocs-ui/components/codeblock"; import { DynamicCodeBlock } from "fumadocs-ui/components/dynamic-codeblock"; -import { ExternalLink, Laptop, LayoutDashboard, Terminal } from "lucide-react"; +import { + Popover, + PopoverClose, + PopoverContent, + PopoverTrigger, +} from "fumadocs-ui/components/ui/popover"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "fumadocs-ui/components/ui/tabs"; +import { + Check, + ChevronDown, + ExternalLink, + Laptop, + LayoutDashboard, + Terminal, +} from "lucide-react"; +import { useState } from "react"; +import { TrackedCodeBlock } from "@/components/code-block"; import { cipherstashDark, cipherstashLight } from "@/lib/shiki-themes"; const ENVIRONMENT_VARIABLES = `CS_WORKSPACE_CRN=crn:.: @@ -9,34 +33,32 @@ CS_CLIENT_ACCESS_KEY=CSAK...`; const options = [ { + value: "developer-profile", title: "Developer profile", useFor: "Local development", icon: Laptop, - content: ( - <> - Run npx stash auth login. The native Stack client finds the - resulting developer profile automatically, so you do not need - environment variables on your development machine. - - ), + command: "npx stash auth login", + action: null, + description: + "The native Stack client uses the developer profile automatically.", }, { + value: "stash-env", title: "stash env", - useFor: "CI and deployed environments", + useFor: "CI and Deployment", icon: Terminal, - content: ( - <> - Run npx stash env --name <app-env> while logged in. - It creates a client and prints the four environment variables below. The - access key is shown only once. - - ), + command: "npx stash env --name ", + action: null, + description: + "Creates a client and prints the four variables below. The access key is shown once.", }, { + value: "dashboard", title: "Dashboard", - useFor: "CI and deployed environments", + useFor: "CI and Deployment", icon: LayoutDashboard, - content: ( + command: null, + action: ( <> Open your{" "} {" "} - and create deployment credentials there. Add the resulting values to - your platform's secret store. + and create deployment credentials. ), + description: "Save the values in your platform’s secret store.", }, ] as const; +type CredentialOptionValue = (typeof options)[number]["value"]; + +function TrackedBashCodeBlock(props: CodeBlockProps) { + return ( + + ); +} + +function DeploymentEnvironmentVariables() { + return ( +
+

+ Deployment environment variables +

+

+ Both deployment methods produce the same values. +
+ Treat CS_CLIENT_KEY and CS_CLIENT_ACCESS_KEY{" "} + as secrets. +

+ +
+ ); +} + /** * The canonical credential-source chooser for integration and deployment * guides. Keep the discovery order and environment-variable names aligned * with the Stack authentication skill. */ export function CipherStashCredentials() { + const [selectedOption, setSelectedOption] = useState( + options[0].value, + ); + const activeOption = + options.find(({ value }) => value === selectedOption) ?? options[0]; + const ActiveIcon = activeOption.icon; + return (
@@ -76,47 +141,130 @@ export function CipherStashCredentials() {

-
    - {options.map(({ title, useFor, icon: Icon, content }, index) => ( -
  1. -
    + + setSelectedOption(value as CredentialOptionValue) + } + className="my-0 gap-0 overflow-visible rounded-none border-0 bg-transparent" + > +
    + + + + + + {options.map(({ value, title, useFor, icon: Icon }) => ( + + + + ))} + + +
    + + + {options.map(({ value, title, useFor, icon: Icon }, index) => ( + -
    -

    + + {index + 1}. {title} -

    -

    + + {useFor} -

    -
    -
    -

    - {content} + + + + ))} + + + {options.map(({ value, command, action, description }) => ( + + {command ? ( + <> +

    Run:

    + + + ) : ( +

    + {action} +

    + )} +

    + {description}

    -
  2. + {value !== "developer-profile" && ( + + )} + ))} -
- -
-

- Deployment environment variables -

-

- Both deployment methods produce the same values. Treat{" "} - CS_CLIENT_KEY and CS_CLIENT_ACCESS_KEY as - secrets. -

- -
+
); }