Audit Vault Documentation

Complete guide to installing, configuring, and using Audit Vault for tamper-evident audit logging in Jenkins.

Installation

Audit Vault can be installed in two ways:

Option 1: Upload HPI File

  1. Download the latest audit-vault.hpi file from your dashboard
  2. Navigate to Manage Jenkins → Plugins → Advanced Settings
  3. Under "Deploy Plugin", click "Choose File" and select the HPI file
  4. Click "Deploy" to install the plugin

Option 2: Manual Installation

  1. Copy the audit-vault.hpi file to your Jenkins plugins directory:
    cp audit-vault.hpi $JENKINS_HOME/plugins/
  2. Restart Jenkins to load the plugin

Note

Audit Vault uses SQLite for local event storage. The database file is created automatically at $JENKINS_HOME/audit-vault/events.db.

Quick Start

Get audit logging running in minutes:

1. Activate Your License

Navigate to Manage Jenkins → System → Audit Vault. Enter your license key and click "Validate License".

2. Enable Event Capture

Check "Enable Audit Vault" and select which event categories to capture (authentication, jobs, credentials, system).

3. Configure an Export Destination (Optional)

Enable one or more of S3 (or an S3-compatible store), a filesystem directory, SFTP, or Azure Blob Storage under Export Destinations below, then click each destination's "Test" button to verify. The export interval (default: 60 minutes) is shared by every destination.

4. Save Configuration

Click "Save". Audit Vault immediately begins capturing events and storing them in the local SQLite database.

5. View the Dashboard

Navigate to Audit Vault in the Jenkins sidebar to view event stats, export status, and chain integrity.

Requirements

  • Jenkins Version: 2.426.x LTS or later
  • Java Version: Java 17 or later
  • Network: HTTPS connectivity for license validation
  • Disk Space: SQLite database grows with event volume (approximately 1 KB per event)
  • S3 Export (optional): AWS credentials with s3:PutObject permission on the target bucket (an S3-compatible endpoint override works the same way, for GCS, MinIO, Cloudflare R2, Wasabi or on-prem Ceph)
  • Filesystem Export (optional): an export directory (local disk or mounted network share) that already exists and is writable by the Jenkins process; the plugin never creates it
  • SFTP Export (optional): the SSH Credentials, Bouncy Castle API and Apache MINA SSHD API plugins; an SSH key credential; and the server's host key(s) in Known Hosts (mandatory -- SFTP export does not run without them)
  • Azure Blob Export (optional): the Azure SDK API plugin; an existing container; and a Secret-text credential holding a SAS token or connection string

Global Settings

Configure Audit Vault in Manage Jenkins → System → Audit Vault.

Enable Audit Vault

Master toggle to enable or disable all event capture. When disabled, no new events are recorded but existing data is preserved.

License Key

Your ozen_av_ license key. Click "Validate License" to activate. The plugin requires a valid license to capture events.

Event Capture Configuration

Control which categories of events are captured. Each toggle controls a group of related event types.

Capture Toggles

  • Authentication Events: Login, logout, failed authentication attempts
  • Job Events: Job creation, modification, deletion, copying, renaming
  • Build Events: Build started, completed, deleted (includes trigger cause and result)
  • Credential Events: Credential creation, modification, deletion, access
  • System Events: Plugin changes, configuration modifications, node activity, security realm changes

Tip

For compliance purposes, enable all event categories. You can always filter events by category when querying or exporting.

Export Destinations

Audit Vault can export audit events to any combination of four destinations: Amazon S3 (or an S3-compatible store), a filesystem directory, an SFTP server, or Azure Blob Storage. Enable each one independently. All four write the same NDJSON content with the same date-based partitioning, and the export interval (default: 60 minutes, minimum: 5) is shared by every destination.

Important

Events are buffered locally in SQLite. With more than one destination enabled, an event only counts as exported, for retention purposes, once every currently enabled destination has confirmed delivery. No events are lost during network outages or export failures -- they stay queued locally until the destination recovers.

S3 Export

Schedule exports to Amazon S3 for long-term storage and SIEM integration.

  • Bucket Name: Target S3 bucket (must already exist)
  • Region: AWS region (e.g., us-east-1)
  • Key Prefix: Optional path prefix for exported files (e.g., jenkins/audit/)
  • Access Key ID: AWS access key with S3 write permissions
  • Secret Access Key: Corresponding AWS secret key
  • Enable Encryption: Server-side AES-256 encryption on uploaded objects -- S3-only; the other three destinations have their own security model, described under each below

