diff --git a/content/docs/meta.json b/content/docs/meta.json index 0c04581..44640f6 100644 --- a/content/docs/meta.json +++ b/content/docs/meta.json @@ -40,6 +40,7 @@ "user-guide/dashboards", "user-guide/sql-editor", "user-guide/rbac", + "user-guide/api-keys", "user-guide/log-iq", "user-guide/openid", "user-guide/retention", diff --git a/content/docs/user-guide/api-keys.mdx b/content/docs/user-guide/api-keys.mdx new file mode 100644 index 0000000..c130779 --- /dev/null +++ b/content/docs/user-guide/api-keys.mdx @@ -0,0 +1,227 @@ +--- +title: API Keys +redirect_from: + - /api-keys + - /features/api-keys +--- + + + +API keys are a non-interactive way to authenticate against Parseable. They are best suited for log forwarders, CLI tools, automation scripts, AI agents, and any other client where Basic Auth or OIDC is impractical. + +A Parseable instance has three types of identities — **Native** (Basic Auth), **OAuth** (OIDC), and **API Key**. API keys behave like users: they are assigned roles, and each role is a set of [RBAC](/docs/user-guide/rbac) privileges. The key inherits exactly the access its roles grant — nothing more, nothing less. + +## When to use API keys + +- **Ingestion agents** — Fluent Bit, Vector, OpenTelemetry Collector, log forwarders. Issue an API key with the `ingestor` role and ship logs without storing a username and password. +- **CLI / scripts** — `pb` CLI or any custom automation that needs scoped, revocable credentials. +- **Agents** — AI agents and other autonomous workloads that need read access to specific datasets. + + +Treat an API key like a password. The full key value is shown **only once** at creation time. Store it in a secrets manager and never commit it to source control. + + +## How API keys work + +An API key has: + +- a **key id** (`keyId`) — a stable identifier used for management operations +- a **key name** (`keyName`) — a human-readable label, must be unique within the tenant/organization +- a **secret value** (`apiKey`) — a UUID, sent on each request via the `x-api-key` header +- a set of **roles** — pre-existing roles that grant privileges (same roles used for Native and OAuth users) + +When a request arrives with an `x-api-key` header, Parseable looks up the key, resolves its roles into permissions, and authorizes the request the same way it authorizes any other user. + +## Create an API key + +Roles must already exist in the tenant/organization. See [RBAC](/docs/user-guide/rbac) for how to create roles. + +```sh +curl -X POST https:///api/prism/v1/apikeys \ + -u admin:admin \ + -H "Content-Type: application/json" \ + -d '{ + "keyName": "frontend-ingest", + "roles": ["ingestor-frontend"] + }' +``` + +Response — the **full key value is returned only on this call**: + +```json +{ + "keyId": "01ARZ3NDEKTSV4RRFFQ69G5FAV", + "keyName": "frontend-ingest", + "apiKey": "9b2f8c4e-1d6a-4f2b-8e7c-3a5d9c1b7e4f", + "roles": ["ingestor-frontend"], + "createdBy": "admin", + "createdAt": "2026-04-30T10:30:00Z", + "modifiedAt": "2026-04-30T10:30:00Z" +} +``` + +Copy the `apiKey` value somewhere safe before you leave the response. Subsequent list calls return a masked version, and there is no way to recover the original after it leaves your screen. + +## List API keys + +```sh +curl https:///api/prism/v1/apikeys -u admin:admin +``` + +Each entry returns the metadata, but `apiKey` is masked to its last four characters: + +```json +[ + { + "keyId": "01ARZ3NDEKTSV4RRFFQ69G5FAV", + "keyName": "frontend-ingest", + "apiKey": "****7e4f", + "roles": ["ingestor-frontend"], + "createdBy": "admin", + "createdAt": "2026-04-30T10:30:00Z", + "modifiedAt": "2026-04-30T10:30:00Z" + } +] +``` + +API-key identities are not surfaced in the regular `GET /api/v1/users` listing — they are managed exclusively under `/api/v1/apikeys`. + +## Get an API key by id + +Fetching a single key by its `keyId` returns the **unmasked** value, so an admin can recover a key without re-creating it. Permission to call this endpoint should be reserved for administrators. + +```sh +curl https:///api/prism/v1/apikeys/01ARZ3NDEKTSV4RRFFQ69G5FAV \ + -u admin:admin +``` + +```json +{ + "keyId": "01ARZ3NDEKTSV4RRFFQ69G5FAV", + "keyName": "frontend-ingest", + "apiKey": "9b2f8c4e-1d6a-4f2b-8e7c-3a5d9c1b7e4f", + "roles": ["ingestor-frontend"], + "createdBy": "admin", + "createdAt": "2026-04-30T10:30:00Z", + "modifiedAt": "2026-04-30T10:30:00Z" +} +``` + +## Delete an API key + +Deletion is the only revocation mechanism. Once deleted, every request using that key value returns `401 Unauthorized`. + +```sh +curl -X DELETE \ + https:///api/prism/v1/apikeys/01ARZ3NDEKTSV4RRFFQ69G5FAV \ + -u admin:admin +``` + +## Use an API key + +Send the secret value in the `x-api-key` header. This replaces the `Authorization: Basic ...` header — do not send both. + +### Ingest logs + +```sh +curl -X POST https:///api/v1/ingest \ + -H "x-api-key: 9b2f8c4e-1d6a-4f2b-8e7c-3a5d9c1b7e4f" \ + -H "X-P-Stream: frontend" \ + -H "Content-Type: application/json" \ + -d '[{"level":"info","message":"hello"}]' +``` + +### Query + +```sh +curl -X POST https:///api/v1/query \ + -H "x-api-key: 9b2f8c4e-1d6a-4f2b-8e7c-3a5d9c1b7e4f" \ + -H "Content-Type: application/json" \ + -d '{ + "query": "SELECT * FROM frontend", + "startTime": "1h", + "endTime": "now" + }' +``` + +In multi-tenant deployments, also send the tenant header: + +```sh +-H "x-p-tenant: " +``` + +## Scoping access via roles + +Because API keys reuse the role system, you can pick any role supported by Parseable RBAC. The role JSON is identical to what you would assign to a Native user — see [RBAC](/docs/user-guide/rbac) for the full schema. + +### Global ingestion key + +Use a single key for forwarders that send logs to every dataset. + +```json +[ + { "privilege": "ingestor" } +] +``` + +### Dataset-scoped ingestion key + +Restrict the key to one or more named datasets. Useful when each environment or team has its own forwarder. + +```json +[ + { "privilege": "ingestor", "resource": { "dataset": "frontend" } }, + { "privilege": "ingestor", "resource": { "dataset": "checkout" } } +] +``` + +### Global reader for query agents + +Read-only access across every dataset — appropriate for analytics scripts or AI agents that need broad query coverage. + +```json +[ + { "privilege": "reader" } +] +``` + +### Dataset-scoped reader + +Limit a query agent to a single dataset (and optionally to events matching a tag). + +```json +[ + { + "privilege": "reader", + "resource": { "dataset": "frontend" } + } +] +``` + +### Admin key + +Full control over the tenant — create datasets, dashboards, filters, alerts, retention policies, manage users and roles. Use sparingly and only for trusted automation. + +```json +[ + { "privilege": "admin" } +] +``` + +### Editor / Writer key + +Authoring access to dashboards, filters, and alerts on selected datasets — useful for CI pipelines that provision dashboards as code. + +```json +[ + { "privilege": "writer", "resource": { "dataset": "frontend" } } +] +``` + +## Best practices + +- **One key per workload.** Issue separate keys for each forwarder, agent, or pipeline so you can rotate or revoke without disrupting others. +- **Scope tightly.** Prefer dataset-scoped roles over global ones. An ingestion key should not be able to query, and a reader key should not be able to write. +- **Rotate periodically.** Create a new key, switch the workload over, then delete the old one. +- **Store keys in a secrets manager.** Inject them into the workload at runtime — do not bake them into images or commit them to repositories. +- **Audit regularly.** List keys and remove any whose owner or purpose is unclear. diff --git a/content/docs/user-guide/meta.json b/content/docs/user-guide/meta.json index 60cbce6..f783a55 100644 --- a/content/docs/user-guide/meta.json +++ b/content/docs/user-guide/meta.json @@ -7,6 +7,7 @@ "dashboards", "sql-editor", "rbac", + "api-keys", "log-iq", "openid" ]