Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

base types for events package #1275

Merged
merged 10 commits into from
Jun 6, 2021
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/hashicorp/cap v0.0.0-20210518163718-e72205e8eaae
github.com/hashicorp/dbassert v0.0.0-20200930125617-6218396928df
github.com/hashicorp/errwrap v1.1.0
github.com/hashicorp/eventlogger v0.0.0-20210523164657-c216620e1746
github.com/hashicorp/go-bexpr v0.1.7
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/go-hclog v0.16.1
Expand Down
8 changes: 7 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,9 @@ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gG
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw=
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
Expand Down Expand Up @@ -449,6 +450,8 @@ github.com/hashicorp/dbassert v0.0.0-20200930125617-6218396928df/go.mod h1:+B5eZ
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/eventlogger v0.0.0-20210523164657-c216620e1746 h1:uFLAYWBCufq4idhqjltAWb4s2JuJt1oE1hDRixwWqwY=
github.com/hashicorp/eventlogger v0.0.0-20210523164657-c216620e1746/go.mod h1:LG0lqGlYKC9FD5m5Umh7FW8SeJlciNUZv400J4+j094=
github.com/hashicorp/go-bexpr v0.1.7 h1:z48qzCgJkvdnMO/LDy3XHNyCyxnHiFGx9uTKLv0jW2Y=
github.com/hashicorp/go-bexpr v0.1.7/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
Expand Down Expand Up @@ -984,6 +987,8 @@ go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo=
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
Expand Down Expand Up @@ -1232,6 +1237,7 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
Expand Down
51 changes: 51 additions & 0 deletions internal/observability/events/event.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package event
jimlambrt marked this conversation as resolved.
Show resolved Hide resolved

import "google.golang.org/protobuf/proto"

type (
Id string
Op string
)

// RequestInfo defines the fields captured about a Boundary request.
type RequestInfo struct {
Id string `json:"id,omitempty"`
Method string `json:"method,omitempty"`
Path string `json:"path,omitempty"`
PublicId string `json:"public_id,omitempty"`
}

// UserInfo defines the fields captured about a user for a Boundary request.
jimlambrt marked this conversation as resolved.
Show resolved Hide resolved
type UserInfo struct {
UserId string `json:"id,omitempty"`
AuthAccountId string `json:"auth_account_id,omitempty"`
}

type GrantsInfo struct {
Grants []GrantsPair `json:"grants_pair,omitempty"`
}

type GrantsPair struct {
Grant string `json:"grant,omitempty"`
ScopeId string `json:"scope_id,omitempty"`
}

type Auth struct {
// AccessorId is a std audit field == auth_token public_id
AccessorId string `json:"accessor_id"`
UserInfo *UserInfo `json:"user_info,omitempty"` // boundary field
GrantsInfo *GrantsInfo `json:"grants_info,omitempty"`
UserEmail string `json:"email,omitempty"`
UserName string `json:"name,omitempty"`
}

type Request struct {
Operation string `json:"operation"` // std audit field
Endpoint string `json:"endpoint"` // std audit field
Details proto.Message `json:"details"` // boundary field
}

type Response struct {
StatusCode int `json:"status_code,omitempty"` // std audit
Details proto.Message `json:"details,omitempty"` // boundary field
}
148 changes: 148 additions & 0 deletions internal/observability/events/event_audit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package event

import (
"fmt"
"time"

"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/eventlogger"
)

// AuditVersion defines the version of audit events
const AuditVersion = "v0.1"

// AuditEventType defines the type of audit event
type AuditEventType string

const (
ApiRequest AuditEventType = "APIRequest" // ApiRequest defines an API request audit event type
)