Required IAM Permissions

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::your-bucket-name/*"
    }
  ]
}

S3 Path Structure

Events are exported with date-based partitioning for efficient querying:

{prefix}/yyyy/MM/dd/HH/audit-{timestamp}-{count}.ndjson

Example: jenkins/audit/2026/02/17/14/audit-1708182000-207.ndjson

S3-Compatible Endpoint (Optional)

An optional endpoint URL points the same S3 client at an S3-compatible store instead of AWS S3 itself, using the AWS SDK's own endpoint-override support (no new dependency). Leave it blank to use AWS S3, unchanged. This covers GCS via its S3-interoperability API with HMAC keys (not the native Google Cloud Storage API; there is no native GCS destination), MinIO and on-prem Ceph (check Force Path-Style Access, since these typically don't support virtual-hosted-style DNS), Cloudflare R2, and Wasabi. For GCS and R2, leave Enable Encryption unchecked: GCS and R2 both encrypt at rest by default, and R2 rejects the S3 server-side-encryption header outright. Changing the endpoint does not re-export events already written to the previous target.

Testing the Connection

Click "Test S3 Connection" to verify your credentials and bucket (or custom endpoint) access. The test uploads a small test object and confirms write permissions.

Filesystem Export

Writes each batch as an NDJSON file to a directory on the controller -- a local disk or a mounted network share -- for air-gapped controllers and for log shippers (Splunk Universal Forwarder, Filebeat, Fluent Bit, Datadog Agent) that read a directory.

  • Export Directory: an absolute path that must already exist and be writable by the Jenkins process. Audit Vault checks this before every export and never creates the directory itself, so a mistyped path fails visibly instead of writing somewhere else. It can't tell whether a network share is actually mounted at that path.

Click "Test Export Directory" to confirm the path exists, is a directory, and is writable (it writes nothing). Each file is written through an atomic temp-file-plus-rename (Jenkins core's AtomicFileWriter), with a .meta.json sidecar file carrying the same checkpoint an S3 export stores as object metadata.

SFTP Export

Uploads each batch to a directory on an SFTP server, for on-premises and air-gapped archives.

  • Host, Port, Remote Directory: the SFTP server and a target directory that must already exist
  • Credentials: an SSH Username with private key credential (public-key login only; passphrase-protected keys work)
  • Known Hosts: the server's pinned host key(s), collected with ssh-keyscan. ssh-keyscan itself does not authenticate the key it returns; it will happily hand back an attacker's key during a man-in-the-middle attack. Before pasting its output into Known Hosts, verify every key returned through a trusted out-of-band channel. Either collect only the key type you need by running ssh-keyscan -t ed25519 hostname, then verify its fingerprint, or run ssh-keyscan hostname (which may return multiple key types) and verify the fingerprint of each one before saving. Run ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub (or the equivalent for your key type) directly on the SFTP server, or get the fingerprints from your infrastructure team, and confirm they match before saving. Host-key verification is mandatory: with no Known Hosts entered, SFTP export does not run at all, and a server whose key isn't listed is refused before any login or upload attempt.

Click "Test SFTP Connection" to verify the host key, log in, and confirm the remote directory exists (it writes nothing, so it can't prove the account can write there; the first export does). Uploads go to a temporary name, flushed to disk when the server supports the OpenSSH fsync extension (most modern SFTP servers, including OpenSSH itself, do), then renamed into place, with the same .meta.json checkpoint sidecar as filesystem export.

Azure Blob Export

Uploads each batch as one NDJSON block blob to an existing Azure Blob Storage container.

  • Container, Path Prefix: the target container (must already exist; Audit Vault never creates it) and an optional blob-name prefix (default jenkins/audit/)
  • Credentials: a Secret-text credential holding a SAS token (Create and Write permissions, HTTPS only recommended) or a storage-account connection string

Click "Test Azure Blob Connection" to validate the credential: it sends one read-only request for a blob name that never exists and writes nothing. The checkpoint is stored as blob metadata in the same request as the upload, so there's no separate sidecar file; any SAS token or account key in a logged failure is shown as [redacted].

Event Types

Audit Vault captures 35+ event types across 7 categories:

Authentication

  • USER_LOGIN - Successful user authentication
  • LOGIN_FAILED - Failed authentication attempt
  • USER_LOGOUT - User logout

Authorization

  • PERMISSION_CHANGED - Permission modification
  • SECURITY_REALM_CHANGED - Security realm configuration change

Job Activity

  • JOB_CREATED - New job created
  • JOB_MODIFIED - Job configuration changed
  • JOB_DELETED - Job deleted
  • JOB_COPIED - Job copied from another
  • JOB_RENAMED - Job renamed

Build Activity

  • BUILD_STARTED - Build execution started (includes trigger cause)
  • BUILD_COMPLETED - Build finished (includes result: SUCCESS, FAILURE, etc.)
  • BUILD_DELETED - Build record deleted

Credential Events

  • CREDENTIAL_CREATED - New credential added
  • CREDENTIAL_MODIFIED - Credential updated
  • CREDENTIAL_DELETED - Credential removed
  • CREDENTIAL_ACCESSED - Credential accessed by a job or user

System Events

  • PLUGIN_INSTALLED / PLUGIN_UPDATED / PLUGIN_REMOVED - Plugin lifecycle
  • CONFIG_CHANGED - System configuration modified
  • NODE_ADDED / NODE_REMOVED / NODE_ONLINE / NODE_OFFLINE - Node activity
  • SECURITY_CONFIG_CHANGED - Security settings modified

Severity Levels

Each event type has a default severity:

  • INFO - Normal operations (logins, builds, config reads)
  • WARNING - Notable actions (permission changes, credential access)
  • ERROR - Failed operations (login failures, export failures)
  • CRITICAL - Security-sensitive events (security realm changes)

Tamper-Evident Logging

Every audit event includes cryptographic integrity guarantees.

SHA-256 Checksums

Each event's checksum is computed from its core fields:

SHA-256(id | timestamp | eventType | actor | resourceType | resourceId | summary | prevHash)

Hash Chaining

Events are linked in a chain where each event includes the checksum of the previous event (prevHash). This creates a verifiable chain of custody:

Event 1: checksum=abc123, prevHash=0000...0000 (genesis)
Event 2: checksum=def456, prevHash=abc123
Event 3: checksum=ghi789, prevHash=def456

If any event is modified or deleted, the chain breaks and integrity verification will detect the tampering.

Genesis Hash

The first event in the chain uses a special genesis hash (0000...0000) as its prevHash, establishing the start of the chain.

Integrity Verification

Audit Vault verifies the hash chain automatically, incrementally, in the background -- there is no manual "run now" click. A full walk of every event runs once, at Jenkins startup (and after a storage re-initialization), to bound how long tampering further back in the chain could go undetected.

How It Works

After the startup walk, each later maintenance pass:

  1. Re-verifies the previously-checkpointed chain head plus every event captured since the last pass
  2. Re-verifies prevHash and the recomputed checksum for a bounded, rolling slice of older events, so history behind the checkpoint keeps getting re-checked over time without re-walking the whole log on every pass
  3. Re-walks the entire chain again roughly every 24 passes once the log passes 10,000 events (below that, every pass re-verifies the whole chain, since it's still cheap to)
  4. Reports any broken links or corrupted events, identifying the specific event

Verification Result

  • Valid: All events verified so far, chain is intact
  • Failed: Specific event where the chain breaks is identified

Tip

The Audit Vault dashboard's Log Integrity box shows the latest check's result, when it ran, and a separate "Last full re-verification" time for the most recent complete walk -- useful for confirming a walk has covered a given point in history before relying on it.

Dashboard

Access the Audit Vault dashboard from the Jenkins sidebar at Audit Vault.

Dashboard Sections

  • License Status: Current license state and expiration
  • Event Statistics: Total events, unexported count, events by category and severity
  • Chain Integrity: Result of the last incremental check, when it ran, and the time of the last full re-verification
  • Export Status: Per-destination export health, last export time, event counts
  • Recent Events: Table of the 50 most recent audit events with type, actor, summary, and timestamp

Export Format

Events are exported in NDJSON (Newline Delimited JSON) format, one event per line. This format is compatible with most SIEM tools including Splunk, Datadog, and Elasticsearch.

Event JSON Schema

{
  "id": "a1b2c3d4",
  "timestamp": "2026-02-17T14:30:00Z",
  "eventType": "USER_LOGIN",
  "category": "AUTHENTICATION",
  "severity": "INFO",
  "actor": "admin",
  "actorIp": "10.0.1.50",
  "resourceType": "user",
  "resourceId": "admin",
  "resourceName": "admin",
  "summary": "User admin logged in",
  "details": "Authentication via password",
  "metadata": {},
  "checksum": "sha256:abc123...",
  "prevHash": "sha256:def456..."
}

SIEM Integration

Point your SIEM tool at the S3 bucket path to ingest audit events. The date-based partitioning supports efficient time-range queries:

  • Splunk: Use the S3 input with sourcetype _json
  • Datadog: Configure an S3 log source with JSON parsing
  • Elasticsearch: Use Logstash S3 input with JSON codec

Licensing

Activating Your License

  1. Purchase a subscription from the product page
  2. Copy your license key from the dashboard
  3. In Jenkins, navigate to Manage Jenkins → System → Audit Vault
  4. Enter your license key and click "Validate License"

License Validation

Audit Vault validates your license periodically (every 24 hours). If the license server is unreachable, a 72-hour grace period allows continued operation.

Unlicensed Behavior

Without a valid license:

  • Event capture is disabled
  • Existing events remain in the database and can be viewed
  • Already-configured export destinations keep running on schedule -- with capture stopped there's nothing new to send, but any backlog not yet exported still goes out
  • A warning banner is shown to admins

FAQ

How much disk space does Audit Vault use?

Each event is approximately 1 KB in the SQLite database. A moderately active Jenkins instance generating 1,000 events/day would use about 1 MB/day or 365 MB/year. Exported events can be purged from the local database to reclaim space.

What happens if Jenkins crashes during event capture?

SQLite with WAL (Write-Ahead Logging) mode ensures durability. Events that were committed to the database before the crash are preserved. The hash chain resumes from the last committed event on restart.

Can I export to destinations other than S3?

Yes. Besides S3 (any S3-compatible store works too, including MinIO, DigitalOcean Spaces, Backblaze B2, Cloudflare R2, Wasabi, and GCS via its S3-interoperability API -- not a native GCS destination), Audit Vault can export to a filesystem directory or mounted network share, an SFTP server with mandatory host-key verification, or an Azure Blob Storage container. Enable any combination; all four write the same NDJSON content and date-partitioned layout.

Does Audit Vault capture build log contents?

No. Audit Vault captures metadata about builds (started, completed, result, trigger cause) but never captures build log contents. This keeps event sizes small and avoids storing sensitive output.

What data leaves my Jenkins instance?

Only two types of outbound communication:

  • License validation: License key, product identifier, controller identifier (a pseudonymous ID; or the controller URL when a request does not include one, as with older plugin versions), and plugin version sent to ozenops.dev. As with any web request, our server also sees your request's source IP, which we retain for rate limiting and audit (see the privacy policy).
  • Export: Audit events sent to each export destination you configure and enable -- your own S3 bucket (or S3-compatible store), a filesystem directory or network share, an SFTP server, or an Azure Blob container

No build-content telemetry, analytics, or usage tracking is ever sent to OzenOps: job data, build logs, and credentials are never transmitted to us. (If you enable export, audit events, which include job/build metadata, go to your own configured destination(s), as described above; that path never touches OzenOps servers either.)

How do I verify integrity of exported events?

Every export carries a checkpoint: the batch's own sequence range plus the audit chain head (sequence number and SHA-256) the plugin read when it exported the batch. S3 exports carry this as object metadata; filesystem and SFTP exports carry the same values in a .meta.json file beside each export file; Azure Blob exports carry it as blob metadata.

The plugin's README ships a documented check-archive.sh script that checks a downloaded export against a copy of the controller's database and reports two separate results: a Head check (whether your database's chain still passes through the recorded head) and a Body check (whether every line of the export matches its database row). A confirmed head is never presented as a verified body, or vice versa.

Changelog

Recent Updates (2026-10-23)

  • Chain integrity verification is now incremental: a full walk of every event runs once, at Jenkins startup, and each later maintenance pass re-verifies the checkpointed chain head, every event captured since, and a rolling slice of older events, re-walking the whole chain again roughly every 24 passes once the log passes 10,000 events.
  • Every S3 export object now carries its sequence range and the audit chain head as object metadata, so a downloaded archive can be checked against a copy of the controller's database with the documented check-archive.sh script (see the FAQ and "Export Destinations" above). Filesystem and SFTP exports carry the same checkpoint in a .meta.json sidecar file; Azure Blob exports carry it as blob metadata.
  • Three new export destinations: a filesystem directory or mounted network share, an SFTP server (mandatory host-key verification), and Azure Blob Storage. An optional S3-compatible endpoint override also lets the existing S3 destination target GCS, MinIO, Cloudflare R2, Wasabi or on-prem Ceph.

Version 1.0.0

Initial Release

  • 35+ event types across 7 categories
  • SHA-256 tamper-evident checksums with hash chaining
  • SQLite local storage with WAL mode
  • Automated S3 export with date-based partitioning
  • NDJSON export format for SIEM compatibility
  • Server-side AES-256 encryption for S3 exports
  • Real-time audit dashboard
  • One-click chain integrity verification
  • Configurable event capture per category
  • License management with 72-hour grace period