From fe19fb1fccfb0535c44aa2916a05efaea4387c93 Mon Sep 17 00:00:00 2001 From: Claudio Busse Date: Tue, 2 Jul 2024 12:13:52 +0200 Subject: [PATCH] OSD-24351: permission denied command should also evaluate read-only events --- cmd/cloudtrail/cloudtrail_test.go | 11 ++++------- cmd/cloudtrail/permission-denied.go | 23 ++++++++--------------- cmd/cloudtrail/pkg/aws/aws.go | 9 ++++++--- cmd/cloudtrail/write-events.go | 4 ++-- 4 files changed, 20 insertions(+), 27 deletions(-) diff --git a/cmd/cloudtrail/cloudtrail_test.go b/cmd/cloudtrail/cloudtrail_test.go index 87047698..3364ce0f 100644 --- a/cmd/cloudtrail/cloudtrail_test.go +++ b/cmd/cloudtrail/cloudtrail_test.go @@ -94,9 +94,6 @@ func TestIgnoreListFilter(t *testing.T) { func TestPermissonDeniedFilter(t *testing.T) { - var ( - permissionDeniedErrorStr = ".*Client.UnauthorizedOperation.*" - ) // Test Case 1 (Ignored) testUsername1 := "RH-SRE-xxx.openshift" testCloudTrailEvent1 := `{"eventVersion": "1.08","userIdentity": {"sessionContext": {"sessionIssuer": {"arn": "arn:aws:iam::123456789012:user/test-12345-6-a7b8-kube-system-capa-controller-manager/RH-SRE-xxx.openshift"}}}, "errorCode": "Client.UnauthorizedOperation"}` @@ -123,7 +120,7 @@ func TestPermissonDeniedFilter(t *testing.T) { filtered, err := ctUtil.ApplyFilters(TestEvents, func(event types.Event) (bool, error) { - return isforbiddenEvent(event, permissionDeniedErrorStr) + return isforbiddenEvent(event) }, ) assert.Nil(t, err) @@ -143,7 +140,7 @@ func TestPermissonDeniedFilter(t *testing.T) { filtered, err := ctUtil.ApplyFilters(edgeCaseEvents, func(event types.Event) (bool, error) { - return isforbiddenEvent(event, permissionDeniedErrorStr) + return isforbiddenEvent(event) }, ) assert.Nil(t, err) @@ -162,7 +159,7 @@ func TestPermissonDeniedFilter(t *testing.T) { filtered, err := ctUtil.ApplyFilters(edgeCaseEvents, func(event types.Event) (bool, error) { - return isforbiddenEvent(event, permissionDeniedErrorStr) + return isforbiddenEvent(event) }, ) assert.Nil(t, err) @@ -181,7 +178,7 @@ func TestPermissonDeniedFilter(t *testing.T) { expected := []types.Event{} filtered, err := ctUtil.ApplyFilters(edgeCaseEvents, func(event types.Event) (bool, error) { - return isforbiddenEvent(event, permissionDeniedErrorStr) + return isforbiddenEvent(event) }, ) assert.EqualErrorf(t, err, "[ERROR] failed to extract raw CloudTrail event details: cannot parse a nil input", "") diff --git a/cmd/cloudtrail/permission-denied.go b/cmd/cloudtrail/permission-denied.go index 2f81544e..f7ad34c0 100644 --- a/cmd/cloudtrail/permission-denied.go +++ b/cmd/cloudtrail/permission-denied.go @@ -17,10 +17,6 @@ import ( "github.com/spf13/cobra" ) -var ( - permissionDeniedErrorStr = ".*Client.UnauthorizedOperation.*" -) - type permissionDeniedEventsOptions struct { ClusterID string StartTime string @@ -39,20 +35,17 @@ func newCmdPermissionDenied() *cobra.Command { }, } permissionDeniedCmd.Flags().StringVarP(&opts.ClusterID, "cluster-id", "C", "", "Cluster ID") - permissionDeniedCmd.Flags().StringVarP(&opts.StartTime, "since", "", "1h", "Specifies that only events that occur within the specified time are returned.Defaults to 1h. Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".") + permissionDeniedCmd.Flags().StringVarP(&opts.StartTime, "since", "", "5m", "Specifies that only events that occur within the specified time are returned.Defaults to 5m. Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".") permissionDeniedCmd.Flags().BoolVarP(&opts.PrintUrl, "url", "u", false, "Generates Url link to cloud console cloudtrail event") permissionDeniedCmd.Flags().BoolVarP(&opts.PrintRaw, "raw-event", "r", false, "Prints the cloudtrail events to the console in raw json format") permissionDeniedCmd.MarkFlagRequired("cluster-id") return permissionDeniedCmd } -func isforbiddenEvent(event types.Event, value string) (bool, error) { - - if value == "" { - return false, nil - } +func isforbiddenEvent(event types.Event) (bool, error) { + permissionDeniedErrorRegexp := ".*Client.UnauthorizedOperation.*" - check, err := regexp.Compile(value) + check, err := regexp.Compile(permissionDeniedErrorRegexp) if err != nil { return false, fmt.Errorf("failed to compile regex: %w", err) } @@ -106,14 +99,14 @@ func (p *permissionDeniedEventsOptions) run() error { fmt.Printf("[INFO] Checking Permission Denied History since %v for AWS Account %v as %v \n", startTime, accountId, arn) cloudTrailclient := cloudtrail.NewFromConfig(cfg) fmt.Printf("[INFO] Fetching %v Event History...", cfg.Region) - lookupOutput, err := ctAws.GetEvents(cloudTrailclient, startTime) + lookupOutput, err := ctAws.GetEvents(cloudTrailclient, startTime, false) if err != nil { return err } filteredEvents, err := ctUtil.ApplyFilters(lookupOutput, func(event types.Event) (bool, error) { - return isforbiddenEvent(event, permissionDeniedErrorStr) + return isforbiddenEvent(event) }, ) if err != nil { @@ -136,13 +129,13 @@ func (p *permissionDeniedEventsOptions) run() error { HTTPClient: cfg.HTTPClient, }) fmt.Printf("[INFO] Fetching Cloudtrail Global Permission Denied Event History from %v Region...", defaultConfig.Region) - lookupOutput, err := ctAws.GetEvents(defaultCloudtrailClient, startTime) + lookupOutput, err := ctAws.GetEvents(defaultCloudtrailClient, startTime, false) if err != nil { return err } filteredEvents, err := ctUtil.ApplyFilters(lookupOutput, func(event types.Event) (bool, error) { - return isforbiddenEvent(event, permissionDeniedErrorStr) + return isforbiddenEvent(event) }, ) if err != nil { diff --git a/cmd/cloudtrail/pkg/aws/aws.go b/cmd/cloudtrail/pkg/aws/aws.go index 16dd83d5..ff9210eb 100644 --- a/cmd/cloudtrail/pkg/aws/aws.go +++ b/cmd/cloudtrail/pkg/aws/aws.go @@ -77,16 +77,19 @@ func Whoami(stsClient sts.Client) (accountArn string, accountId string, err erro // getWriteEvents retrieves cloudtrail events since the specified time // using the provided cloudtrail client and starttime from since flag. -func GetEvents(cloudtailClient *cloudtrail.Client, startTime time.Time) ([]types.Event, error) { +func GetEvents(cloudtailClient *cloudtrail.Client, startTime time.Time, writeOnly bool) ([]types.Event, error) { alllookupEvents := []types.Event{} input := cloudtrail.LookupEventsInput{ StartTime: &startTime, EndTime: aws.Time(time.Now()), - LookupAttributes: []types.LookupAttribute{ + } + + if writeOnly { + input.LookupAttributes = []types.LookupAttribute{ {AttributeKey: "ReadOnly", AttributeValue: aws.String("false")}, - }, + } } paginator := cloudtrail.NewLookupEventsPaginator(cloudtailClient, &input, func(c *cloudtrail.LookupEventsPaginatorOptions) {}) diff --git a/cmd/cloudtrail/write-events.go b/cmd/cloudtrail/write-events.go index 79f521ac..ed5f9fe5 100644 --- a/cmd/cloudtrail/write-events.go +++ b/cmd/cloudtrail/write-events.go @@ -149,7 +149,7 @@ func (o *writeEventsOptions) run() error { fmt.Printf("[INFO] Checking write event history since %v for AWS Account %v as %v \n", startTime, accountId, arn) cloudTrailclient := cloudtrail.NewFromConfig(cfg) fmt.Printf("[INFO] Fetching %v Event History...", cfg.Region) - queriedEvents, err := ctAws.GetEvents(cloudTrailclient, startTime) + queriedEvents, err := ctAws.GetEvents(cloudTrailclient, startTime, true) if err != nil { return err } @@ -180,7 +180,7 @@ func (o *writeEventsOptions) run() error { HTTPClient: cfg.HTTPClient, }) fmt.Printf("[INFO] Fetching Cloudtrail Global Event History from %v Region...", defaultConfig.Region) - lookupOutput, err := ctAws.GetEvents(defaultCloudtrailClient, startTime) + lookupOutput, err := ctAws.GetEvents(defaultCloudtrailClient, startTime, true) if err != nil { return err }