Skip to content

Commit

Permalink
[8.x](backport #2654) [Asset Inventory][GCP] Populate `related.entity…
Browse files Browse the repository at this point in the history
…` field for resources implemented so far (#2806)

[Asset Inventory][GCP] Populate `related.entity` field for resources implemented so far (#2654)

(cherry picked from commit daba272)

Co-authored-by: Kuba Soboń <[email protected]>
  • Loading branch information
mergify[bot] and kubasobon authored Dec 2, 2024
1 parent 921b7a2 commit cdbd1b6
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 3 deletions.
11 changes: 9 additions & 2 deletions internal/inventory/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,9 @@ type AssetEvent struct {

// Asset contains the identifiers of the asset
type Asset struct {
Id []string `json:"id"`
Name string `json:"name"`
Id []string `json:"id"`
RelatedEntityId []string `json:"related_entity_id"`
Name string `json:"name"`
AssetClassification
Tags map[string]string `json:"tags"`
Raw any `json:"raw"`
Expand Down Expand Up @@ -354,6 +355,12 @@ func WithRawAsset(raw any) AssetEnricher {
}
}

func WithRelatedAssetIds(ids []string) AssetEnricher {
return func(a *AssetEvent) {
a.Asset.RelatedEntityId = ids
}
}

func WithTags(tags map[string]string) AssetEnricher {
return func(a *AssetEvent) {
if len(tags) == 0 {
Expand Down
75 changes: 75 additions & 0 deletions internal/inventory/gcpfetcher/fetcher_assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"context"

"github.com/elastic/elastic-agent-libs/logp"
"github.com/samber/lo"
"google.golang.org/protobuf/types/known/structpb"

"github.com/elastic/cloudbeat/internal/inventory"
gcpinventory "github.com/elastic/cloudbeat/internal/resources/providers/gcplib/inventory"
Expand Down Expand Up @@ -86,6 +88,9 @@ func (f *assetsInventory) fetch(ctx context.Context, assetChan chan<- inventory.
[]string{item.Name},
item.Name,
inventory.WithRawAsset(item),
inventory.WithRelatedAssetIds(
f.findRelatedAssetIds(classification.SubType, item),
),
inventory.WithCloud(inventory.AssetCloud{
Provider: inventory.GcpCloudProvider,
Account: inventory.AssetCloudAccount{
Expand All @@ -103,3 +108,73 @@ func (f *assetsInventory) fetch(ctx context.Context, assetChan chan<- inventory.
)
}
}

func (f *assetsInventory) findRelatedAssetIds(subType inventory.AssetSubType, item *gcpinventory.ExtendedGcpAsset) []string {
ids := []string{}
ids = append(ids, item.Ancestors...)
if item.Resource != nil {
ids = append(ids, item.Resource.Parent)
}

ids = append(ids, f.findRelatedAssetIdsForSubType(subType, item)...)

ids = lo.Compact(ids)
ids = lo.Uniq(ids)
return ids
}

func (f *assetsInventory) findRelatedAssetIdsForSubType(subType inventory.AssetSubType, item *gcpinventory.ExtendedGcpAsset) []string {
ids := []string{}

var fields map[string]*structpb.Value
if item.Resource != nil && item.Resource.Data != nil {
fields = item.GetResource().GetData().GetFields()
}

switch subType {
case inventory.SubTypeGcpInstance:
if v, ok := fields["networkInterfaces"]; ok {
for _, networkInterface := range v.GetListValue().GetValues() {
networkInterfaceFields := networkInterface.GetStructValue().GetFields()
ids = appendIfExists(ids, networkInterfaceFields, "network")
ids = appendIfExists(ids, networkInterfaceFields, "subnetwork")
}
}
if v, ok := fields["serviceAccounts"]; ok {
for _, serviceAccount := range v.GetListValue().GetValues() {
serviceAccountFields := serviceAccount.GetStructValue().GetFields()
ids = appendIfExists(ids, serviceAccountFields, "email")
}
}
if v, ok := fields["disks"]; ok {
for _, disk := range v.GetListValue().GetValues() {
diskFields := disk.GetStructValue().GetFields()
ids = appendIfExists(ids, diskFields, "source")
}
}
ids = appendIfExists(ids, fields, "machineType")
ids = appendIfExists(ids, fields, "zone")
case inventory.SubTypeGcpFirewall, inventory.SubTypeGcpSubnet:
ids = appendIfExists(ids, fields, "network")
case inventory.SubTypeGcpProject, inventory.SubTypeGcpBucket:
if item.IamPolicy == nil {
break
}
for _, binding := range item.IamPolicy.Bindings {
ids = append(ids, binding.Role)
ids = append(ids, binding.Members...)
}
default:
return ids
}

return ids
}

func appendIfExists(slice []string, fields map[string]*structpb.Value, key string) []string {
value, ok := fields[key]
if !ok {
return slice
}
return append(slice, value.GetStringValue())
}
1 change: 1 addition & 0 deletions internal/inventory/gcpfetcher/fetcher_assets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func TestAccountFetcher_Fetch_Assets(t *testing.T) {
[]string{"/projects/<project UUID>/some_resource"},
"/projects/<project UUID>/some_resource",
inventory.WithRawAsset(assets[0]),
inventory.WithRelatedAssetIds([]string{}),
inventory.WithCloud(inventory.AssetCloud{
Provider: inventory.GcpCloudProvider,
Account: inventory.AssetCloudAccount{
Expand Down
7 changes: 6 additions & 1 deletion internal/inventory/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ func (a *AssetInventory) Run(ctx context.Context) {

func (a *AssetInventory) publish(assets []AssetEvent) {
events := lo.Map(assets, func(e AssetEvent, _ int) beat.Event {
var relatedEntity []string
relatedEntity = append(relatedEntity, e.Asset.Id...)
if len(e.Asset.RelatedEntityId) > 0 {
relatedEntity = append(relatedEntity, e.Asset.RelatedEntityId...)
}
return beat.Event{
Meta: mapstr.M{libevents.FieldMetaIndex: generateIndex(e.Asset)},
Timestamp: a.now(),
Expand All @@ -113,7 +118,7 @@ func (a *AssetInventory) publish(assets []AssetEvent) {
"network": e.Network,
"iam": e.IAM,
"resource_policies": e.ResourcePolicies,
"related.entity": e.Asset.Id,
"related.entity": relatedEntity,
},
}
})
Expand Down

0 comments on commit cdbd1b6

Please sign in to comment.