Auditing
Audit logs provide a level of non-repudiation for the system. These logs are written to the container’s stdout, and cannot be disabled.
Each authenticated endpoint (both /token and /git-credentials) records details about the request, the authorization process, and the GitHub token created. Errors are also recorded.
Characteristics
Section titled “Characteristics”Requests to non-existent routes are not logged. Access logs or firewall logs are better sources for this traffic.
A panic in the request chain still results in the audit log being written. Panic details appear in the error field, and the panic propagates after the log is written.
HTTP error responses return generic messages like “Forbidden” to avoid leaking policy details to clients. Detailed error information is only available in audit logs. This prevents unauthorized users from learning about profile configurations or match conditions.
Log format
Section titled “Log format”Logs are written to stdout using zerolog at the “audit” log level. All audit logs are in single-line JSON format.
Related fields are grouped into nested JSON objects by concern: request, pipeline, authorization, and token. The request and authorization sections are always present. The pipeline and token sections are omitted when all their fields are empty — for example, when a request fails before JWT validation completes or before a token operation begins.
Fields
Section titled “Fields”Identifying fields
Section titled “Identifying fields”Always "audit".
message
Section titled “message”Always "audit_event".
request
Section titled “request”Always present.
method
Section titled “method”The HTTP request method. Currently always POST for authenticated endpoints.
The requested path (e.g., /token, /git-credentials, /organization/token/profile-name).
status
Section titled “status”The HTTP response status code.
sourceIP
Section titled “sourceIP”The client IP address and port.
userAgent
Section titled “userAgent”The user agent reported by the client.
pipeline
Section titled “pipeline”Present when Buildkite identity claims are available from the JWT. Omitted when JWT validation fails before claims can be extracted.
organizationSlug
Section titled “organizationSlug”The Buildkite organization slug.
pipelineSlug
Section titled “pipelineSlug”The pipeline slug.
The Buildkite job ID.
buildNumber
Section titled “buildNumber”The build number.
buildBranch
Section titled “buildBranch”The Git branch for the build.
authorization
Section titled “authorization”Always present. Contains JWT validation results.
authorized
Section titled “authorized”Boolean indicating whether the request JWT was successfully authorized.
subject
Section titled “subject”The contents of the sub field from the JWT.
issuer
Section titled “issuer”The JWT iss field.
audience
Section titled “audience”Array of aud field values from the JWT.
expiry
Section titled “expiry”The JWT expiry time as an RFC-3339 date-time string.
expiryRemaining
Section titled “expiryRemaining”The time the JWT will remain valid at the time of logging, in milliseconds.
Present when a token operation occurs (profile lookup, token creation, or match evaluation). Omitted when the request fails before reaching the token stage.
requestedProfile
Section titled “requestedProfile”The profile name requested. Omitted for pipeline-based requests without a profile.
requestedRepository
Section titled “requestedRepository”The repository URL supplied by the client. Present when using /git-credentials endpoints.
vendedRepository
Section titled “vendedRepository”The repository URL the token was vended for. Only present on successful token issuance.
repositories
Section titled “repositories”Array of repository URLs the token allows access to. Only present on successful token issuance.
permissions
Section titled “permissions”Object containing GitHub token permissions assigned to the token. Only present on successful token issuance.
expiry
Section titled “expiry”The GitHub token expiry time as an RFC-3339 date-time string. Only present on successful token issuance.
expiryRemaining
Section titled “expiryRemaining”The time the GitHub token will remain valid at the time of logging, in milliseconds. Only present on successful token issuance.
matches
Section titled “matches”Array of matched claim/value pairs on successful profile access. Each element contains claim and value fields.
attemptedPatterns
Section titled “attemptedPatterns”Array showing which condition failed on denied access. Each element contains claim, pattern, and value fields.
Top-level field. The error produced by the request. Only present when an error occurred. This may come from internal errors or panics, as well as JWT validation and token creation components.
HTTP error responses return generic messages like “Forbidden” to avoid leaking policy details to clients. Detailed error information is only available in audit logs.
Examples
Section titled “Examples”Pipeline-based token request
Section titled “Pipeline-based token request”{ "level": "audit", "request": { "method": "POST", "path": "/git-credentials", "status": 200, "sourceIP": "1.2.3.4:34340", "userAgent": "curl/8.3.0" }, "pipeline": { "organizationSlug": "example-org", "pipelineSlug": "example-repo", "jobID": "0184990a-477b-4fa8-9968-496074483cee", "buildNumber": 42, "buildBranch": "feature-branch" }, "authorization": { "authorized": true, "subject": "organization:example-org:pipeline:example-repo:ref:refs/heads/feature-branch:commit:40631gitcommithash8b3:step:step-name-from-pipeline", "issuer": "https://agent.buildkite.com", "audience": ["github-app-auth:example-org"], "expiry": "2025-01-20T04:52:58Z", "expiryRemaining": 299372 }, "token": { "repositories": ["https://github.com/example-org/example-repo.git"], "permissions": ["contents:read"], "expiry": "2025-01-20T05:09:45Z", "expiryRemaining": 1306372 }, "type": "audit", "time": "2025-01-20T04:47:00Z", "message": "audit_event"}Successful organization profile access
Section titled “Successful organization profile access”{ "level": "audit", "request": { "method": "POST", "path": "/organization/token/release-publisher", "status": 200, "sourceIP": "1.2.3.4:34340", "userAgent": "curl/8.3.0" }, "pipeline": { "organizationSlug": "example-org", "pipelineSlug": "silk-release", "jobID": "0184990a-477b-4fa8-9968-496074483cee", "buildNumber": 7, "buildBranch": "main" }, "authorization": { "authorized": true, "subject": "organization:example-org:pipeline:silk-release:ref:refs/heads/main:commit:abc123:step:publish", "issuer": "https://agent.buildkite.com", "audience": ["github-app-auth:example-org"] }, "token": { "requestedProfile": "release-publisher", "matches": [ { "claim": "pipeline_slug", "value": "silk-release" }, { "claim": "build_branch", "value": "main" } ], "repositories": ["https://github.com/example-org/release-tools.git"], "permissions": ["contents:write", "packages:write"], "expiry": "2025-01-20T05:09:45Z", "expiryRemaining": 1306372 }, "type": "audit", "time": "2025-01-20T04:47:00Z", "message": "audit_event"}Denied profile access (match failed)
Section titled “Denied profile access (match failed)”{ "level": "audit", "request": { "method": "POST", "path": "/organization/token/release-publisher", "status": 403, "sourceIP": "1.2.3.4:34340", "userAgent": "curl/8.3.0" }, "pipeline": { "organizationSlug": "example-org", "pipelineSlug": "silk-staging", "jobID": "0184990a-477b-4fa8-9968-496074483cee", "buildNumber": 15, "buildBranch": "main" }, "authorization": { "authorized": true, "subject": "organization:example-org:pipeline:silk-staging:ref:refs/heads/main:commit:abc123:step:publish", "issuer": "https://agent.buildkite.com", "audience": ["github-app-auth:example-org"] }, "token": { "requestedProfile": "release-publisher", "attemptedPatterns": [ { "claim": "pipeline_slug", "pattern": ".*-release", "value": "silk-staging" } ] }, "error": "profile match conditions not met", "type": "audit", "time": "2025-01-20T04:47:00Z", "message": "audit_event"}