mirror of
https://dev.azure.com/schwarzit/schwarzit.stackit-public/_git/audit-go
synced 2026-02-07 16:47:24 +00:00
Makes the request body accessible and modifiable in the audit event builder to enable SDK users to hide secrets in request bodies captured in the request body (by middlewares). Also updates dependencies. Security-concept-update-needed: false. JIRA Work Item: STACKITALO-284
683 lines
24 KiB
Go
683 lines
24 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/trace"
|
|
|
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
|
pkgAuditUtils "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/utils"
|
|
)
|
|
|
|
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 pkgAuditCommon.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 pkgAuditCommon.ObjectType
|
|
|
|
ResponseBody any
|
|
|
|
// Log severity
|
|
Severity auditV1.LogSeverity
|
|
}
|
|
|
|
func getObjectIdAndTypeFromAuditParams(
|
|
auditParams *AuditParameters,
|
|
) (string, *pkgAuditCommon.ObjectType, error) {
|
|
|
|
objectId := auditParams.ObjectId
|
|
if objectId == "" {
|
|
return "", nil, errors.New("object id missing")
|
|
}
|
|
|
|
var objectType *pkgAuditCommon.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 internalAuditApi.AuditRequest
|
|
auditResponse internalAuditApi.AuditResponse
|
|
auditMetadata internalAuditApi.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: pkgAuditCommon.EventTypeAdminActivity,
|
|
},
|
|
auditRequest: internalAuditApi.AuditRequest{
|
|
Request: &pkgAuditCommon.ApiRequest{},
|
|
RequestClientIP: quadZero,
|
|
RequestCorrelationId: nil,
|
|
RequestId: nil,
|
|
RequestTime: &requestTime,
|
|
},
|
|
auditResponse: internalAuditApi.AuditResponse{
|
|
ResponseBodyBytes: nil,
|
|
ResponseStatusCode: 200,
|
|
ResponseHeaders: make(map[string][]string),
|
|
ResponseNumItems: nil,
|
|
ResponseTime: nil,
|
|
},
|
|
auditMetadata: internalAuditApi.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 = &pkgAuditCommon.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(pkgAuditCommon.EventTypeSystemEvent)
|
|
return builder
|
|
}
|
|
|
|
// WithRequiredApiRequest adds api request details
|
|
func (builder *AuditLogEntryBuilder) WithRequiredApiRequest(request pkgAuditCommon.ApiRequest) *AuditLogEntryBuilder {
|
|
builder.auditRequest.Request = &request
|
|
return builder
|
|
}
|
|
|
|
// GetApiRequest returns the api request details
|
|
func (builder *AuditLogEntryBuilder) GetApiRequest() *pkgAuditCommon.ApiRequest {
|
|
return builder.auditRequest.Request
|
|
}
|
|
|
|
func (builder *AuditLogEntryBuilder) GetApiRequestBody() *pkgAuditCommon.ApiRequest {
|
|
return builder.auditRequest.Request
|
|
}
|
|
|
|
// 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 pkgAuditCommon.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 pkgAuditCommon.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 pkgAuditCommon.ObjectType
|
|
if builder.auditParams.EventType == pkgAuditCommon.EventTypeSystemEvent {
|
|
logIdentifier = pkgAuditCommon.SystemIdentifier.Identifier
|
|
logType = pkgAuditCommon.ObjectTypeSystem
|
|
} else {
|
|
logIdentifier = objectId
|
|
logType = *objectType
|
|
}
|
|
|
|
builder.auditMetadata.AuditInsertId = internalAuditApi.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{}
|
|
if len(builder.auditParams.Details) > 0 {
|
|
details = builder.auditParams.Details
|
|
}
|
|
|
|
// Instantiate the audit event
|
|
return internalAuditApi.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 pkgAuditCommon.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 pkgAuditUtils.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 pkgAuditCommon.AuditApi,
|
|
|
|
// The sequence number generator can be used to get and revert sequence numbers to build audit log events
|
|
sequenceNumberGenerator pkgAuditUtils.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(number SequenceNumber) {
|
|
builder.sequenceNumberGenerator.Revert(uint64(number))
|
|
}
|
|
|
|
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 pkgAuditCommon.ApiRequest) *AuditEventBuilder {
|
|
builder.auditLogEntryBuilder.WithRequiredApiRequest(request)
|
|
return builder
|
|
}
|
|
|
|
// GetApiRequest returns the api request details
|
|
func (builder *AuditEventBuilder) GetApiRequest() *pkgAuditCommon.ApiRequest {
|
|
return builder.auditLogEntryBuilder.GetApiRequest()
|
|
}
|
|
|
|
// 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 pkgAuditCommon.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 pkgAuditCommon.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
|
|
}
|
|
|
|
// MarkAsBuilt sets the internal built flag to true.
|
|
// This is useful in middlewares where the IsBuilt method is used
|
|
// to check if an event has been constructed.
|
|
func (builder *AuditEventBuilder) MarkAsBuilt() {
|
|
builder.built = true
|
|
}
|
|
|
|
// 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) (*pkgAuditCommon.CloudEvent, *pkgAuditCommon.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 *pkgAuditCommon.RoutableIdentifier
|
|
if builder.auditLogEntryBuilder.auditParams.EventType == pkgAuditCommon.EventTypeSystemEvent {
|
|
routingIdentifier = internalAuditApi.NewAuditRoutingIdentifier(uuid.Nil.String(), pkgAuditCommon.ObjectTypeSystem)
|
|
if objectId == "" {
|
|
objectId = uuid.Nil.String()
|
|
builder.WithRequiredObjectId(objectId)
|
|
}
|
|
if objectType == "" {
|
|
objectType = pkgAuditCommon.ObjectTypeSystem
|
|
builder.WithRequiredObjectType(objectType)
|
|
}
|
|
} else {
|
|
routingIdentifier = internalAuditApi.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
|
|
}
|