From b87a8dfa92eb6346453d97aea2494ab319d415df Mon Sep 17 00:00:00 2001 From: Ori Shavit Date: Tue, 10 Dec 2024 18:17:23 +0100 Subject: [PATCH 1/2] Accept both SrcIP and client identity in ReportAWSOperation --- src/mapper/pkg/graph/generated/generated.go | 62 ++++++++++++++++++- src/mapper/pkg/graph/model/models_gen.go | 12 +++- .../pkg/resolvers/schema.helpers.resolvers.go | 39 +++++++----- src/mapperclient/generated.go | 23 +++++-- src/mappergraphql/schema.graphql | 8 ++- 5 files changed, 118 insertions(+), 26 deletions(-) diff --git a/src/mapper/pkg/graph/generated/generated.go b/src/mapper/pkg/graph/generated/generated.go index b2486eaf..2369ac14 100644 --- a/src/mapper/pkg/graph/generated/generated.go +++ b/src/mapper/pkg/graph/generated/generated.go @@ -519,6 +519,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputIstioConnectionResults, ec.unmarshalInputKafkaMapperResult, ec.unmarshalInputKafkaMapperResults, + ec.unmarshalInputNamespacedName, ec.unmarshalInputRecordedDestinationsForSrc, ec.unmarshalInputServerFilter, ec.unmarshalInputSocketScanResults, @@ -773,10 +774,16 @@ input IstioConnectionResults { results: [IstioConnection!]! } +input NamespacedName { + name: String! + namespace: String! +} + input AWSOperation { resource: String! actions: [String!]! - srcIp: String! + srcIp: String + client: NamespacedName } input ServerFilter { @@ -5041,7 +5048,7 @@ func (ec *executionContext) unmarshalInputAWSOperation(ctx context.Context, obj asMap[k] = v } - fieldsInOrder := [...]string{"resource", "actions", "srcIp"} + fieldsInOrder := [...]string{"resource", "actions", "srcIp", "client"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -5064,11 +5071,18 @@ func (ec *executionContext) unmarshalInputAWSOperation(ctx context.Context, obj it.Actions = data case "srcIp": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("srcIp")) - data, err := ec.unmarshalNString2string(ctx, v) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.SrcIP = data + case "client": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("client")) + data, err := ec.unmarshalONamespacedName2ᚖgithubᚗcomᚋotterizeᚋnetworkᚑmapperᚋsrcᚋmapperᚋpkgᚋgraphᚋmodelᚐNamespacedName(ctx, v) + if err != nil { + return it, err + } + it.Client = data } } @@ -5431,6 +5445,40 @@ func (ec *executionContext) unmarshalInputKafkaMapperResults(ctx context.Context return it, nil } +func (ec *executionContext) unmarshalInputNamespacedName(ctx context.Context, obj interface{}) (model.NamespacedName, error) { + var it model.NamespacedName + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"name", "namespace"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "name": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Name = data + case "namespace": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("namespace")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Namespace = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputRecordedDestinationsForSrc(ctx context.Context, obj interface{}) (model.RecordedDestinationsForSrc, error) { var it model.RecordedDestinationsForSrc asMap := map[string]interface{}{} @@ -7487,6 +7535,14 @@ func (ec *executionContext) marshalOKafkaOperation2ᚕgithubᚗcomᚋotterizeᚋ return ret } +func (ec *executionContext) unmarshalONamespacedName2ᚖgithubᚗcomᚋotterizeᚋnetworkᚑmapperᚋsrcᚋmapperᚋpkgᚋgraphᚋmodelᚐNamespacedName(ctx context.Context, v interface{}) (*model.NamespacedName, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputNamespacedName(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) marshalOPodLabel2ᚕgithubᚗcomᚋotterizeᚋnetworkᚑmapperᚋsrcᚋmapperᚋpkgᚋgraphᚋmodelᚐPodLabelᚄ(ctx context.Context, sel ast.SelectionSet, v []model.PodLabel) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/src/mapper/pkg/graph/model/models_gen.go b/src/mapper/pkg/graph/model/models_gen.go index 458c1ab6..22868a24 100644 --- a/src/mapper/pkg/graph/model/models_gen.go +++ b/src/mapper/pkg/graph/model/models_gen.go @@ -10,9 +10,10 @@ import ( ) type AWSOperation struct { - Resource string `json:"resource"` - Actions []string `json:"actions"` - SrcIP string `json:"srcIp"` + Resource string `json:"resource"` + Actions []string `json:"actions"` + SrcIP *string `json:"srcIp,omitempty"` + Client *NamespacedName `json:"client,omitempty"` } type AzureOperation struct { @@ -107,6 +108,11 @@ type KafkaMapperResults struct { type Mutation struct { } +type NamespacedName struct { + Name string `json:"name"` + Namespace string `json:"namespace"` +} + type OtterizeServiceIdentity struct { Name string `json:"name"` Namespace string `json:"namespace"` diff --git a/src/mapper/pkg/resolvers/schema.helpers.resolvers.go b/src/mapper/pkg/resolvers/schema.helpers.resolvers.go index 4f6c1beb..43ab88d2 100644 --- a/src/mapper/pkg/resolvers/schema.helpers.resolvers.go +++ b/src/mapper/pkg/resolvers/schema.helpers.resolvers.go @@ -248,33 +248,42 @@ func (r *Resolver) handleDNSCaptureResultsAsExternalTraffic(_ context.Context, d // ReportAWSOperation is the resolver for the reportAWSOperation field. func (r *Resolver) handleAWSOperationReport(ctx context.Context, operation model.AWSOperationResults) error { for _, op := range operation { - logrus.Debugf("Received AWS operation: %+v", op) - srcPod, err := r.kubeFinder.ResolveIPToPod(ctx, op.SrcIP) + var serviceIdentity model.OtterizeServiceIdentity - if err != nil { - logrus.Errorf("could not resolve %s to pod: %s", op.SrcIP, err.Error()) - continue - } + if op.Client != nil { + serviceIdentity.Name = op.Client.Name + serviceIdentity.Namespace = op.Client.Namespace + } else if op.SrcIP != nil { + srcPod, err := r.kubeFinder.ResolveIPToPod(ctx, *op.SrcIP) - serviceId, err := r.serviceIdResolver.ResolvePodToServiceIdentity(ctx, srcPod) + if err != nil { + logrus.Errorf("could not resolve %s to pod: %s", op.SrcIP, err.Error()) + continue + } - if err != nil { - logrus.Errorf("could not resolve pod %s to identity: %s", srcPod.Name, err.Error()) + serviceId, err := r.serviceIdResolver.ResolvePodToServiceIdentity(ctx, srcPod) + + if err != nil { + logrus.Errorf("could not resolve pod %s to identity: %s", srcPod.Name, err.Error()) + continue + } + + serviceIdentity.Name = serviceId.Name + serviceIdentity.Namespace = srcPod.Namespace + } else { + logrus.Error("Invalid AWS operation report: both srcIP and client are nil") continue } r.awsIntentsHolder.AddIntent(awsintentsholder.AWSIntent{ - Client: model.OtterizeServiceIdentity{ - Name: serviceId.Name, - Namespace: srcPod.Namespace, - }, + Client: serviceIdentity, Actions: op.Actions, ARN: op.Resource, }) logrus. - WithField("client", serviceId.Name). - WithField("namespace", srcPod.Namespace). + WithField("clientName", serviceIdentity.Name). + WithField("clientNamespace", serviceIdentity.Namespace). WithField("actions", op.Actions). WithField("arn", op.Resource). Debug("Discovered AWS intent") diff --git a/src/mapperclient/generated.go b/src/mapperclient/generated.go index f51bc045..c2019dfd 100644 --- a/src/mapperclient/generated.go +++ b/src/mapperclient/generated.go @@ -11,9 +11,10 @@ import ( ) type AWSOperation struct { - Resource string `json:"resource"` - Actions []string `json:"actions"` - SrcIp string `json:"srcIp"` + Resource string `json:"resource"` + Actions []string `json:"actions"` + SrcIp nilable.Nilable[string] `json:"srcIp"` + Client nilable.Nilable[NamespacedName] `json:"client"` } // GetResource returns AWSOperation.Resource, and is useful for accessing the field via an interface. @@ -23,7 +24,10 @@ func (v *AWSOperation) GetResource() string { return v.Resource } func (v *AWSOperation) GetActions() []string { return v.Actions } // GetSrcIp returns AWSOperation.SrcIp, and is useful for accessing the field via an interface. -func (v *AWSOperation) GetSrcIp() string { return v.SrcIp } +func (v *AWSOperation) GetSrcIp() nilable.Nilable[string] { return v.SrcIp } + +// GetClient returns AWSOperation.Client, and is useful for accessing the field via an interface. +func (v *AWSOperation) GetClient() nilable.Nilable[NamespacedName] { return v.Client } type AzureOperation struct { Scope string `json:"scope"` @@ -127,6 +131,17 @@ type KafkaMapperResults struct { // GetResults returns KafkaMapperResults.Results, and is useful for accessing the field via an interface. func (v *KafkaMapperResults) GetResults() []KafkaMapperResult { return v.Results } +type NamespacedName struct { + Name string `json:"name"` + Namespace string `json:"namespace"` +} + +// GetName returns NamespacedName.Name, and is useful for accessing the field via an interface. +func (v *NamespacedName) GetName() string { return v.Name } + +// GetNamespace returns NamespacedName.Namespace, and is useful for accessing the field via an interface. +func (v *NamespacedName) GetNamespace() string { return v.Namespace } + type RecordedDestinationsForSrc struct { SrcIp string `json:"srcIp"` SrcHostname string `json:"srcHostname"` diff --git a/src/mappergraphql/schema.graphql b/src/mappergraphql/schema.graphql index 5b2a1685..e1d10e21 100644 --- a/src/mappergraphql/schema.graphql +++ b/src/mappergraphql/schema.graphql @@ -152,10 +152,16 @@ input IstioConnectionResults { results: [IstioConnection!]! } +input NamespacedName { + name: String! + namespace: String! +} + input AWSOperation { resource: String! actions: [String!]! - srcIp: String! + srcIp: String + client: NamespacedName } input ServerFilter { From ddaa14786075391c1912dc0b892252f05cb64249 Mon Sep 17 00:00:00 2001 From: Ori Shavit Date: Wed, 11 Dec 2024 11:13:20 +0100 Subject: [PATCH 2/2] fix log string --- src/mapper/pkg/resolvers/schema.helpers.resolvers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mapper/pkg/resolvers/schema.helpers.resolvers.go b/src/mapper/pkg/resolvers/schema.helpers.resolvers.go index 43ab88d2..2c8a4cda 100644 --- a/src/mapper/pkg/resolvers/schema.helpers.resolvers.go +++ b/src/mapper/pkg/resolvers/schema.helpers.resolvers.go @@ -257,7 +257,7 @@ func (r *Resolver) handleAWSOperationReport(ctx context.Context, operation model srcPod, err := r.kubeFinder.ResolveIPToPod(ctx, *op.SrcIP) if err != nil { - logrus.Errorf("could not resolve %s to pod: %s", op.SrcIP, err.Error()) + logrus.Errorf("could not resolve IP %s to pod: %s", *op.SrcIP, err.Error()) continue }