go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/id/awsec2/metadata_local.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package awsec2 5 6 import ( 7 "context" 8 "io" 9 10 "github.com/aws/aws-sdk-go-v2/aws" 11 "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" 12 "github.com/aws/aws-sdk-go-v2/service/ec2" 13 14 ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" 15 ) 16 17 func NewLocal(cfg aws.Config) *LocalEc2InstanceMetadata { 18 return &LocalEc2InstanceMetadata{config: cfg} 19 } 20 21 // Ec2InstanceMetadata returns the instance id 22 // TODO: we may want to implement instance verification as documented in 23 // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html 24 type LocalEc2InstanceMetadata struct { 25 config aws.Config 26 } 27 28 func (m *LocalEc2InstanceMetadata) Identify() (Identity, error) { 29 metadata := imds.NewFromConfig(m.config) 30 ec2svc := ec2.NewFromConfig(m.config) 31 ctx := context.Background() 32 doc, err := metadata.GetInstanceIdentityDocument(ctx, &imds.GetInstanceIdentityDocumentInput{}) 33 if err != nil { 34 return Identity{}, err 35 } 36 name := "" 37 // try and fetch this from the metadata, if the tag metadata service is enabled. 38 nameTag, err := m.getMetadataValue(metadata, "tags/instance/Name") 39 if err == nil { 40 name = nameTag 41 } else { 42 // if not enabled, try and use the aws api as a fallback. this only works if the aws config is setup 43 // correctly on the ec2 instance. 44 filters := []ec2types.Filter{ 45 { 46 Name: aws.String("resource-id"), 47 Values: []string{doc.InstanceID}, 48 }, 49 } 50 tags, err := ec2svc.DescribeTags(ctx, &ec2.DescribeTagsInput{Filters: filters}) 51 if err == nil { 52 for _, t := range tags.Tags { 53 if t.Key != nil && *t.Key == "Name" && t.Value != nil { 54 name = *t.Value 55 } 56 } 57 } 58 } 59 return Identity{ 60 InstanceName: name, 61 InstanceID: MondooInstanceID(doc.AccountID, doc.Region, doc.InstanceID), 62 AccountID: "//platformid.api.mondoo.app/runtime/aws/accounts/" + doc.AccountID, 63 }, nil 64 } 65 66 // gets the metadata at the relative specified path. The base path is /latest/meta-data 67 // so the path param needs to only specify which metadata path is requested 68 func (m *LocalEc2InstanceMetadata) getMetadataValue(client *imds.Client, path string) (value string, err error) { 69 output, err := client.GetMetadata(context.TODO(), &imds.GetMetadataInput{ 70 Path: path, 71 }) 72 if err != nil { 73 return "", err 74 } 75 defer output.Content.Close() 76 bytes, err := io.ReadAll(output.Content) 77 if err != nil { 78 return "", err 79 } 80 resp := string(bytes) 81 return resp, err 82 }