// Audit defines the data of audit events
type Audit struct {
Id string `json:"id"` // std audit/boundary field
Version string `json:"version"` // std audit/boundary field
Type string `json:"type"` // std audit field
Timestamp time.Time `json:"timestamp"` // std audit field
RequestInfo *RequestInfo `json:"request_info,omitempty"` // boundary field
Auth *Auth `json:"auth,omitempty"` // std audit field
Request *Request `json:"request,omitempty"` // std audit field
Response *Response `json:"response,omitempty"` // std audit field
SerializedHMAC string `json:"serialized_hmac"` // boundary field
Flush bool `json:"-"`
}

func newAudit(fromOperation Op, opt ...Option) (*Audit, error) {
jimlambrt marked this conversation as resolved.
Show resolved Hide resolved
const op = "event.newAudit"
if fromOperation == "" {
return nil, errors.New(errors.InvalidParameter, op, "missing from operation")
}
opts := getOpts(opt...)
if opts.withId == "" {
var err error
opts.withId, err = newId(string(AuditType))
if err != nil {
return nil, errors.Wrap(err, op)
}
}
jimlambrt marked this conversation as resolved.
Show resolved Hide resolved
var dtm time.Time
switch opts.withNow.IsZero() {
case false:
dtm = opts.withNow
default:
dtm = time.Now()
}

a := &Audit{
Id: opts.withId,
Version: AuditVersion,
Type: string(ApiRequest),
Timestamp: dtm,
RequestInfo: opts.withRequestInfo,
Auth: opts.withAuth,
Request: opts.withRequest,
Response: opts.withResponse,
Flush: opts.withFlush,
}
if err := a.validate(); err != nil {
return nil, errors.Wrap(err, op)
}
return a, nil
}

// EventType is required for all event types by the eventlogger broker
func (a *Audit) EventType() string { return string(AuditType) }

func (a *Audit) validate() error {
const op = "event.(audit).validate"
if a.Id == "" {
return errors.New(errors.InvalidParameter, op, "missing id")
}
return nil
}

// GetID is part of the eventlogger.Gateable interface and returns the audit
// event's id.
func (a *Audit) GetID() string {
return a.Id
}

// FlushEvent is part of the eventlogger.Gateable interface and returns the
// value of the audit event's flush field
func (a *Audit) FlushEvent() bool {
return a.Flush
}

// ComposedFrom is part of the eventlogger.Gatable interface. It's important to
// remember that the receiver will always be nil when this is called by the eventlogger.GatedFilter
func (a *Audit) ComposeFrom(events []*eventlogger.Event) (eventlogger.EventType, interface{}, error) {
const op = "event.(audit).ComposedFrom"
if len(events) == 0 {
return "", nil, errors.New(errors.InvalidParameter, op, "missing events")
}
var validId string
payload := Audit{}
for i, v := range events {
gated, ok := v.Payload.(*Audit)
if !ok {
return "", nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("event %d is not an audit payload", i))
}
if gated.Id == "" {
// can't really happen since it has to have an id to be gated, but
// I'll add this check in the name of completeness
return "", nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("event %d: id is required", i))
}
if validId == "" {
validId = gated.Id
}
if gated.Id != validId {
return "", nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("event %d has an invalid id: %s != %s", i, gated.Id, validId))
}
if gated.Version != AuditVersion {
return "", nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("event %d has an invalid version: %s != %s", i, gated.Version, AuditVersion))
}
if gated.Type != string(ApiRequest) {
return "", nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("event %d has an invalid type: %s != %s", i, gated.Type, string(AuditType)))
}
if gated.RequestInfo != nil {
payload.RequestInfo = gated.RequestInfo
}
if gated.Auth != nil {
payload.Auth = gated.Auth
}
if gated.Request != nil {
payload.Request = gated.Request
}
if gated.Response != nil {
payload.Response = gated.Response
}
if !gated.Timestamp.IsZero() {
payload.Timestamp = gated.Timestamp
}

}
payload.Id = validId
payload.Version = AuditVersion
payload.Type = string(ApiRequest)
return eventlogger.EventType(a.EventType()), payload, nil
}
Loading