Audit log
The audit events NebulaCtrl records, their fields, how to filter and export them from the Activity page or the API, and what is never written to them.
The control plane writes an audit event for each state-changing action. The Activity page and the API read those events. This page lists the fields, the guarantees, the filters and every action the control plane records.
Quick reference
| Console | Activity, in the organization's navigation |
| API | GET /api/v1/activity (listActivity) and GET /api/v1/activity/export (exportActivity) |
| Who can read | Every role, including viewer. A project-limited API token sees only events of its projects. |
| Export | CSV only |
| Retention | Kept as long as the organization exists |
| Editable | No. Events are append-only. |
An audit event
| Field | Meaning |
|---|---|
id | The event's identifier. |
at | When it was recorded, in UTC. |
actorType | user, token, agent or system. |
actorId | The user's or token's id, the id of the cluster that sent the event, system, or updater for the outcome of a control plane update. |
action | What happened, such as member.role_changed. |
target | A JSON object of ids and names the action touched. |
before, after | JSON snapshots, present only for actions that change something. |
The console shows the actor by name: the member's name, NAME token or API token, CLUSTER agent, or system. An event with no actor is recorded as system.
Guarantees and limits
- Append-only. A database trigger rejects every update and every delete of an event. The only exception is the cascade that deletes an organization's events together with the organization.
- Best effort in places. Most events are written after the action completes. If the write fails, the action still happened, and the control plane logs
audit event was not recorded; the action it describes still happened. Events written together with a change, such as organization creation, team changes, SCIM changes and change set transitions, roll back with it. - Not in any organization's feed.
user.signed_inanduser.provisionedbelong to no organization. - No secrets. Events name which variable, token or credential changed and never its value.
- One exception.
database.queriedrecords the full query text. - Outside the record. Changes made directly in the database or inside a cluster.
Filter the Activity page
| Control | Effect |
|---|---|
| Kind | all, deploys, config, access or clusters. The API takes kind=deploy, config, access or cluster. |
| Search box | Filter by actor, target or action matches the action, the actor id and the readable fields of the target. The API parameter is q. |
| Project | Events of one project, directly or through its environments, services and releases. The API parameter is projectId. |
| Time range | Last 24h, Last 7 days, Last 30 days or All time. The API takes from and to as RFC 3339 timestamps. |
| Actor chip | Select an actor's name in a row to filter by them; the chip clears the filter. The API parameter is actorId. |
The API also filters by action. Pages hold 50 events by default and at most 200, and the response carries nextCursor and an exact total. The page groups events by UTC day and folds runs of identical actions by one actor into one row.
Select a row to see its action, actor, time, target, and the Before and After values when they exist.
Export
Select Export CSV on the Activity page, or call GET /api/v1/activity/export. The export applies the same filters, ignores paging and walks the whole matching ledger in batches of 500. The file is named activity.csv by the API, and activity-TIMESTAMP.csv by the console.
The header row is:
id,at,actorType,actorId,action,target,before,afterat is RFC 3339 with nanoseconds in UTC. target, before and after are JSON text. If the export fails partway, the file is truncated, and the rows already sent are correct.
Events by kind
The Kind filter groups events by the prefix of their action. Events with the prefixes mesh., template., tailnet., preview., project_config. and backup., and three organization.* security events, fall under no kind. They appear under all, with the chip other; Under no kind lists them.
Deploys
| Action | Recorded when |
|---|---|
release.created, release.promoted | A release is created, or promoted to another environment. |
deployment.started, deployment.rolled_back, deployment.cancelled, deployment.superseded | A deployment starts, rolls back, is cancelled, or is replaced by a newer one. |
approval.requested, approval.decided, approval.expired | A production approval is requested, decided, or expires. |
build.queued, build.cancelled, build.superseded, build.release_failed | A build is queued, cancelled, replaced, or fails to produce a release. |
change_set.submitted, .applied, .failed, .rejected, .discarded, .item_staged, .item_removed | A change set moves through its states, or an edit is staged or removed. |
service.suspended, service.resumed | A service is suspended or resumed. |
process.restarted, pod.restarted | A process or a pod is restarted. |
Configuration
| Action | Recorded when |
|---|---|
project.created, .updated, .deleted | A project changes. |
environment.created, .updated, .bound, .cluster_bound, .deleted | An environment changes, or is bound to a cluster, by a person or automatically. |
service.created, .updated, .deleted, service.production_approval_changed | A service changes, or its production approval rule does. |
process.created, .updated, .deleted | A process changes. |
volume.created, volume.deleted | A volume is created or deleted. |
variable.set, .deleted, .revealed, .unmanaged | A variable is set, deleted or revealed, or stops being owned by nebula.toml. |
external_resource.created, .updated, .deleted, .linked | An external resource changes, or is linked to services. |
domain.created, .exposure_updated, .dns_settings_updated, .certificate_method_updated, .deleted | A domain changes. |
domain.checked, domain.dns_synced, domain.dns_adopted | A domain is checked, its DNS records are synced, or existing records are adopted. |
domain.certificate_issued, domain.certificate_renewed | A certificate is issued or renewed. |
git_connection.created, .deleted | A Git connection changes. |
registry_credential.created, .deleted | A registry credential changes. |
object_store.created, .updated, .deleted | An object store changes. |
cloudflare_connection.created, .updated, .deleted | A Cloudflare connection changes. |
notification_channel.created, .updated, .deleted | A notification channel changes. The event records whether the secret was replaced, not the secret. |
database.created, database.queried, database.pitr_enabled, database.pitr_disabled, database.reader_promoted, database.archive_deleted | A database service is created, queried, has point-in-time recovery switched, has a reader promoted, or has its archive deleted. |
volume_backup.created, .deleted, .downloaded, .succeeded, .failed | A volume backup is taken, deleted, downloaded, or finishes. |
volume_restore.created, .succeeded, .failed | A volume restore starts or finishes. |
volume_backup_schedule.put, volume_backup_schedule.deleted | A backup schedule is set or removed. |
organization.updated | The organization's name or default cluster changes. |
Access
| Action | Recorded when |
|---|---|
user.signed_in, user.provisioned | A person signs in, or signs in for the first time. Recorded outside any organization. |
session.revoked | A session ends, by sign-out or revocation. |
organization.created, .deleted, .transferred | An organization is created, deleted, or changes owner. |
member.role_changed, member.removed, member.left | A member's role changes, or they are removed or leave. |
invitation.created, .revoked, .accepted | An invitation is created, revoked, or accepted by link. |
api_token.created, api_token.revoked | An API token is created or revoked. |
team.created, .updated, .deleted, team.members_set, team.member_added | A team changes. |
scim.token_rotated, scim.token_disabled | The SCIM token is rotated or turned off. |
scim.user_provisioned, .user_updated, .user_deleted, .user_bound, .user_deprovisioned | The identity provider provisions, updates, deletes, binds or deprovisions a user. The last records how many tokens and sessions ended. |
Clusters
| Action | Recorded when |
|---|---|
cluster.created, .updated, .deleted, .enrolled | A cluster changes, or its agent enrolls. |
cluster.enrollment_token_regenerated | The install credentials are regenerated. |
cluster.join_token_created, cluster.join_token_revoked | A node join token is created or revoked. |
cluster.high_availability_started, cluster.cnpg_install_started, cluster.tailscale_connect_started | One of those installs is started. |
cluster.ssh_key_created, cluster.ssh_install_started, .ssh_install_confirmed, .ssh_install_finished | An SSH install runs. The events carry the host, port, user and host-key fingerprint, never a key. |
cluster.agent.update, cluster.agent.rollback | An agent update or rollback starts, with the images it moves between. |
cluster.cordoned, cluster.uncordoned | A cluster stops or resumes accepting new workloads. |
node.cordoned, node.uncordoned, node.drained | A node is cordoned, uncordoned or drained. |
control_plane.update.requested, .cancelled, .finished | A control plane update is requested, cancelled, or ends. The last is written by the updater or by the control plane when it gives up on a silent updater. |
Under no kind
| Action | Recorded when |
|---|---|
organization.policy_updated | The change policy or deploy freeze changes. |
organization.security_updated | Require two-factor for everyone changes. |
organization.join_token_ttl_updated | The default join token lifetime changes. |
mesh.peer_registered, mesh.peer_revoked | A machine joins the mesh, or a peer is revoked. |
mesh.grant_created, mesh.grant_deleted | Cross-environment network access is granted or removed. |
preview.settings_updated, preview.created, preview.deleted | Preview settings change, or a preview environment is created or deleted. |
project_config.set, project_config.removed | A project's config repository is set or removed. |
tailnet.device_removed, tailnet.device_removal_failed | A Tailscale device is cleaned up, or cleanup fails. |
template.created, .updated, .deleted, template.installed | A template changes, or is installed. |
backup.objects_deleted | Backup objects are removed when an environment is deleted. |
See also
- Security model for what the record covers.
- Manage members and teams for the access events.
Secrets and sealing
How NebulaCtrl encrypts stored secrets with envelope encryption, what the master key protects, how rotation and resealing work, and which values are never logged.
Troubleshooting
Find the page that explains the message you see, from a deployment that does not start to a cluster that does not connect and a control plane that does not sign you in.