Skip to content

[Cloud Asset Inventory] Add extra resource fields #1 - #6991

Merged
kubasobon merged 8 commits into
elastic:mainfrom
kubasobon:asset-discovery/missing-aws-fields
Jul 6, 2026
Merged

[Cloud Asset Inventory] Add extra resource fields #1#6991
kubasobon merged 8 commits into
elastic:mainfrom
kubasobon:asset-discovery/missing-aws-fields

Conversation

@kubasobon

@kubasobon kubasobon commented Jun 26, 2026

Copy link
Copy Markdown
Member

Summary

Follow-up to InfoSec's review of #6991. Adds the remaining EC2 and ELB
fields InfoSec needs to retire their custom AWS CLI scripts for the FedRAMP
asset inventory. All new fields land in entity.attributes.* (non-ECS,
UpperCamelCase) — no ECS mapping change required.

Tracking: https://github.com/elastic/security-team/issues/17750

Changes

EC2 (entity.attributes):

  • ImageId, Platform, VpcId, SubnetId, State, RoleArn
  • Owner, CostCenter — resolved case-insensitively from instance tags

ELB v1 + v2 (entity.attributes):

  • LoadBalancerType — v2 reports the real type; v1 reports classic
  • AccountID
  • State — v2 only (State.Code); classic ELB exposes no state field
  • IPAddresses — NLB static IPs; ALB/classic are DNS-only (empty)
  • OwnerTag — required adding DescribeTags to both ELB Client
    interfaces and providers (batched to the 20-item AWS limit)

Notes

  • No elastic/integrations change: entity.attributes is flattened, so
    new keys need no mapping and there's no migration.
  • No new asset classifications, so ASSETS.md is unchanged. Route53 and
    EKS (also requested in the review) are separate follow-up PRs.
  • Mocks regenerated; unit tests cover EC2 attributes and the ELB
    Type/State/IPAddresses/OwnerTag flow end-to-end.
@mergify

This comment was marked as resolved.

kubasobon and others added 3 commits June 26, 2026 17:12
- gci: align map key spacing in fetcher_elb.go
- prealloc: preallocate routes slice in rds/provider.go
- revive: remove trailing empty line in azurefetcher groups loop
- revive: add default case to type switch in fetcher_resource_graph.go

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Follow-up to InfoSec review of the missing-AWS-fields PR. Surfaces
additional EC2 and ELB fields into entity.attributes (non-ECS,
UpperCamelCase) so the Asset Discovery integration can replace the
custom AWS CLI scripts.

EC2:
- ImageId, Platform, VpcId, SubnetId, State, RoleArn from the instance
- Owner, CostCenter looked up case-insensitively from tags

ELB v1 + v2:
- LoadBalancerType (v2 real type; v1 "classic"), AccountID
- State (v2 only; classic ELB has no state field)
- IPAddresses (NLB static IPs; ALB/classic are DNS-only)
- OwnerTag via new DescribeTags plumbing on both providers
@kubasobon kubasobon changed the title [Cloud Asset Inventory] Add extra resource fields Jul 3, 2026

