diff --git a/info/audit-logs.mdx b/info/audit-logs.mdx index 17e3f78..e3b29c3 100644 --- a/info/audit-logs.mdx +++ b/info/audit-logs.mdx @@ -1,6 +1,6 @@ --- title: "Audit Logs" -description: "Search and export audit logs for API requests across your organization" +description: "Audit logs for API requests across your organization" --- Audit logs record authenticated API requests across your entire organization. Use them to review who called Kernel, which endpoint they called, when the request happened, and how the request completed. @@ -10,15 +10,16 @@ Choose the endpoint that matches the amount of data you need: | Endpoint | Best for | Output | |----------|----------|--------| | [Search](#search-audit-logs) | Interactive investigation and recent activity | Paginated JSON events | -| [Export](#export-audit-logs) | Archival, compliance, and offline analysis | Gzip-compressed JSON Lines (`.jsonl.gz`) | +| [Download](#download-audit-logs) | Archival, compliance, and offline analysis of a bounded time window | Gzip-compressed JSON Lines (`.jsonl.gz`) | +| [Continuous S3 export](#continuous-s3-export) | Ongoing delivery to your data lake or compliance bucket | Partitioned `jsonl.gz` objects in your S3 bucket | -Audit logs are ordered newest first. Time windows use an inclusive `start` and exclusive `end`: `[start, end)`. A search or export can cover up to 30 days. Split longer periods into multiple time windows. +Search and download are available on **Start-Up** and **Enterprise** plans. Continuous S3 export is available on **Enterprise**. -Both endpoints are also available from the [CLI](/reference/cli/audit-logs). For the underlying HTTP API, see [search](https://kernel.sh/docs/api-reference/audit-logs/list-audit-logs) and [export](https://kernel.sh/docs/api-reference/audit-logs/download-an-audit-log-export-chunk) in the API reference. +Audit logs are also available from the [CLI](/reference/cli/audit-logs). ## Filter audit logs -The API and SDKs use the same filters for search and export: +The API and SDKs use the same filters for search and downloads: - `auth_strategy` filters by authentication method, such as `api_key`, `dashboard`, or `oauth`. - `service` filters by the service that emitted the audit event. @@ -95,14 +96,9 @@ func main() { See the [API reference](https://kernel.sh/docs/api-reference/audit-logs/list-audit-logs) for the full request and response schema. -## Export audit logs +## Download audit logs -The SDK download helpers default to `jsonl.gz` and write a complete export to a destination you provide. They: - -- request every chunk until the export is complete -- validate pagination metadata and each chunk's SHA-256 checksum before writing -- retry transient HTTP and transfer failures -- append verified chunks in order +A download covers a time window of up to 30 days. The SDK download helpers default to `jsonl.gz` and write the result to a destination you provide. The helpers don't close the destination. Python provides equivalent sync and async methods; both accept a synchronous binary destination. @@ -178,6 +174,257 @@ func main() { ``` -Export chunks contain one JSON object per line. They use the same fields as search results and add `event_id`. +Downloaded chunks contain one JSON object per line. They use the same fields as search results and add `event_id`. For direct HTTP integrations, see the [API reference](https://kernel.sh/docs/api-reference/audit-logs/download-an-audit-log-export-chunk) for pagination headers, formats, and the full request and response schema. + +## Continuous S3 export + +Continuous export writes new audit log events to an S3 bucket that you control. A destination is an organization-level resource: Kernel assumes an IAM role in your AWS account and writes `jsonl.gz` objects to the configured bucket. The destination is created paused so you can configure and verify IAM before delivery starts. + +### Set up a destination + +You can use the SDKs, the [CLI](/reference/cli/audit-logs#kernel-audit-logs-export), or the HTTP API. All destination requests require an organization-level credential. + +The setup steps below use the SDKs. For the CLI walkthrough, see the [CLI reference](/reference/cli/audit-logs#kernel-audit-logs-export). + +#### 1. Create a paused destination + +Create the destination with the customer role ARN. The create response contains the destination `id`, the Kernel role ARN that must be trusted (`kernel_role_arn`), and the unique STS external ID (`external_id`). Save all three values. The `external_id` is not your organization ID and is not interchangeable with an external ID from another destination. + +Every destination is an S3 destination in `jsonl.gz` format and starts with `status: "paused"`. If you use KMS, set `kms_key_id` to a key ID, alias, or ARN in the destination region. + + +```typescript TypeScript +import Kernel from '@onkernel/sdk'; + +const kernel = new Kernel({ + apiKey: process.env.KERNEL_API_KEY, +}); + +const destination = await kernel.auditLogs.exportDestinations.create({ + type: 's3', + format: 'jsonl.gz', + region: 'us-east-1', + bucket: 'customer-audit-logs', + prefix: 'audit-logs', + role_arn: 'arn:aws:iam::123456789012:role/customer-audit-log-export', + // kms_key_id: 'arn:aws:kms:us-east-1:123456789012:key/11111111-2222-3333-4444-555555555555', +}); + +console.log(destination.id); +console.log(destination.kernel_role_arn); +console.log(destination.external_id); +``` + +```python Python +import os +from kernel import Kernel + +client = Kernel(api_key=os.environ["KERNEL_API_KEY"]) + +destination = client.audit_logs.export_destinations.create( + type="s3", + format="jsonl.gz", + region="us-east-1", + bucket="customer-audit-logs", + prefix="audit-logs", + role_arn="arn:aws:iam::123456789012:role/customer-audit-log-export", + # kms_key_id="arn:aws:kms:us-east-1:123456789012:key/11111111-2222-3333-4444-555555555555", +) + +print(destination.id) +print(destination.kernel_role_arn) +print(destination.external_id) +``` + +```go Go +package main + +import ( + "context" + "fmt" + + "github.com/kernel/kernel-go-sdk" +) + +func main() { + ctx := context.Background() + client := kernel.NewClient() + + destination, err := client.AuditLogs.ExportDestinations.New(ctx, kernel.AuditLogExportDestinationNewParams{ + CreateAuditLogExportDestinationRequest: kernel.CreateAuditLogExportDestinationRequestParam{ + Type: kernel.CreateAuditLogExportDestinationRequestTypeS3, + Format: kernel.CreateAuditLogExportDestinationRequestFormatJSONLGz, + Region: "us-east-1", + Bucket: "customer-audit-logs", + Prefix: "audit-logs", + RoleArn: "arn:aws:iam::123456789012:role/customer-audit-log-export", + // KmsKeyID: kernel.String("arn:aws:kms:us-east-1:123456789012:key/11111111-2222-3333-4444-555555555555"), + }, + }) + if err != nil { + panic(err) + } + + fmt.Println(destination.ID) + fmt.Println(destination.KernelRoleArn) + fmt.Println(destination.ExternalID) +} +``` + + +#### 2. Configure the IAM trust policy + +Update the trust policy on the customer role supplied as `role_arn`. Use the `kernel_role_arn` and `external_id` returned by the create call. The values below are placeholders; replace both of them with the values from your response. + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowKernelAuditLogExport", + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::123456789012:role/kernel-audit-log-export" + }, + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "sts:ExternalId": "external-id-from-create-response" + } + } + } + ] +} +``` + +`Principal.AWS` must be the returned `kernel_role_arn`, not the customer role's own ARN. The `sts:ExternalId` condition must be the returned `external_id`. Recreating a destination generates a new external ID, so update this trust policy again if you recreate it. + +#### 3. Grant S3 and KMS permissions + +Attach an identity policy to the customer role. Grant `s3:PutObject` for real delivery and the test probe. Granting `s3:DeleteObject` is recommended so Kernel can remove the temporary probe after a successful test. + +The resource should match the configured prefix. If you use a different prefix, replace `audit-logs/*` below. Omit the KMS statement when `kms_key_id` is empty. + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "WriteAuditLogObjects", + "Effect": "Allow", + "Action": [ + "s3:PutObject", + "s3:DeleteObject" + ], + "Resource": "arn:aws:s3:::customer-audit-logs/audit-logs/*" + }, + { + "Sid": "UseAuditLogKMSKey", + "Effect": "Allow", + "Action": "kms:GenerateDataKey", + "Resource": "arn:aws:kms:us-east-1:123456789012:key/11111111-2222-3333-4444-555555555555" + } + ] +} +``` + +When KMS is configured, the KMS key policy must also allow the customer role to use `kms:GenerateDataKey` (unless the key policy delegates access to IAM policies). The test and real uploads use the same encryption request: SSE-KMS with the configured key. Without a configured KMS key, the bucket's default encryption applies. + +#### 4. Test and activate + +The test endpoint assumes the customer role, writes a temporary gzip probe, and attempts to delete it. The probe uses the same request metadata as a real delivery: a SHA-256 checksum, `Content-Type: application/gzip`, and SSE-KMS when configured. Run the test before changing the destination to active. + +A successful test returns `stage: "complete"`. A failed test identifies `assume_role` or `put_object` and returns `assume_role_failed` or `put_object_failed`. Do not activate the destination until the test succeeds. + + +```typescript TypeScript +const test = await kernel.auditLogs.exportDestinations.test(destination.id); +if (!test.success) { + throw new Error(`export test failed at ${test.stage}`); +} + +const active = await kernel.auditLogs.exportDestinations.update(destination.id, { + status: 'active', +}); +console.log(active.status); // active +``` + +```python Python +test = client.audit_logs.export_destinations.test(destination.id) +if not test.success: + raise RuntimeError(f"export test failed at {test.stage}") + +active = client.audit_logs.export_destinations.update( + destination.id, + status="active", +) +print(active.status) # active +``` + +```go Go +test, err := client.AuditLogs.ExportDestinations.Test(ctx, destination.ID) +if err != nil { + panic(err) +} +if !test.Success { + panic(fmt.Sprintf("export test failed at %s", test.Stage)) +} + +active, err := client.AuditLogs.ExportDestinations.Update(ctx, destination.ID, kernel.AuditLogExportDestinationUpdateParams{ + UpdateAuditLogExportDestinationRequest: kernel.UpdateAuditLogExportDestinationRequestParam{ + Status: kernel.UpdateAuditLogExportDestinationRequestStatusActive, + }, +}) +if err != nil { + panic(err) +} +fmt.Println(active.Status) // active +``` + + +Activation starts delivery at the activation time. It does not backfill events recorded before activation. + +### Object layout + +Every continuous export object uses this exact key layout: + +``` +/destination_id=/org_id=/date=/hour=/-.jsonl.gz +``` + +For example, a destination with prefix `audit-logs` writes under `audit-logs/destination_id=...`. If the prefix is empty, the key starts with `destination_id=...` and has no leading slash. The `date` and `hour` partitions are UTC and identify the calendar hour that fully contains every row in the object. This makes the layout safe for Hive-style partitioning. The format is always `jsonl.gz`: each decompressed line is one JSON event, including `event_id`. + +### Delivery semantics + +- Delivery is **at least once**. A retry can rewrite the same object. +- Each event-time window is held for about 10 minutes before it commits. A row that becomes visible after its window has committed may not be delivered. +- Delivery begins at activation time; events before activation are not backfilled. +- Pausing stops new delivery attempts. Resuming starts from the resume time; events recorded while paused are never exported. Pausing is not a way to defer delivery. +- An S3 upload already in progress may complete after a pause or delete. Its rows can appear again after the destination is resumed. + +### Monitor delivery + +Use the SDK retrieve and list methods, the [CLI](/reference/cli/audit-logs#kernel-audit-logs-export), or the HTTP GET endpoints to inspect the destination and its delivery health. The health fields are: + +| Field | Meaning | +|-------|---------| +| `status` | `active` or `paused`. | +| `last_exported_cursor` | Opaque forward-only checkpoint for continuous delivery. It is not an audit-log list page token. | +| `last_success_at` | Time of the most recent successful export upload. | +| `last_error` | Sanitized description of the most recent delivery failure. | +| `last_error_at` | Time of the most recent delivery failure. | +| `consecutive_failures` | Number of consecutive failed delivery attempts. | +| `next_attempt_at` | Scheduled time for the next delivery attempt after a failure. | + +The cursor and timestamp/error fields can be absent until the destination has attempted delivery. Use `last_error`, `last_error_at`, and `consecutive_failures` together when investigating a destination that is active but not progressing. + +### Troubleshoot delivery + +- **`assume_role` / `assume_role_failed`:** Check the customer role's trust policy. The principal must be the current `kernel_role_arn` from the destination response, and `sts:ExternalId` must equal the current `external_id`. Recreating a destination issues a new external ID; update the trust policy after recreation. +- **`put_object` / `put_object_failed`:** Confirm that the customer role can write to the configured bucket and prefix with `s3:PutObject`, and that the bucket is in the configured commercial AWS region. Grant `s3:DeleteObject` as well so the test probe can be cleaned up. +- **KMS failures:** Confirm that the KMS key is in the commercial `aws` partition, that an ARN's region matches the destination region, and that both the role policy and key policy allow `kms:GenerateDataKey`. If you do not need a customer-managed key, clear it and use bucket-default encryption. +- **A probe remains after a successful test:** Probe cleanup is best effort. Add `s3:DeleteObject` for the configured prefix and remove any leftover `.kernel-audit-log-export-test-*.jsonl.gz` object yourself. +- **A `PATCH` returns `409 Conflict`:** The destination changed concurrently. Retrieve fresh state, merge your intended fields with that state, and retry the update. Do not retry a stale read-modify-write payload unchanged. +- **No objects after a pause or downgrade:** Check `status` and the plan. Pausing and non-Enterprise status stop new delivery; restore Enterprise and follow the normal activation/resume path if the destination is paused. Events recorded while paused are not backfilled. diff --git a/reference/cli/audit-logs.mdx b/reference/cli/audit-logs.mdx index 300272c..91f565f 100644 --- a/reference/cli/audit-logs.mdx +++ b/reference/cli/audit-logs.mdx @@ -2,10 +2,16 @@ title: "Audit Logs" --- -Search and download [organization audit logs](/info/audit-logs) from the CLI. +Search, download, and manage [organization audit logs](/info/audit-logs) from the CLI. + +Search and download are available on **Start-Up** and **Enterprise** plans. Continuous S3 export is available on **Enterprise**. Time values can be dates (`2026-06-01`) or timestamps (`2026-06-01T15:04:05Z`). Dates begin at midnight UTC. + + The `kernel audit-logs export` group follows the current CLI implementation. Install a CLI release that includes this command group; availability depends on the release you have installed. + + ## `kernel audit-logs search` Search audit logs within a time window. Results are ordered newest first. @@ -88,6 +94,166 @@ The requested output appears only after the full download succeeds. Failed downl Downloads don't resume: rerunning the command starts over. Existing files are replaced only when you pass `--force`. +## `kernel audit-logs export` + +Manage S3 destinations that receive a continuous export of your organization's audit logs. The group is also available as `kernel audit-logs exports` and `kernel audit-logs export-destinations`. + +Objects use the layout `/destination_id=/org_id=/date=/hour=/-.jsonl.gz`. Delivery is at-least-once. + +Create a destination paused, configure the IAM trust and permissions, run `test`, and then run `resume`. The create response includes the `kernel_role_arn` and `external_id` values needed for the trust policy. The destination must use an organization-level credential; project-scoped API keys are refused. + +### `kernel audit-logs export create` + +Create an S3 audit log export destination. The destination is created paused. + +```bash +kernel audit-logs export create \ + --region us-east-1 \ + --bucket customer-audit-logs \ + --prefix audit-logs \ + --role-arn arn:aws:iam::123456789012:role/customer-audit-log-export \ + --output json +``` + +Use `--kms-key-id` when the destination should use SSE-KMS. The command always creates the destination with the `s3` type and `jsonl.gz` format. + +| Flag | Description | +|------|-------------| +| `--region ` | AWS region of the destination bucket. Required. | +| `--bucket ` | Destination S3 bucket name. Required. | +| `--prefix ` | Key prefix for exported objects; may be empty. Required. | +| `--role-arn ` | IAM role ARN Kernel assumes to deliver logs. Required. | +| `--kms-key-id ` | KMS key ID, alias, or ARN for server-side encryption. | +| `--output json`, `-o json` | Output the raw JSON destination object. | + +The human-readable output prints the destination details and the activation steps. Use JSON output when a script needs to capture `id`, `kernel_role_arn`, and `external_id`. + +### `kernel audit-logs export list` + +List audit log export destinations. Human-readable output includes the destination ID, bucket, prefix, region, status, last success, failure count, and last error. + +```bash +kernel audit-logs export list \ + --limit 20 \ + --output json +``` + +| Flag | Description | +|------|-------------| +| `--limit ` | Maximum number of destinations to return, from `1` to `100`. Defaults to `20`. | +| `--output json`, `-o json` | Output a JSON object with `destinations` and `next_offset` when another page exists. | + +### `kernel audit-logs export get ` + +Get details for one audit log export destination. + +```bash +kernel audit-logs export get y2kkbpcz1lg0h3q6yr8x4m7d \ + --output json +``` + +| Flag | Description | +|------|-------------| +| `--output json`, `-o json` | Output the raw JSON destination object. | + +Without `--output json`, the command prints configuration, status, and delivery health fields such as `last_exported_cursor`, `last_success_at`, `last_error`, `last_error_at`, `consecutive_failures`, and `next_attempt_at`. + +### `kernel audit-logs export update ` + +Update one or more destination fields. Pass at least one update flag. The API validates the merged destination configuration, so a KMS key ARN must match the destination region. + +```bash +kernel audit-logs export update y2kkbpcz1lg0h3q6yr8x4m7d \ + --prefix audit-logs-v2 \ + --output json +``` + +To remove a configured KMS key and use bucket-default encryption: + +```bash +kernel audit-logs export update y2kkbpcz1lg0h3q6yr8x4m7d \ + --clear-kms-key +``` + +| Flag | Description | +|------|-------------| +| `--region ` | Update the AWS region of the destination bucket. | +| `--bucket ` | Update the destination S3 bucket name. | +| `--prefix ` | Update the key prefix for exported objects. | +| `--role-arn ` | Update the IAM role ARN Kernel assumes to deliver logs. | +| `--kms-key-id ` | Update the KMS key ID, alias, or ARN for server-side encryption. | +| `--clear-kms-key` | Remove the configured KMS key. Mutually exclusive with `--kms-key-id`. | +| `--output json`, `-o json` | Output the raw JSON destination object. | + +A successful update prints the updated destination. A `409 Conflict` means the destination changed concurrently; retrieve fresh state and retry with the intended fields. + +### `kernel audit-logs export pause ` + +Pause a destination so new delivery attempts stop. + +```bash +kernel audit-logs export pause y2kkbpcz1lg0h3q6yr8x4m7d \ + --output json +``` + +| Flag | Description | +|------|-------------| +| `--output json`, `-o json` | Output the raw JSON destination object. | + +An S3 upload already in progress may still complete after the pause. Events recorded while paused are not exported. + +### `kernel audit-logs export resume ` + +Resume a destination. Delivery starts from the time of the resume; events recorded while paused are not exported. + +```bash +kernel audit-logs export resume y2kkbpcz1lg0h3q6yr8x4m7d \ + --output json +``` + +| Flag | Description | +|------|-------------| +| `--output json`, `-o json` | Output the raw JSON destination object. | + +Use `resume` only after the destination's trust policy and permissions are configured and `test` succeeds. + +### `kernel audit-logs export delete ` + +Delete a destination and stop new delivery attempts. + +```bash +kernel audit-logs export delete y2kkbpcz1lg0h3q6yr8x4m7d +``` + +This command has no flags and does not support JSON output. An S3 upload already in progress may complete after the delete. + +### `kernel audit-logs export test ` + +Test a destination by assuming its role and writing a temporary probe object. The command exits non-zero when the test fails. + +```bash +kernel audit-logs export test y2kkbpcz1lg0h3q6yr8x4m7d \ + --output json +``` + +| Flag | Description | +|------|-------------| +| `--output json`, `-o json` | Output the raw JSON test result. | + +The result has `success` and `stage` fields. The stages are `assume_role`, `put_object`, and `complete`; customer-fixable failures use `assume_role_failed` or `put_object_failed`. A successful test reaches `complete`. The probe is deleted after the write when the role has `s3:DeleteObject`; grant that permission so test objects are cleaned up. + +### Activation sequence + +Use this sequence for every new destination: + +1. Run `create`. Save the returned destination ID, `kernel_role_arn`, and `external_id`. +2. Update the customer role's trust policy to allow the returned Kernel role ARN with the returned `sts:ExternalId`. +3. Grant `s3:PutObject` and, preferably, `s3:DeleteObject` on the configured prefix. If KMS is configured, grant `kms:GenerateDataKey` and key-policy access. +4. Run `test ` and fix any `assume_role` or `put_object` failure. +5. Run `resume ` to start delivery from that point. There is no backfill. + +After a plan downgrade, `list`, `get`, and `delete` remain available for cleanup, while delivery stops and `create`, `update`, and `test` require Enterprise. + ## Aliases You can also use `kernel audit-log`, `kernel auditlogs`, or `kernel auditlog`.