@@ -4,20 +4,16 @@ import (
44 "context"
55 "errors"
66 "fmt"
7- "github.com/compliance-framework/plugin-aws-networking-security/internal"
8- "os"
9- "time"
10-
117 "github.com/aws/aws-sdk-go-v2/config"
128 "github.com/aws/aws-sdk-go-v2/service/ec2"
139 policyManager "github.com/compliance-framework/agent/policy-manager"
1410 "github.com/compliance-framework/agent/runner"
1511 "github.com/compliance-framework/agent/runner/proto"
16- "github.com/compliance-framework/configuration-service/sdk"
17- "github.com/google/uuid"
12+ "github.com/compliance-framework/plugin-aws-networking-security/internal"
1813 "github.com/hashicorp/go-hclog"
1914 goplugin "github.com/hashicorp/go-plugin"
20- "google.golang.org/protobuf/types/known/timestamppb"
15+ "os"
16+ "slices"
2117)
2218
2319type CompliancePlugin struct {
@@ -37,7 +33,6 @@ func (l *CompliancePlugin) Configure(req *proto.ConfigureRequest) (*proto.Config
3733
3834func (l * CompliancePlugin ) Eval (request * proto.EvalRequest , apiHelper runner.ApiHelper ) (* proto.EvalResponse , error ) {
3935 ctx := context .TODO ()
40- startTime := time .Now ()
4136 evalStatus := proto .ExecutionStatus_SUCCESS
4237 var accumulatedErrors error
4338
@@ -64,18 +59,22 @@ func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.Api
6459 findings := make ([]* proto.Finding , 0 )
6560 observations := make ([]* proto.Observation , 0 )
6661
67- subjectAttributeMap := map [string ]string {
68- "type" : "aws" ,
69- "service" : "security-group" ,
70- "instance-id" : * group .GroupId ,
71- "instance-name" : * group .GroupName ,
72- "vpc-id" : * group .VpcId ,
62+ labels := map [string ]string {
63+ "type" : "aws" ,
64+ "service" : "security-groups" ,
65+ "instance-id" : * group .GroupId ,
7366 }
7467 subjects := []* proto.SubjectReference {
7568 {
76- Type : "aws-security-group" ,
77- Attributes : subjectAttributeMap ,
78- Title : internal .StringAddressed ("AWS Security Group" ),
69+ Type : "aws-security-group" ,
70+ Attributes : map [string ]string {
71+ "type" : "aws" ,
72+ "service" : "security-group" ,
73+ "instance-id" : * group .GroupId ,
74+ "instance-name" : * group .GroupName ,
75+ "vpc-id" : * group .VpcId ,
76+ },
77+ Title : internal .StringAddressed ("AWS Security Group" ),
7978 Props : []* proto.Property {
8079 {
8180 Name : "security-group-id" ,
@@ -87,6 +86,21 @@ func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.Api
8786 },
8887 },
8988 },
89+ {
90+ Type : "aws-vpc" ,
91+ Attributes : map [string ]string {
92+ "type" : "aws" ,
93+ "service" : "vpc" ,
94+ "vpc-id" : fmt .Sprintf ("%v" , * group .VpcId ),
95+ },
96+ Title : internal .StringAddressed ("AWS VPC" ),
97+ Props : []* proto.Property {
98+ {
99+ Name : "vpc-id" ,
100+ Value : fmt .Sprintf ("%v" , * group .VpcId ),
101+ },
102+ },
103+ },
90104 }
91105 actors := []* proto.OriginActor {
92106 {
@@ -119,138 +133,25 @@ func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.Api
119133 }
120134
121135 for _ , policyPath := range request .GetPolicyPaths () {
122- steps := make ([]* proto.Step , 0 )
123- steps = append (steps , & proto.Step {
124- Title : "Compile policy bundle" ,
125- Description : "Using a locally addressable policy path, compile the policy files to an in memory executable." ,
126- })
127- steps = append (steps , & proto.Step {
128- Title : "Execute policy bundle" ,
129- Description : "Using previously collected JSON-formatted Security Group configuration, execute the compiled policies" ,
130- })
131-
132- results , err := policyManager .New (ctx , l .logger , policyPath ).Execute (ctx , "compliance_plugin" , map [string ]interface {}{
133- "SecurityGroupID" : * group .GroupId ,
134- "IpPermissions" : group .IpPermissions ,
135- "IpPermissionsEgress" : group .IpPermissionsEgress ,
136- })
136+ // Explicitly reset steps to make things readable
137+ processor := policyManager .NewPolicyProcessor (
138+ l .logger ,
139+ internal .MergeMaps (
140+ labels ,
141+ map [string ]string {
142+ "_policy_path" : policyPath ,
143+ },
144+ ),
145+ subjects ,
146+ components ,
147+ actors ,
148+ activities ,
149+ )
150+ obs , finds , err := processor .GenerateResults (ctx , policyPath , group )
151+ observations = slices .Concat (observations , obs )
152+ findings = slices .Concat (findings , finds )
137153 if err != nil {
138- l .logger .Error ("policy evaluation failed" , "error" , err )
139- evalStatus = proto .ExecutionStatus_FAILURE
140154 accumulatedErrors = errors .Join (accumulatedErrors , err )
141- continue
142- }
143-
144- activities = append (activities , & proto.Activity {
145- Title : "Execute policy" ,
146- Description : "Prepare and compile policy bundles, and execute them using the prepared Security Group data" ,
147- Steps : steps ,
148- })
149-
150- for _ , result := range results {
151- // Observation UUID should differ for each individual subject, but remain consistent when validating the same policy for the same subject.
152- // This acts as an identifier to show the history of an observation.
153- observationUUIDMap := internal .MergeMaps (subjectAttributeMap , map [string ]string {
154- "type" : "observation" ,
155- "policy" : result .Policy .Package .PurePackage (),
156- "policy_file" : result .Policy .File ,
157- "policy_path" : policyPath ,
158- })
159- observationUUID , err := sdk .SeededUUID (observationUUIDMap )
160- if err != nil {
161- accumulatedErrors = errors .Join (accumulatedErrors , err )
162- // We've been unable to do much here, but let's try the next one regardless.
163- continue
164- }
165-
166- // Finding UUID should differ for each individual subject, but remain consistent when validating the same policy for the same subject.
167- // This acts as an identifier to show the history of a finding.
168- findingUUIDMap := internal .MergeMaps (subjectAttributeMap , map [string ]string {
169- "type" : "finding" ,
170- "policy" : result .Policy .Package .PurePackage (),
171- "policy_file" : result .Policy .File ,
172- "policy_path" : policyPath ,
173- })
174- findingUUID , err := sdk .SeededUUID (findingUUIDMap )
175- if err != nil {
176- accumulatedErrors = errors .Join (accumulatedErrors , err )
177- // We've been unable to do much here, but let's try the next one regardless.
178- continue
179- }
180-
181- observation := proto.Observation {
182- ID : uuid .New ().String (),
183- UUID : observationUUID .String (),
184- Collected : timestamppb .New (startTime ),
185- Expires : timestamppb .New (startTime .Add (24 * time .Hour )),
186- Origins : []* proto.Origin {{Actors : actors }},
187- Subjects : subjects ,
188- Activities : activities ,
189- Components : components ,
190- RelevantEvidence : []* proto.RelevantEvidence {
191- {
192- Description : fmt .Sprintf ("Policy %v was executed against the AWS Security Group configuration, using the Local AWS Security Group Plugin" , result .Policy .Package .PurePackage ()),
193- },
194- },
195- }
196-
197- newFinding := func () * proto.Finding {
198- return & proto.Finding {
199- ID : uuid .New ().String (),
200- UUID : findingUUID .String (),
201- Collected : timestamppb .New (time .Now ()),
202- Labels : map [string ]string {
203- "type" : "aws" ,
204- "service" : "security-groups" ,
205- "instance-id" : * group .GroupId ,
206- "instance-name" : * group .GroupName ,
207- "vpc-id" : * group .VpcId ,
208- "_policy" : result .Policy .Package .PurePackage (),
209- "_policy_path" : result .Policy .File ,
210- },
211- Origins : []* proto.Origin {{Actors : actors }},
212- Subjects : subjects ,
213- Components : components ,
214- RelatedObservations : []* proto.RelatedObservation {{ObservationUUID : observation .ID }},
215- Controls : nil ,
216- }
217- }
218-
219- // There are no violations reported from the policies.
220- // We'll send the observation back to the agent
221- if len (result .Violations ) == 0 {
222- observation .Title = internal .StringAddressed ("The plugin succeeded. No compliance issues to report." )
223- observation .Description = "The plugin policies did not return any violations. The configuration is in compliance with policies."
224- observations = append (observations , & observation )
225-
226- finding := newFinding ()
227- finding .Title = fmt .Sprintf ("No violations found on %s" , result .Policy .Package .PurePackage ())
228- finding .Description = fmt .Sprintf ("No violations were found on the %s policy within the AWS Security Groups Compliance Plugin." , result .Policy .Package .PurePackage ())
229- finding .Status = & proto.FindingStatus {
230- State : runner .FindingTargetStatusSatisfied ,
231- }
232- findings = append (findings , finding )
233- continue
234- }
235-
236- // There are violations in the policy checks.
237- // We'll send these observations back to the agent
238- if len (result .Violations ) > 0 {
239- observation .Title = internal .StringAddressed (fmt .Sprintf ("Validation on %s failed." , result .Policy .Package .PurePackage ()))
240- observation .Description = fmt .Sprintf ("Observed %d violation(s) on the %s policy within the AWS Security groups Compliance Plugin." , len (result .Violations ), result .Policy .Package .PurePackage ())
241- observations = append (observations , & observation )
242-
243- for _ , violation := range result .Violations {
244- finding := newFinding ()
245- finding .Title = violation .Title
246- finding .Description = violation .Description
247- finding .Remarks = internal .StringAddressed (violation .Remarks )
248- finding .Status = & proto.FindingStatus {
249- State : runner .FindingTargetStatusNotSatisfied ,
250- }
251- findings = append (findings , finding )
252- }
253- }
254155 }
255156 }
256157
0 commit comments