@romulets romulets left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Biggest question is about the lifecycle event which we don't extract

}
if i.IamInstanceProfile != nil {
if v := pointers.Deref(i.IamInstanceProfile.Arn); v != "" {
attrs["RoleArn"] = v

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is IamInstanceProfile.Arn directly understandable from a ec2 instance attributes.RoleArn? Isn't it better perhaps to be more explicit on the naming?

Just asking, I'm ok with your call.

@kubasobon kubasobon Jul 6, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IamInstanceProfile.Arn is a not strictly a Role ARN, according to AWS docs - it's a Identity Profile attached to the EC2 (which contains the role).

Comment thread internal/inventory/asset.go Outdated

// Lifecycle holds non-ECS lifecycle timestamps for an asset (non-ECS fields use UpperCamelCase).
type Lifecycle struct {
CreatedAt *time.Time `json:"CreatedAt,omitempty"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/elastic/kibana/blob/main/x-pack/solutions/security/plugins/entity_store/common/domain/definitions/common_fields.ts#L140-L156

This field is not extracted. If we extract, I'm not sure we should have it capitalised, it doesn't follow the other fields

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'm aware. It's an untracked non-ECS, but I'm adding it to the integration on InfoSec's ask. It's not entity's creation date, but the resource's.

// timestamp. Values may arrive as time.Time (from typed SDK providers) or as RFC3339 strings
// (from the Resource Graph JSON response). Returns nil when no creation time is found.
func extractAzureCreatedAt(properties map[string]any) *time.Time {
for _, key := range []string{"createdTime", "timeCreated", "creationTime", "creationDate"} {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is interesting lol. I won't challenge because I know how azure is, but not super ideal haha

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, that's just Azure being Azure 😅

Comment thread internal/resources/providers/awslib/elb/load_balancer.go Outdated
if err != nil {
p.log.Errorf("Could not get route table for subnet %s of DB %s. Error: %v", *subnet.SubnetIdentifier, *dbInstance.DBInstanceIdentifier, err)
} else {
routes := make([]Route, 0, len(routeTableForSubnet.Routes))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memory thanks you

@kubasobon
kubasobon requested a review from romulets July 6, 2026 15:00
@mergify

mergify Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request
@kubasobon
kubasobon added this pull request to the merge queue Jul 6, 2026
Merged via the queue into elastic:main with commit a25d3cb Jul 6, 2026
12 checks passed
@kubasobon
kubasobon deleted the asset-discovery/missing-aws-fields branch July 6, 2026 16:46
gsarantid pushed a commit to gsarantid/cloudbeat that referenced this pull request Jul 6, 2026
…elastic#7183)

## Summary

Follow-up to InfoSec's review of elastic#6991: adds two AWS asset types the
FedRAMP inventory needs but cloudbeat didn't emit — **Route53 DNS
records** and **EKS clusters**. Both are greenfield providers +
fetchers. All resource-specific fields land in `entity.attributes.*`
(non-ECS, flattened), so no integration mapping change is required.

Tracking: elastic/security-team#17750
Merge after: elastic#6991

## Route53 (`awslib/route53`)

- New global provider (`ListHostedZones` → `ListResourceRecordSets`,
paginated); one asset per record set, carrying its parent zone.
- `entity.attributes`: `Type`, `ResourceRecords`, `Weight`, `Region`,
`ZoneID`, `ZoneName`, `AliasTargetDNS`, `AliasTargetZoneId`,
`HealthCheckId`.
- Classification: `{Infrastructure, "AWS Route53 DNS Record"}`. Region
reported as `global`. Records have no creation time in the SDK, so no
`CreatedAt`.

## EKS (`awslib/eks`)

- New regional provider (`ListClusters` → `DescribeCluster` per
cluster); one asset per cluster.
- `entity.attributes`: `Status`, `Version`, `Endpoint`, `RoleArn`,
`PlatformVersion`, `EndpointPublicAccess`, `EndpointPrivateAccess`,
`OwnerTag`; plus `entity.lifecycle.CreatedAt`.
- Classification: `{Orchestrator, "AWS EKS Cluster"}` (consistent with
GCP GKE).

## Notes

- **Dependency bump:** adding the EKS SDK pulled a core bump —
`aws-sdk-go-v2` 1.41.1→1.42.1, `smithy-go` 1.24.0→1.27.3, and two
indirect internal modules. Whole repo builds and tests pass.
- **ASSETS.md / spreadsheet:** regenerated (AWS coverage 21→23/85). The
`cloud_assets.xlsx` "EKS Cluster" row was moved from Infrastructure to
Orchestrator to match the classification (and GKE); the Route53 and EKS
"Updated Type" cells were filled so the generator marks them
implemented.
- **No `elastic/integrations` change:** `entity.attributes` is flattened
(arbitrary keys) and `entity.lifecycle.CreatedAt` +
`entity.type`/`sub_type` are already mapped by the 1.7.0 PR (#19795).

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

2 participants