mirror of
https://dev.azure.com/schwarzit/schwarzit.stackit-public/_git/audit-go
synced 2026-02-08 00:57:24 +00:00
658 lines
23 KiB
Go
658 lines
23 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/utils"
|
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/google/uuid"
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/trace"
|
|
"time"
|
|
)
|
|
|
|
const quadZero = "0.0.0.0"
|
|
|
|
type SequenceNumber uint64
|
|
|
|
type AuditParameters struct {
|
|
|
|
// A map that is added as "details" to the message
|
|
Details map[string]interface{}
|
|
|
|
// The type of the event
|
|
EventType EventType
|
|
|
|
// A set of user-defined (key, value) data that provides additional
|
|
// information about the log entry.
|
|
Labels map[string]string
|
|
|
|
// UUID identifier of the object, the audit event refers to
|
|
ObjectId string
|
|
|
|
// Type of the object, the audit event refers to
|
|
ObjectType ObjectType
|
|
|
|
ResponseBody any
|
|
|
|
// Log severity
|
|
Severity auditV1.LogSeverity
|
|
}
|
|
|
|
func getObjectIdAndTypeFromAuditParams(
|
|
auditParams *AuditParameters,
|
|
) (string, *ObjectType, error) {
|
|
|
|
objectId := auditParams.ObjectId
|
|
if objectId == "" {
|
|
return "", nil, errors.New("object id missing")
|
|
}
|
|
|
|
var objectType *ObjectType
|
|
if auditParams.ObjectType != "" {
|
|
objectType = &auditParams.ObjectType
|
|
}
|
|
|
|
if objectType == nil {
|
|
return "", nil, errors.New("object type missing")
|
|
}
|
|
if err := objectType.IsSupportedType(); err != nil {
|
|
return "", nil, err
|
|
}
|
|
return objectId, objectType, nil
|
|
}
|
|
|
|
// AuditLogEntryBuilder collects audit params to construct auditV1.AuditLogEntry
|
|
type AuditLogEntryBuilder struct {
|
|
auditParams AuditParameters
|
|
auditRequest AuditRequest
|
|
auditResponse AuditResponse
|
|
auditMetadata AuditMetadata
|
|
|
|
// Region and optional zone id. If both, separated with a - (dash).
|
|
// Example: eu01
|
|
location string
|
|
|
|
// Opentelemetry tracer
|
|
tracer trace.Tracer
|
|
|
|
// The ID of the K8s Pod, Service-Instance, etc. (must be unique for a sending service)
|
|
workerId string
|
|
}
|
|
|
|
// NewAuditLogEntryBuilder returns a builder to construct auditV1.AuditLogEntry
|
|
func NewAuditLogEntryBuilder() *AuditLogEntryBuilder {
|
|
|
|
requestTime := time.Now().UTC()
|
|
|
|
return &AuditLogEntryBuilder{
|
|
auditParams: AuditParameters{
|
|
EventType: EventTypeAdminActivity,
|
|
},
|
|
auditRequest: AuditRequest{
|
|
Request: &ApiRequest{},
|
|
RequestClientIP: quadZero,
|
|
RequestCorrelationId: nil,
|
|
RequestId: nil,
|
|
RequestTime: &requestTime,
|
|
},
|
|
auditResponse: AuditResponse{
|
|
ResponseBodyBytes: nil,
|
|
ResponseStatusCode: 200,
|
|
ResponseHeaders: make(map[string][]string),
|
|
ResponseNumItems: nil,
|
|
ResponseTime: nil,
|
|
},
|
|
auditMetadata: AuditMetadata{
|
|
AuditInsertId: "",
|
|
AuditLabels: nil,
|
|
AuditLogName: "",
|
|
AuditLogSeverity: auditV1.LogSeverity_LOG_SEVERITY_DEFAULT,
|
|
AuditOperationName: "",
|
|
AuditPermission: nil,
|
|
AuditPermissionGranted: nil,
|
|
AuditResourceName: "",
|
|
AuditServiceName: "",
|
|
AuditTime: nil,
|
|
},
|
|
location: "",
|
|
tracer: otel.Tracer("audit-log-entry-builder"),
|
|
workerId: "",
|
|
}
|
|
}
|
|
|
|
func (builder *AuditLogEntryBuilder) AsSystemEvent() *AuditLogEntryBuilder {
|
|
if builder.auditRequest.Request == nil {
|
|
builder.auditRequest.Request = &ApiRequest{}
|
|
}
|
|
if builder.auditRequest.Request.Header == nil {
|
|
builder.auditRequest.Request.Header = map[string][]string{"user-agent": {"none"}}
|
|
}
|
|
if builder.auditRequest.Request.Host == "" {
|
|
builder.auditRequest.Request.Host = quadZero
|
|
}
|
|
if builder.auditRequest.Request.Method == "" {
|
|
builder.auditRequest.Request.Method = "OTHER"
|
|
}
|
|
if builder.auditRequest.Request.Scheme == "" {
|
|
builder.auditRequest.Request.Scheme = "none"
|
|
}
|
|
if builder.auditRequest.Request.Proto == "" {
|
|
builder.auditRequest.Request.Proto = "none"
|
|
}
|
|
if builder.auditRequest.Request.URL.Path == "" {
|
|
builder.auditRequest.Request.URL.Path = "none"
|
|
}
|
|
if builder.auditRequest.RequestClientIP == "" {
|
|
builder.auditRequest.RequestClientIP = quadZero
|
|
}
|
|
builder.WithEventType(EventTypeSystemEvent)
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredApiRequest adds api request details
|
|
func (builder *AuditLogEntryBuilder) WithRequiredApiRequest(request ApiRequest) *AuditLogEntryBuilder {
|
|
builder.auditRequest.Request = &request
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredLocation adds the region and optional zone id. If both, separated with a - (dash).
|
|
// Example: eu01
|
|
func (builder *AuditLogEntryBuilder) WithRequiredLocation(location string) *AuditLogEntryBuilder {
|
|
builder.location = location
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredRequestClientIp adds the client ip
|
|
func (builder *AuditLogEntryBuilder) WithRequiredRequestClientIp(requestClientIp string) *AuditLogEntryBuilder {
|
|
builder.auditRequest.RequestClientIP = requestClientIp
|
|
return builder
|
|
}
|
|
|
|
// WithRequestCorrelationId adds an optional request correlation id
|
|
func (builder *AuditLogEntryBuilder) WithRequestCorrelationId(requestCorrelationId string) *AuditLogEntryBuilder {
|
|
builder.auditRequest.RequestCorrelationId = &requestCorrelationId
|
|
return builder
|
|
}
|
|
|
|
// WithRequestId adds an optional request id
|
|
func (builder *AuditLogEntryBuilder) WithRequestId(requestId string) *AuditLogEntryBuilder {
|
|
builder.auditRequest.RequestId = &requestId
|
|
return builder
|
|
}
|
|
|
|
// WithRequestTime sets the request time on the builder. If not set - the instantiation time of the builder is used.
|
|
func (builder *AuditLogEntryBuilder) WithRequestTime(requestTime time.Time) *AuditLogEntryBuilder {
|
|
builder.auditRequest.RequestTime = &requestTime
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredServiceName adds the service name in lowercase (allowed characters are [a-z-]).
|
|
func (builder *AuditLogEntryBuilder) WithRequiredServiceName(serviceName string) *AuditLogEntryBuilder {
|
|
builder.auditMetadata.AuditServiceName = serviceName
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredWorkerId adds the ID of the K8s Pod, Service-Instance, etc. (must be unique for a sending service)
|
|
func (builder *AuditLogEntryBuilder) WithRequiredWorkerId(workerId string) *AuditLogEntryBuilder {
|
|
builder.workerId = workerId
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredObjectId adds the object identifier.
|
|
// May be prefilled by audit middleware (if the identifier can be extracted from the url path).
|
|
func (builder *AuditLogEntryBuilder) WithRequiredObjectId(objectId string) *AuditLogEntryBuilder {
|
|
builder.auditParams.ObjectId = objectId
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredObjectType adds the object type.
|
|
// May be prefilled by audit middleware (if the type can be extracted from the url path).
|
|
func (builder *AuditLogEntryBuilder) WithRequiredObjectType(objectType ObjectType) *AuditLogEntryBuilder {
|
|
builder.auditParams.ObjectType = objectType
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredOperation adds the name of the service method or operation.
|
|
//
|
|
// Format: stackit.<product>.<version>.<type-chain>.<operation>
|
|
// Where:
|
|
//
|
|
// Product: The name of the service in lowercase
|
|
// Version: Optional API version
|
|
// Type-Chain: Chained path to object
|
|
// Operation: The name of the operation in lowercase
|
|
//
|
|
// Examples:
|
|
//
|
|
// "stackit.resource-manager.v1.organizations.create"
|
|
// "stackit.authorization.v1.projects.volumes.create"
|
|
// "stackit.authorization.v2alpha.projects.volumes.create"
|
|
// "stackit.authorization.v2.folders.move"
|
|
// "stackit.resource-manager.health"
|
|
func (builder *AuditLogEntryBuilder) WithRequiredOperation(operation string) *AuditLogEntryBuilder {
|
|
builder.auditMetadata.AuditOperationName = operation
|
|
return builder
|
|
}
|
|
|
|
// WithAuditPermission adds the IAM permission
|
|
//
|
|
// Examples:
|
|
//
|
|
// "resourcemanager.project.edit"
|
|
func (builder *AuditLogEntryBuilder) WithAuditPermission(permission string) *AuditLogEntryBuilder {
|
|
builder.auditMetadata.AuditPermission = &permission
|
|
return builder
|
|
}
|
|
|
|
// WithAuditPermissionCheckResult adds the IAM permission check result
|
|
func (builder *AuditLogEntryBuilder) WithAuditPermissionCheckResult(permissionCheckResult bool) *AuditLogEntryBuilder {
|
|
builder.auditMetadata.AuditPermissionGranted = &permissionCheckResult
|
|
return builder
|
|
}
|
|
|
|
// WithLabels adds A set of user-defined (key, value) data that provides additional
|
|
// information about the log entry.
|
|
func (builder *AuditLogEntryBuilder) WithLabels(labels map[string]string) *AuditLogEntryBuilder {
|
|
builder.auditMetadata.AuditLabels = &labels
|
|
return builder
|
|
}
|
|
|
|
// WithNumResponseItems adds the number of items returned to the client if applicable.
|
|
func (builder *AuditLogEntryBuilder) WithNumResponseItems(numResponseItems int64) *AuditLogEntryBuilder {
|
|
builder.auditResponse.ResponseNumItems = &numResponseItems
|
|
return builder
|
|
}
|
|
|
|
// WithEventType overwrites the default event type EventTypeAdminActivity
|
|
func (builder *AuditLogEntryBuilder) WithEventType(eventType EventType) *AuditLogEntryBuilder {
|
|
builder.auditParams.EventType = eventType
|
|
return builder
|
|
}
|
|
|
|
// WithDetails adds an optional details object to the audit log entry
|
|
func (builder *AuditLogEntryBuilder) WithDetails(details map[string]interface{}) *AuditLogEntryBuilder {
|
|
builder.auditParams.Details = details
|
|
return builder
|
|
}
|
|
|
|
// WithSeverity overwrites the default log severity level auditV1.LogSeverity_LOG_SEVERITY_DEFAULT
|
|
func (builder *AuditLogEntryBuilder) WithSeverity(severity auditV1.LogSeverity) *AuditLogEntryBuilder {
|
|
builder.auditMetadata.AuditLogSeverity = severity
|
|
return builder
|
|
}
|
|
|
|
// WithStatusCode adds the (http) response status code
|
|
func (builder *AuditLogEntryBuilder) WithStatusCode(statusCode int) *AuditLogEntryBuilder {
|
|
builder.auditResponse.ResponseStatusCode = statusCode
|
|
return builder
|
|
}
|
|
|
|
// WithResponseBody adds the response body to the builder and transforms it in the Build method (json serializable or protobuf message expected)
|
|
func (builder *AuditLogEntryBuilder) WithResponseBody(responseBody any) *AuditLogEntryBuilder {
|
|
builder.auditParams.ResponseBody = responseBody
|
|
return builder
|
|
}
|
|
|
|
// WithResponseBodyBytes adds the response body as bytes (serialized json or protobuf message expected)
|
|
func (builder *AuditLogEntryBuilder) WithResponseBodyBytes(responseBody *[]byte) *AuditLogEntryBuilder {
|
|
builder.auditResponse.ResponseBodyBytes = responseBody
|
|
return builder
|
|
}
|
|
|
|
// WithResponseHeaders adds response headers
|
|
func (builder *AuditLogEntryBuilder) WithResponseHeaders(responseHeaders map[string][]string) *AuditLogEntryBuilder {
|
|
builder.auditResponse.ResponseHeaders = responseHeaders
|
|
return builder
|
|
}
|
|
|
|
// WithResponseTime adds the time when the response is sent
|
|
func (builder *AuditLogEntryBuilder) WithResponseTime(responseTime time.Time) *AuditLogEntryBuilder {
|
|
builder.auditResponse.ResponseTime = &responseTime
|
|
return builder
|
|
}
|
|
|
|
// Build constructs the auditV1.AuditLogEntry.
|
|
//
|
|
// Parameters:
|
|
// - A context object
|
|
// - A SequenceNumber
|
|
//
|
|
// Returns:
|
|
// - The auditV1.AuditLogEntry protobuf message or
|
|
// - Error if the entry cannot be built
|
|
func (builder *AuditLogEntryBuilder) Build(ctx context.Context, sequenceNumber SequenceNumber) (*auditV1.AuditLogEntry, error) {
|
|
_, span := builder.tracer.Start(ctx, "build-audit-log-entry")
|
|
defer span.End()
|
|
|
|
auditTime := time.Now()
|
|
builder.auditMetadata.AuditTime = &auditTime
|
|
|
|
objectId, objectType, err := getObjectIdAndTypeFromAuditParams(&builder.auditParams)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if builder.auditResponse.ResponseBodyBytes != nil && builder.auditParams.ResponseBody != nil {
|
|
return nil, errors.New("responseBodyBytes and responseBody set")
|
|
} else if builder.auditParams.ResponseBody != nil {
|
|
responseBytes, err := ResponseBodyToBytes(builder.auditParams.ResponseBody)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
builder.auditResponse.ResponseBodyBytes = responseBytes
|
|
}
|
|
|
|
resourceName := fmt.Sprintf("%s/%s", objectType.Plural(), objectId)
|
|
var logIdentifier string
|
|
var logType ObjectType
|
|
if builder.auditParams.EventType == EventTypeSystemEvent {
|
|
logIdentifier = SystemIdentifier.Identifier
|
|
logType = ObjectTypeSystem
|
|
} else {
|
|
logIdentifier = objectId
|
|
logType = *objectType
|
|
}
|
|
|
|
builder.auditMetadata.AuditInsertId = NewInsertId(time.Now().UTC(), builder.location, builder.workerId, uint64(sequenceNumber))
|
|
builder.auditMetadata.AuditLogName = fmt.Sprintf("%s/%s/logs/%s", logType.Plural(), logIdentifier, builder.auditParams.EventType)
|
|
builder.auditMetadata.AuditResourceName = resourceName
|
|
|
|
var details *map[string]interface{} = nil
|
|
if len(builder.auditParams.Details) > 0 {
|
|
details = &builder.auditParams.Details
|
|
}
|
|
|
|
// Instantiate the audit event
|
|
return NewAuditLogEntry(
|
|
builder.auditRequest,
|
|
builder.auditResponse,
|
|
details,
|
|
builder.auditMetadata,
|
|
)
|
|
}
|
|
|
|
// AuditEventBuilder collects audit log parameters, validates input and
|
|
// returns a cloud event that can be sent to the audit log system.
|
|
type AuditEventBuilder struct {
|
|
|
|
// The audit api used to validate, serialize and send events
|
|
api *AuditApi
|
|
|
|
// The audit log entry builder which is used to build the actual protobuf message
|
|
auditLogEntryBuilder *AuditLogEntryBuilder
|
|
|
|
// Status whether the event has been built
|
|
built bool
|
|
|
|
// Sequence number generator providing sequential increasing numbers for the insert IDs
|
|
sequenceNumberGenerator *utils.SequenceNumberGenerator
|
|
|
|
// Opentelemetry tracer
|
|
tracer trace.Tracer
|
|
|
|
// Visibility of the event
|
|
visibility auditV1.Visibility
|
|
}
|
|
|
|
// NewAuditEventBuilder returns a builder that collects audit log parameters,
|
|
// validates input and returns a cloud event that can be sent to the audit log system.
|
|
func NewAuditEventBuilder(
|
|
// The audit api used to validate, serialize and send events
|
|
api *AuditApi,
|
|
|
|
// The sequence number generator can be used to get and revert sequence numbers to build audit log events
|
|
sequenceNumberGenerator *utils.SequenceNumberGenerator,
|
|
|
|
// The service name in lowercase (allowed characters are [a-z-]).
|
|
serviceName string,
|
|
|
|
// The ID of the K8s Pod, Service-Instance, etc. (must be unique for a sending service)
|
|
workerId string,
|
|
|
|
// The location of the service (e.g. eu01)
|
|
location string,
|
|
) *AuditEventBuilder {
|
|
return &AuditEventBuilder{
|
|
api: api,
|
|
auditLogEntryBuilder: NewAuditLogEntryBuilder().
|
|
WithRequiredServiceName(serviceName).
|
|
WithRequiredWorkerId(workerId).
|
|
WithRequiredLocation(location),
|
|
sequenceNumberGenerator: sequenceNumberGenerator,
|
|
tracer: otel.Tracer("audit-event-builder"),
|
|
visibility: auditV1.Visibility_VISIBILITY_PUBLIC,
|
|
}
|
|
}
|
|
|
|
// NextSequenceNumber returns the next sequence number from utils.SequenceNumberGenerator.
|
|
// In case of an error RevertSequenceNumber must be called to prevent gaps in the sequence of numbers.
|
|
func (builder *AuditEventBuilder) NextSequenceNumber() SequenceNumber {
|
|
return SequenceNumber((*builder.sequenceNumberGenerator).Next())
|
|
}
|
|
|
|
// RevertSequenceNumber can be called to decrease the sequence number on the utils.SequenceNumberGenerator in case of an error
|
|
func (builder *AuditEventBuilder) RevertSequenceNumber() {
|
|
(*builder.sequenceNumberGenerator).Revert()
|
|
}
|
|
|
|
func (builder *AuditEventBuilder) AsSystemEvent() *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.AsSystemEvent()
|
|
builder.WithVisibility(auditV1.Visibility_VISIBILITY_PRIVATE)
|
|
return builder
|
|
}
|
|
|
|
// WithAuditLogEntryBuilder overwrites the preconfigured AuditLogEntryBuilder
|
|
func (builder *AuditEventBuilder) WithAuditLogEntryBuilder(auditLogEntryBuilder *AuditLogEntryBuilder) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder = auditLogEntryBuilder
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredApiRequest adds api request details
|
|
func (builder *AuditEventBuilder) WithRequiredApiRequest(request ApiRequest) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithRequiredApiRequest(request)
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredRequestClientIp adds the client ip
|
|
func (builder *AuditEventBuilder) WithRequiredRequestClientIp(requestClientIp string) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithRequiredRequestClientIp(requestClientIp)
|
|
return builder
|
|
}
|
|
|
|
// WithRequestCorrelationId adds an optional request correlation id
|
|
func (builder *AuditEventBuilder) WithRequestCorrelationId(requestCorrelationId string) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithRequestCorrelationId(requestCorrelationId)
|
|
return builder
|
|
}
|
|
|
|
// WithRequestId adds an optional request id
|
|
func (builder *AuditEventBuilder) WithRequestId(requestId string) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithRequestId(requestId)
|
|
return builder
|
|
}
|
|
|
|
// WithRequestTime sets the request time on the builder. If not set - the instantiation time of the builder is used.
|
|
func (builder *AuditEventBuilder) WithRequestTime(requestTime time.Time) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithRequestTime(requestTime)
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredObjectId adds the object identifier.
|
|
// May be prefilled by audit middleware (if the identifier can be extracted from the url path).
|
|
func (builder *AuditEventBuilder) WithRequiredObjectId(objectId string) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithRequiredObjectId(objectId)
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredObjectType adds the object type.
|
|
// May be prefilled by audit middleware (if the type can be extracted from the url path).
|
|
func (builder *AuditEventBuilder) WithRequiredObjectType(objectType ObjectType) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithRequiredObjectType(objectType)
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredOperation adds the name of the service method or operation.
|
|
//
|
|
// Format: stackit.<product>.<version>.<type-chain>.<operation>
|
|
// Where:
|
|
//
|
|
// Product: The name of the service in lowercase
|
|
// Version: Optional API version
|
|
// Type-Chain: Chained path to object
|
|
// Operation: The name of the operation in lowercase
|
|
//
|
|
// Examples:
|
|
//
|
|
// "stackit.resource-manager.v1.organizations.create"
|
|
// "stackit.authorization.v1.projects.volumes.create"
|
|
// "stackit.authorization.v2alpha.projects.volumes.create"
|
|
// "stackit.authorization.v2.folders.move"
|
|
// "stackit.resource-manager.health"
|
|
func (builder *AuditEventBuilder) WithRequiredOperation(operation string) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.auditMetadata.AuditOperationName = operation
|
|
return builder
|
|
}
|
|
|
|
// WithAuditPermission adds the IAM permission
|
|
//
|
|
// Examples:
|
|
//
|
|
// "resourcemanager.project.edit"
|
|
func (builder *AuditEventBuilder) WithAuditPermission(permission string) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithAuditPermission(permission)
|
|
return builder
|
|
}
|
|
|
|
// WithAuditPermissionCheckResult adds the IAM permission check result
|
|
func (builder *AuditEventBuilder) WithAuditPermissionCheckResult(permissionCheckResult bool) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithAuditPermissionCheckResult(permissionCheckResult)
|
|
return builder
|
|
}
|
|
|
|
// WithLabels adds A set of user-defined (key, value) data that provides additional
|
|
// information about the log entry.
|
|
func (builder *AuditEventBuilder) WithLabels(labels map[string]string) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithLabels(labels)
|
|
return builder
|
|
}
|
|
|
|
// WithNumResponseItems adds the number of items returned to the client if applicable.
|
|
func (builder *AuditEventBuilder) WithNumResponseItems(numResponseItems int64) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithNumResponseItems(numResponseItems)
|
|
return builder
|
|
}
|
|
|
|
// WithEventType overwrites the default event type EventTypeAdminActivity
|
|
func (builder *AuditEventBuilder) WithEventType(eventType EventType) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithEventType(eventType)
|
|
return builder
|
|
}
|
|
|
|
// WithDetails adds an optional details object to the audit log entry
|
|
func (builder *AuditEventBuilder) WithDetails(details map[string]interface{}) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithDetails(details)
|
|
return builder
|
|
}
|
|
|
|
// WithSeverity overwrites the default log severity level auditV1.LogSeverity_LOG_SEVERITY_DEFAULT
|
|
func (builder *AuditEventBuilder) WithSeverity(severity auditV1.LogSeverity) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithSeverity(severity)
|
|
return builder
|
|
}
|
|
|
|
// WithStatusCode adds the (http) response status code
|
|
func (builder *AuditEventBuilder) WithStatusCode(statusCode int) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithStatusCode(statusCode)
|
|
return builder
|
|
}
|
|
|
|
// WithResponseBody adds the response body to the builder and transforms it in the Build method (json serializable or protobuf message expected)
|
|
func (builder *AuditEventBuilder) WithResponseBody(responseBody any) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithResponseBody(responseBody)
|
|
return builder
|
|
}
|
|
|
|
// WithResponseBodyBytes adds the response body as bytes (serialized json or protobuf message expected)
|
|
func (builder *AuditEventBuilder) WithResponseBodyBytes(responseBody *[]byte) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithResponseBodyBytes(responseBody)
|
|
return builder
|
|
}
|
|
|
|
// WithResponseHeaders adds response headers
|
|
func (builder *AuditEventBuilder) WithResponseHeaders(responseHeaders map[string][]string) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithResponseHeaders(responseHeaders)
|
|
return builder
|
|
}
|
|
|
|
// WithResponseTime adds the time when the response is sent
|
|
func (builder *AuditEventBuilder) WithResponseTime(responseTime time.Time) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithResponseTime(responseTime)
|
|
return builder
|
|
}
|
|
|
|
// WithVisibility overwrites the default visibility auditV1.Visibility_VISIBILITY_PUBLIC
|
|
func (builder *AuditEventBuilder) WithVisibility(visibility auditV1.Visibility) *AuditEventBuilder {
|
|
builder.visibility = visibility
|
|
return builder
|
|
}
|
|
|
|
// IsBuilt returns the status whether the cloud event has been built
|
|
func (builder *AuditEventBuilder) IsBuilt() bool {
|
|
return builder.built
|
|
}
|
|
|
|
// Build constructs the CloudEvent.
|
|
//
|
|
// Parameters:
|
|
// - A context object
|
|
// - A sequence number. AuditEventBuilder.NextSequenceNumber can be used to get the next SequenceNumber.
|
|
//
|
|
// Returns:
|
|
// - The CloudEvent containing the audit log entry
|
|
// - The RoutableIdentifier required for routing the cloud event
|
|
// - The operation name
|
|
// - Error if the event cannot be built
|
|
func (builder *AuditEventBuilder) Build(ctx context.Context, sequenceNumber SequenceNumber) (*CloudEvent, *RoutableIdentifier, error) {
|
|
if builder.auditLogEntryBuilder == nil {
|
|
return nil, nil, fmt.Errorf("audit log entry builder not set")
|
|
}
|
|
|
|
ctx, span := builder.tracer.Start(ctx, "build-audit-event")
|
|
defer span.End()
|
|
|
|
visibility := builder.visibility
|
|
objectId := builder.auditLogEntryBuilder.auditParams.ObjectId
|
|
objectType := builder.auditLogEntryBuilder.auditParams.ObjectType
|
|
var routingIdentifier *RoutableIdentifier
|
|
if builder.auditLogEntryBuilder.auditParams.EventType == EventTypeSystemEvent {
|
|
routingIdentifier = NewAuditRoutingIdentifier(uuid.Nil.String(), ObjectTypeSystem)
|
|
if objectId == "" {
|
|
objectId = uuid.Nil.String()
|
|
builder.WithRequiredObjectId(objectId)
|
|
}
|
|
if objectType == "" {
|
|
objectType = ObjectTypeSystem
|
|
builder.WithRequiredObjectType(objectType)
|
|
}
|
|
} else {
|
|
routingIdentifier = NewAuditRoutingIdentifier(objectId, objectType)
|
|
}
|
|
|
|
auditLogEntry, err := builder.auditLogEntryBuilder.Build(ctx, sequenceNumber)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Validate and serialize the protobuf event into a cloud event
|
|
cloudEvent, err := (*builder.api).ValidateAndSerialize(ctx, auditLogEntry, visibility, routingIdentifier)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
builder.built = true
|
|
return cloudEvent,
|
|
routingIdentifier,
|
|
nil
|
|
}
|