diff --git a/pkg/security/events/event.go b/pkg/security/events/event.go index 2da64962a482be..fd816210358de3 100644 --- a/pkg/security/events/event.go +++ b/pkg/security/events/event.go @@ -13,13 +13,14 @@ import "github.com/DataDog/datadog-agent/pkg/security/secl/rules" // AgentContext serializes the agent context to JSON // easyjson:json type AgentContext struct { - RuleID string `json:"rule_id"` - RuleVersion string `json:"rule_version,omitempty"` - PolicyName string `json:"policy_name,omitempty"` - PolicyVersion string `json:"policy_version,omitempty"` - Version string `json:"version,omitempty"` - OS string `json:"os,omitempty"` - Arch string `json:"arch,omitempty"` + RuleID string `json:"rule_id"` + RuleVersion string `json:"rule_version,omitempty"` + RuleActions []map[string]interface{} `json:"rule_actions,omitempty"` + PolicyName string `json:"policy_name,omitempty"` + PolicyVersion string `json:"policy_version,omitempty"` + Version string `json:"version,omitempty"` + OS string `json:"os,omitempty"` + Arch string `json:"arch,omitempty"` } // Signal - Rule event wrapper used to send an event to the backend diff --git a/pkg/security/events/event_easyjson.go b/pkg/security/events/event_easyjson.go index e6a5bb792b0282..a70c792edf95f7 100644 --- a/pkg/security/events/event_easyjson.go +++ b/pkg/security/events/event_easyjson.go @@ -99,6 +99,53 @@ func easyjsonF642ad3eDecodeGithubComDataDogDatadogAgentPkgSecurityEvents1(in *jl out.RuleID = string(in.String()) case "rule_version": out.RuleVersion = string(in.String()) + case "rule_actions": + if in.IsNull() { + in.Skip() + out.RuleActions = nil + } else { + in.Delim('[') + if out.RuleActions == nil { + if !in.IsDelim(']') { + out.RuleActions = make([]map[string]interface{}, 0, 8) + } else { + out.RuleActions = []map[string]interface{}{} + } + } else { + out.RuleActions = (out.RuleActions)[:0] + } + for !in.IsDelim(']') { + var v1 map[string]interface{} + if in.IsNull() { + in.Skip() + } else { + in.Delim('{') + if !in.IsDelim('}') { + v1 = make(map[string]interface{}) + } else { + v1 = nil + } + for !in.IsDelim('}') { + key := string(in.String()) + in.WantColon() + var v2 interface{} + if m, ok := v2.(easyjson.Unmarshaler); ok { + m.UnmarshalEasyJSON(in) + } else if m, ok := v2.(json.Unmarshaler); ok { + _ = m.UnmarshalJSON(in.Raw()) + } else { + v2 = in.Interface() + } + (v1)[key] = v2 + in.WantComma() + } + in.Delim('}') + } + out.RuleActions = append(out.RuleActions, v1) + in.WantComma() + } + in.Delim(']') + } case "policy_name": out.PolicyName = string(in.String()) case "policy_version": @@ -133,6 +180,42 @@ func easyjsonF642ad3eEncodeGithubComDataDogDatadogAgentPkgSecurityEvents1(out *j out.RawString(prefix) out.String(string(in.RuleVersion)) } + if len(in.RuleActions) != 0 { + const prefix string = ",\"rule_actions\":" + out.RawString(prefix) + { + out.RawByte('[') + for v3, v4 := range in.RuleActions { + if v3 > 0 { + out.RawByte(',') + } + if v4 == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 { + out.RawString(`null`) + } else { + out.RawByte('{') + v5First := true + for v5Name, v5Value := range v4 { + if v5First { + v5First = false + } else { + out.RawByte(',') + } + out.String(string(v5Name)) + out.RawByte(':') + if m, ok := v5Value.(easyjson.Marshaler); ok { + m.MarshalEasyJSON(out) + } else if m, ok := v5Value.(json.Marshaler); ok { + out.Raw(m.MarshalJSON()) + } else { + out.Raw(json.Marshal(v5Value)) + } + } + out.RawByte('}') + } + } + out.RawByte(']') + } + } if in.PolicyName != "" { const prefix string = ",\"policy_name\":" out.RawString(prefix) diff --git a/pkg/security/module/server.go b/pkg/security/module/server.go index d520831221d857..861e0b96616103 100644 --- a/pkg/security/module/server.go +++ b/pkg/security/module/server.go @@ -259,9 +259,33 @@ func (a *APIServer) GetConfig(ctx context.Context, params *api.GetConfigParams) // SendEvent forwards events sent by the runtime security module to Datadog func (a *APIServer) SendEvent(rule *rules.Rule, e events.Event, extTagsCb func() []string, service string) { + ruleActions := make([]map[string]interface{}, 0, len(rule.Definition.Actions)) + for _, action := range rule.Definition.Actions { + switch { + case action.Kill != nil: + ruleActions = append(ruleActions, map[string]interface{}{"name": "kill", "signal": action.Kill.Signal}) + case action.Set != nil: + ruleAction := map[string]interface{}{"name": "set"} + if action.Set.Value != nil { + ruleAction["value"] = action.Set.Value + } + if action.Set.Field != "" { + ruleAction["field"] = action.Set.Field + } + if action.Set.Append { + ruleAction["append"] = action.Set.Append + } + if action.Set.Scope != "" { + ruleAction["scope"] = string(action.Set.Scope) + } + ruleActions = append(ruleActions, ruleAction) + } + } + agentContext := events.AgentContext{ RuleID: rule.Definition.ID, RuleVersion: rule.Definition.Version, + RuleActions: ruleActions, Version: version.AgentVersion, OS: runtime.GOOS, Arch: utils.RuntimeArch(), diff --git a/pkg/security/secl/model/model.go b/pkg/security/secl/model/model.go index b583e06c108995..55091a9d753c1c 100644 --- a/pkg/security/secl/model/model.go +++ b/pkg/security/secl/model/model.go @@ -375,6 +375,7 @@ type MatchedRule struct { RuleID string RuleVersion string RuleTags map[string]string + RuleActions []map[string]interface{} PolicyName string PolicyVersion string } diff --git a/pkg/security/serializers/serializers_base.go b/pkg/security/serializers/serializers_base.go index d9fd170ccddae3..4c2365ec21232c 100644 --- a/pkg/security/serializers/serializers_base.go +++ b/pkg/security/serializers/serializers_base.go @@ -166,6 +166,7 @@ func newMatchedRulesSerializer(r *model.MatchedRule) MatchedRuleSerializer { for tagName, tagValue := range r.RuleTags { mrs.Tags = append(mrs.Tags, tagName+":"+tagValue) } + return mrs }