internal/inventory/asset.go (308 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package inventory
import (
"github.com/mitchellh/mapstructure"
"github.com/samber/lo"
)
// AssetCategory is used to build the document index.
type AssetCategory string
const (
CategoryAccessManagement AssetCategory = "Access Management"
CategoryAccount AssetCategory = "Account"
CategoryContainerRegistry AssetCategory = "Container Registry"
CategoryContainerService AssetCategory = "Container Service"
CategoryDatabase AssetCategory = "Database"
CategoryFaaS AssetCategory = "FaaS"
CategoryFileSystemService AssetCategory = "File System Service"
CategoryFirewall AssetCategory = "Firewall"
CategoryGateway AssetCategory = "Gateway"
CategoryGroup AssetCategory = "Group"
CategoryHost AssetCategory = "Host"
CategoryIdentity AssetCategory = "Identity"
CategoryInfrastructure AssetCategory = "Infrastructure"
CategoryLoadBalancer AssetCategory = "Load Balancer"
CategoryMessagingService AssetCategory = "Messaging Service"
CategoryNetworking AssetCategory = "Networking"
CategoryOrchestrator AssetCategory = "Orchestrator"
CategoryOrganization AssetCategory = "Organization"
CategoryPrivateEndpoint AssetCategory = "Private Endpoint"
CategoryServiceAccount AssetCategory = "Service Account"
CategoryServiceUsageTechnology AssetCategory = "Service Usage Technology"
CategorySnapshot AssetCategory = "Snapshot"
CategoryStorageBucket AssetCategory = "Storage Bucket"
CategorySubnet AssetCategory = "Subnet"
CategoryVolume AssetCategory = "Volume"
CategoryWebService AssetCategory = "Web Service"
)
// AssetType is used to build the document index.
type AssetType string
const (
AwsCloudProvider = "aws"
AzureCloudProvider = "azure"
GcpCloudProvider = "gcp"
)
// AssetClassification holds the taxonomy of an asset
type AssetClassification struct {
Category AssetCategory `json:"category"`
Type AssetType `json:"type"`
}
// AssetClassifications below are used to generate
// 'internal/inventory/ASSETS.md'. Please keep formatting consistent.
var (
// AWS
AssetClassificationAwsEc2Instance = AssetClassification{CategoryHost, "AWS EC2 Instance"}
AssetClassificationAwsElbV1 = AssetClassification{CategoryLoadBalancer, "AWS Elastic Load Balancer"}
AssetClassificationAwsElbV2 = AssetClassification{CategoryLoadBalancer, "AWS Elastic Load Balancer v2"}
AssetClassificationAwsIamPolicy = AssetClassification{CategoryAccessManagement, "AWS IAM Policy"}
AssetClassificationAwsIamRole = AssetClassification{CategoryServiceAccount, "AWS IAM Role"}
AssetClassificationAwsIamUser = AssetClassification{CategoryIdentity, "AWS IAM User"}
AssetClassificationAwsLambdaEventSourceMapping = AssetClassification{CategoryFaaS, "AWS Lambda Event Source Mapping"}
AssetClassificationAwsLambdaFunction = AssetClassification{CategoryFaaS, "AWS Lambda Function"}
AssetClassificationAwsLambdaLayer = AssetClassification{CategoryFaaS, "AWS Lambda Layer"}
AssetClassificationAwsInternetGateway = AssetClassification{CategoryGateway, "AWS Internet Gateway"}
AssetClassificationAwsNatGateway = AssetClassification{CategoryGateway, "AWS NAT Gateway"}
AssetClassificationAwsNetworkAcl = AssetClassification{CategoryNetworking, "AWS EC2 Network ACL"}
AssetClassificationAwsNetworkInterface = AssetClassification{CategoryNetworking, "AWS EC2 Network Interface"}
AssetClassificationAwsSecurityGroup = AssetClassification{CategoryFirewall, "AWS EC2 Security Group"}
AssetClassificationAwsSubnet = AssetClassification{CategoryNetworking, "AWS EC2 Subnet"}
AssetClassificationAwsTransitGateway = AssetClassification{CategoryGateway, "AWS Transit Gateway"}
AssetClassificationAwsTransitGatewayAttachment = AssetClassification{CategoryGateway, "AWS Transit Gateway Attachment"}
AssetClassificationAwsVpcPeeringConnection = AssetClassification{CategoryNetworking, "AWS VPC Peering Connection"}
AssetClassificationAwsVpc = AssetClassification{CategoryNetworking, "AWS VPC"}
AssetClassificationAwsRds = AssetClassification{CategoryDatabase, "AWS RDS Instance"}
AssetClassificationAwsS3Bucket = AssetClassification{CategoryStorageBucket, "AWS S3 Bucket"}
AssetClassificationAwsSnsTopic = AssetClassification{CategoryMessagingService, "AWS SNS Topic"}
// Azure
AssetClassificationAzureAppService = AssetClassification{CategoryWebService, "Azure App Service"}
AssetClassificationAzureContainerRegistry = AssetClassification{CategoryContainerRegistry, "Azure Container Registry"}
AssetClassificationAzureCosmosDBAccount = AssetClassification{CategoryInfrastructure, "Azure Cosmos DB Account"}
AssetClassificationAzureCosmosDBSQLDatabase = AssetClassification{CategoryInfrastructure, "Azure Cosmos DB SQL Database"}
AssetClassificationAzureDisk = AssetClassification{CategoryVolume, "Azure Disk"}
AssetClassificationAzureElasticPool = AssetClassification{CategoryDatabase, "Azure Elastic Pool"}
AssetClassificationAzureEntraGroup = AssetClassification{CategoryGroup, "Azure Microsoft Entra ID Group"}
AssetClassificationAzureEntraUser = AssetClassification{CategoryIdentity, "Azure Microsoft Entra ID User"}
AssetClassificationAzureResourceGroup = AssetClassification{CategoryAccessManagement, "Azure Resource Group"}
AssetClassificationAzureRoleDefinition = AssetClassification{CategoryAccessManagement, "Azure RoleDefinition"}
AssetClassificationAzureSQLDatabase = AssetClassification{CategoryDatabase, "Azure SQL Database"}
AssetClassificationAzureSQLServer = AssetClassification{CategoryDatabase, "Azure SQL Server"}
AssetClassificationAzureServicePrincipal = AssetClassification{CategoryServiceAccount, "Azure Principal"}
AssetClassificationAzureSnapshot = AssetClassification{CategorySnapshot, "Azure Snapshot"}
AssetClassificationAzureStorageAccount = AssetClassification{CategoryPrivateEndpoint, "Azure Storage Account"}
AssetClassificationAzureStorageBlobContainer = AssetClassification{CategoryStorageBucket, "Azure Storage Blob Container"}
AssetClassificationAzureStorageBlobService = AssetClassification{CategoryServiceUsageTechnology, "Azure Storage Blob Service"}
AssetClassificationAzureStorageFileService = AssetClassification{CategoryFileSystemService, "Azure Storage File Service"}
AssetClassificationAzureStorageFileShare = AssetClassification{CategoryFileSystemService, "Azure Storage File Share"}
AssetClassificationAzureStorageQueue = AssetClassification{CategoryMessagingService, "Azure Storage Queue"}
AssetClassificationAzureStorageQueueService = AssetClassification{CategoryMessagingService, "Azure Storage Queue Service"}
AssetClassificationAzureStorageTable = AssetClassification{CategoryDatabase, "Azure Storage Table"}
AssetClassificationAzureStorageTableService = AssetClassification{CategoryServiceUsageTechnology, "Azure Storage Table Service"}
AssetClassificationAzureSubscription = AssetClassification{CategoryAccessManagement, "Azure Subscription"}
AssetClassificationAzureTenant = AssetClassification{CategoryAccessManagement, "Azure Tenant"}
AssetClassificationAzureVirtualMachine = AssetClassification{CategoryHost, "Azure Virtual Machine"}
// GCP
AssetClassificationGcpProject = AssetClassification{CategoryAccount, "GCP Project"}
AssetClassificationGcpOrganization = AssetClassification{CategoryOrganization, "GCP Organization"}
AssetClassificationGcpFolder = AssetClassification{CategoryOrganization, "GCP Folder"}
AssetClassificationGcpInstance = AssetClassification{CategoryHost, "GCP Compute Instance"}
AssetClassificationGcpBucket = AssetClassification{CategoryStorageBucket, "GCP Bucket"}
AssetClassificationGcpFirewall = AssetClassification{CategoryFirewall, "GCP Firewall"}
AssetClassificationGcpSubnet = AssetClassification{CategorySubnet, "GCP Subnet"}
AssetClassificationGcpServiceAccount = AssetClassification{CategoryAccessManagement, "GCP Service Account"}
AssetClassificationGcpServiceAccountKey = AssetClassification{CategoryAccessManagement, "GCP Service Account Key"}
AssetClassificationGcpGkeCluster = AssetClassification{CategoryOrchestrator, "GCP Kubernetes Engine (GKE) Cluster"}
AssetClassificationGcpForwardingRule = AssetClassification{CategoryLoadBalancer, "GCP Load Balancing Forwarding Rule"}
AssetClassificationGcpIamRole = AssetClassification{CategoryServiceUsageTechnology, "GCP IAM Role"}
AssetClassificationGcpCloudFunction = AssetClassification{CategoryFaaS, "GCP Cloud Function"}
AssetClassificationGcpCloudRunService = AssetClassification{CategoryContainerService, "GCP Cloud Run Service"}
AssetClassificationGcpNetwork = AssetClassification{CategoryNetworking, "GCP VPC Network"}
)
// AssetEvent holds the whole asset
type AssetEvent struct {
Entity Entity
Event Event
Cloud *Cloud
Container *Container
Fass *Fass
Group *Group
Host *Host
Network *Network
Orchestrator *Orchestrator
Organization *Organization
URL *URL
User *User
Labels map[string]string
Tags []string
RawAttributes *any
}
type Organization struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
}
type Fass struct {
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
}
type URL struct {
Full string `json:"full"`
}
// Entity contains the identifiers of the asset
type Entity struct {
Id string `json:"id"`
Name string `json:"name"`
AssetClassification
// non exported fields
relatedEntityId []string
}
type Event struct {
Kind string `json:"kind"`
}
type Network struct {
Name string `json:"name,omitempty"`
Direction string `json:"direction,omitempty"`
Type string `json:"type,omitempty"`
}
type Cloud struct {
Provider string `json:"provider,omitempty"`
Region string `json:"region,omitempty"`
AvailabilityZone string `json:"availability_zone,omitempty"`
AccountID string `json:"account.id,omitempty"`
AccountName string `json:"account.name,omitempty"`
InstanceID string `json:"instance.id,omitempty"`
InstanceName string `json:"instance.name,omitempty"`
MachineType string `json:"machine.type,omitempty"`
ServiceName string `json:"service.name,omitempty"`
ProjectID string `json:"project.id,omitempty"`
ProjectName string `json:"project.name,omitempty"`
}
type Group struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Domain string `json:"domain,omitempty"`
}
type Host struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Architecture string `json:"architecture,omitempty"`
Type string `json:"type,omitempty"`
IP string `json:"ip,omitempty"`
MacAddress []string `json:"mac,omitempty"`
}
type User struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Roles []string `json:"roles,omitempty"`
}
type Orchestrator struct {
ClusterID string `json:"cluster.id,omitempty"`
ClusterName string `json:"cluster.name,omitempty"`
Type string `json:"type,omitempty"`
}
type Container struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
ImageName string `json:"image.name,omitempty"`
}
// AssetEnricher functional builder function
type AssetEnricher func(asset *AssetEvent)
func NewAssetEvent(c AssetClassification, id string, name string, enrichers ...AssetEnricher) AssetEvent {
a := AssetEvent{
Entity: Entity{
Id: id,
Name: name,
AssetClassification: c,
},
Event: Event{
Kind: "asset",
},
}
for _, enrich := range enrichers {
enrich(&a)
}
return a
}
func WithRawAsset(raw any) AssetEnricher {
return func(a *AssetEvent) {
a.RawAttributes = &raw
}
}
func WithRelatedAssetIds(ids []string) AssetEnricher {
return func(a *AssetEvent) {
ids = lo.Filter(ids, func(id string, _ int) bool {
return id != ""
})
if len(ids) == 0 {
a.Entity.relatedEntityId = nil
return
}
a.Entity.relatedEntityId = lo.Uniq(ids)
}
}
func WithLabels(labels map[string]string) AssetEnricher {
return func(a *AssetEvent) {
if len(labels) == 0 {
return
}
a.Labels = labels
}
}
func WithLabelsFromAny(labels map[string]any) AssetEnricher {
return func(a *AssetEvent) {
if len(labels) == 0 {
return
}
output := map[string]string{}
if err := mapstructure.Decode(labels, &output); err != nil {
return
}
a.Labels = output
}
}
func WithNetwork(network Network) AssetEnricher {
return func(a *AssetEvent) {
a.Network = &network
}
}
func WithCloud(cloud Cloud) AssetEnricher {
return func(a *AssetEvent) {
a.Cloud = &cloud
}
}
func WithGroup(group Group) AssetEnricher {
return func(a *AssetEvent) {
a.Group = &group
}
}
func WithHost(host Host) AssetEnricher {
return func(a *AssetEvent) {
a.Host = &host
}
}
func WithTags(tags []string) AssetEnricher {
return func(a *AssetEvent) {
if len(tags) == 0 {
return
}
a.Tags = tags
}
}
func WithUser(user User) AssetEnricher {
return func(a *AssetEvent) {
a.User = &user
}
}
func EmptyEnricher() AssetEnricher {
return func(_ *AssetEvent) {}
}
func WithOrganization(org Organization) AssetEnricher {
return func(a *AssetEvent) {
a.Organization = &org
}
}
func WithFass(fass Fass) AssetEnricher {
return func(a *AssetEvent) {
a.Fass = &fass
}
}
func WithURL(url URL) AssetEnricher {
return func(a *AssetEvent) {
a.URL = &url
}
}
func WithOrchestrator(orchestrator Orchestrator) AssetEnricher {
return func(a *AssetEvent) {
a.Orchestrator = &orchestrator
}
}
func WithContainer(container Container) AssetEnricher {
return func(a *AssetEvent) {
a.Container = &container
}
}