diff --git a/.vscode/launch.json b/.vscode/launch.json index 8780adddfe..5973af4fd1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -177,6 +177,15 @@ "args": [ "status", ], + }, + { + "name": "cnquery-shell", + "type": "go", + "request": "launch", + "program": "${workspaceRoot}/apps/cnquery/cnquery.go", + "args": [ + "shell", "ssh", "user@18.215.249.49", + ], } ] } diff --git a/providers/os/connection/mock/mock.go b/providers/os/connection/mock/mock.go index c4565e0ccf..fd32ea8f19 100644 --- a/providers/os/connection/mock/mock.go +++ b/providers/os/connection/mock/mock.go @@ -139,7 +139,8 @@ func (c *Connection) RunCommand(command string) (*shared.Command, error) { found, ok := c.data.Commands[command] if !ok { // try to fetch command by hash (more reliable for whitespace) - found, ok = c.data.Commands[hashCmd(command)] + hash := hashCmd(command) + found, ok = c.data.Commands[hash] } if !ok { c.missing["command"][command] = true diff --git a/providers/os/connection/vagrant.go b/providers/os/connection/vagrant.go index 7799489161..d3efe0280f 100644 --- a/providers/os/connection/vagrant.go +++ b/providers/os/connection/vagrant.go @@ -119,7 +119,7 @@ func migrateVagrantAssetToSsh(id uint32, sshConfig *vagrant.VagrantVmSSHConfig, asset.Name = sshConfig.Host asset.Connections = []*inventory.Config{cc} - asset.IdDetector = []string{ids.IdDetector_Hostname, ids.IdDetector_SshHostkey, ids.IdDetector_MachineID} + asset.IdDetector = []string{ids.IdDetector_Hostname, ids.IdDetector_SshHostkey} return nil } diff --git a/providers/os/id/aws/testdata/instance.toml b/providers/os/id/aws/testdata/instance.toml index c102f710c9..e1f1a5aefe 100644 --- a/providers/os/id/aws/testdata/instance.toml +++ b/providers/os/id/aws/testdata/instance.toml @@ -22,7 +22,10 @@ content = "Red Hat Enterprise Linux Server release 7.2 (Maipo)" gid = 0 size = 0 -[commands."curl http://169.254.169.254/latest/dynamic/instance-identity/document"] +[commands."curl -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\" -X PUT \"http://169.254.169.254/latest/api/token\""] +stdout = "MYTOKEN" + +[commands."curl -H \"X-aws-ec2-metadata-token: MYTOKEN\" -v http://169.254.169.254/latest/dynamic/instance-identity/document"] stdout = """ { "devpayProductCodes" : null, @@ -43,6 +46,5 @@ stdout = """ } """ - -[commands."curl http://169.254.169.254/latest/meta-data/tags/instance/Name"] +[commands."curl -H \"X-aws-ec2-metadata-token: MYTOKEN\" -v http://169.254.169.254/latest/meta-data/tags/instance/Name"] stdout = "ec2-name" \ No newline at end of file diff --git a/providers/os/id/aws/testdata/instancearm.toml b/providers/os/id/aws/testdata/instancearm.toml index 36a5fab4ce..9b1113b320 100644 --- a/providers/os/id/aws/testdata/instancearm.toml +++ b/providers/os/id/aws/testdata/instancearm.toml @@ -34,7 +34,10 @@ content = "Red Hat Enterprise Linux Server release 7.2 (Maipo)" gid = 0 size = 0 -[commands."curl http://169.254.169.254/latest/dynamic/instance-identity/document"] +[commands."curl -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\" -X PUT \"http://169.254.169.254/latest/api/token\""] +stdout = "MYTOKEN" + +[commands."curl -H \"X-aws-ec2-metadata-token: MYTOKEN\" -v http://169.254.169.254/latest/dynamic/instance-identity/document"] stdout = """ { "devpayProductCodes" : null, @@ -55,5 +58,5 @@ stdout = """ } """ -[commands."curl http://169.254.169.254/latest/meta-data/tags/instance/Name"] +[commands."curl -H \"X-aws-ec2-metadata-token: MYTOKEN\" -v http://169.254.169.254/latest/meta-data/tags/instance/Name"] stdout = "ec2-name" \ No newline at end of file diff --git a/providers/os/id/aws/testdata/notinstance.toml b/providers/os/id/aws/testdata/notinstance.toml index 64bd8a39c6..45d26c5fa0 100644 --- a/providers/os/id/aws/testdata/notinstance.toml +++ b/providers/os/id/aws/testdata/notinstance.toml @@ -22,7 +22,10 @@ content = "Red Hat Enterprise Linux Server release 7.2 (Maipo)" gid = 0 size = 0 -[commands."curl http://169.254.169.254/latest/dynamic/instance-identity/document"] +[commands."curl -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\" -X PUT \"http://169.254.169.254/latest/api/token\""] +stdout = "MYTOKEN" + +[commands."curl -H \"X-aws-ec2-metadata-token: MYTOKEN\" -v http://169.254.169.254/latest/dynamic/instance-identity/document"] stdout = """ { "devpayProductCodes" : null, diff --git a/providers/os/id/awsec2/metadata_cmd.go b/providers/os/id/awsec2/metadata_cmd.go index 622ad3c254..4a5be11399 100644 --- a/providers/os/id/awsec2/metadata_cmd.go +++ b/providers/os/id/awsec2/metadata_cmd.go @@ -21,8 +21,29 @@ import ( ) const ( - identityUrl = "http://169.254.169.254/latest/dynamic/instance-identity/document" - tagNameUrl = "http://169.254.169.254/latest/meta-data/tags/instance/Name" + identityUrl = `-H "X-aws-ec2-metadata-token: %s" -v http://169.254.169.254/latest/dynamic/instance-identity/document` + tokenUrl = `-H "X-aws-ec2-metadata-token-ttl-seconds: 21600" -X PUT "http://169.254.169.254/latest/api/token"` + tagNameUrl = `-H "X-aws-ec2-metadata-token: %s" -v http://169.254.169.254/latest/meta-data/tags/instance/Name` + + identityUrlWindows = ` +$Headers = @{ + "X-aws-ec2-metadata-token" = %s +} +Invoke-RestMethod -TimeoutSec 1 -Headers $Headers -URI http://169.254.169.254/latest/dynamic/instance-identity/document -UseBasicParsing | ConvertTo-Json +` + + tokenUrlWindows = ` +$Headers = @{ + "X-aws-ec2-metadata-token-ttl-seconds" = "21600" +} +Invoke-RestMethod -Method Put -Uri "http://169.254.169.254/latest/api/token" -Headers $Headers -TimeoutSec 1 -UseBasicParsing +` + tagNameUrlWindows = ` +$Headers = @{ + "X-aws-ec2-metadata-token" = %s +} +Invoke-RestMethod -Method Put -Uri "http://169.254.169.254/latest/meta-data/tags/instance/Name" -Headers $Headers -TimeoutSec 1 -UseBasicParsing +` ) func NewCommandInstanceMetadata(conn shared.Connection, pf *inventory.Platform, config *aws.Config) *CommandInstanceMetadata { @@ -81,14 +102,17 @@ func (m *CommandInstanceMetadata) Identify() (Identity, error) { }, nil } -func curlWindows(url string) string { - return fmt.Sprintf("Invoke-RestMethod -TimeoutSec 1 -URI %s -UseBasicParsing | ConvertTo-Json", url) -} +type metadataType int + +const ( + document metadataType = iota + instanceNameTag +) -func (m *CommandInstanceMetadata) curlDocument(url string) (string, error) { +func (m *CommandInstanceMetadata) curlDocument(metadataType metadataType) (string, error) { switch { case m.platform.IsFamily(inventory.FAMILY_UNIX): - cmd, err := m.conn.RunCommand("curl " + url) + cmd, err := m.conn.RunCommand("curl " + tokenUrl) if err != nil { return "", err } @@ -96,12 +120,29 @@ func (m *CommandInstanceMetadata) curlDocument(url string) (string, error) { if err != nil { return "", err } + tokenString := strings.TrimSpace(string(data)) + + commandScript := "" + switch metadataType { + case document: + commandScript = "curl " + fmt.Sprintf(identityUrl, tokenString) + case instanceNameTag: + commandScript = "curl " + fmt.Sprintf(tagNameUrl, tokenString) + } + + cmd, err = m.conn.RunCommand(commandScript) + if err != nil { + return "", err + } + data, err = io.ReadAll(cmd.Stdout) + if err != nil { + return "", err + } return strings.TrimSpace(string(data)), nil case m.platform.IsFamily(inventory.FAMILY_WINDOWS): - curlCmd := curlWindows(url) - encoded := powershell.Encode(curlCmd) - cmd, err := m.conn.RunCommand(encoded) + tokenPwshEncoded := powershell.Encode(tokenUrlWindows) + cmd, err := m.conn.RunCommand(tokenPwshEncoded) if err != nil { return "", err } @@ -109,6 +150,24 @@ func (m *CommandInstanceMetadata) curlDocument(url string) (string, error) { if err != nil { return "", err } + tokenString := strings.TrimSpace(string(data)) + + commandScript := "" + switch metadataType { + case document: + commandScript = powershell.Encode(fmt.Sprintf(identityUrlWindows, tokenString)) + case instanceNameTag: + commandScript = powershell.Encode(fmt.Sprintf(tagNameUrlWindows, tokenString)) + } + + cmd, err = m.conn.RunCommand(commandScript) + if err != nil { + return "", err + } + data, err = io.ReadAll(cmd.Stdout) + if err != nil { + return "", err + } return strings.TrimSpace(string(data)), nil default: @@ -117,7 +176,7 @@ func (m *CommandInstanceMetadata) curlDocument(url string) (string, error) { } func (m *CommandInstanceMetadata) instanceNameTag() (string, error) { - res, err := m.curlDocument(tagNameUrl) + res, err := m.curlDocument(instanceNameTag) if err != nil { return "", err } @@ -128,5 +187,5 @@ func (m *CommandInstanceMetadata) instanceNameTag() (string, error) { } func (m *CommandInstanceMetadata) instanceIdentityDocument() (string, error) { - return m.curlDocument(identityUrl) + return m.curlDocument(document) } diff --git a/providers/os/id/awsec2/metadata_local_test.go b/providers/os/id/awsec2/metadata_local_test.go index be83fa6a52..a8b1e8e2e7 100644 --- a/providers/os/id/awsec2/metadata_local_test.go +++ b/providers/os/id/awsec2/metadata_local_test.go @@ -44,6 +44,13 @@ func TestEC2RoleProviderInstanceIdentityLocal(t *testing.T) { cfg := fakeConfig() cfg.HTTPClient = smithyhttp.ClientDoFunc(func(r *http.Request) (*http.Response, error) { url := r.URL.String() + if strings.Contains(url, "latest/api/token") { + return &http.Response{ + StatusCode: 200, + Header: http.Header{}, + Body: io.NopCloser(bytes.NewBufferString("mock-token")), + }, nil + } if strings.Contains(url, "tags/instance/Name") { return &http.Response{ StatusCode: 200, @@ -75,6 +82,13 @@ func TestEC2RoleProviderInstanceIdentityLocalDisabledTagsService(t *testing.T) { cfg := fakeConfig() cfg.HTTPClient = smithyhttp.ClientDoFunc(func(r *http.Request) (*http.Response, error) { url := r.URL.String() + if strings.Contains(url, "latest/api/token") { + return &http.Response{ + StatusCode: 200, + Header: http.Header{}, + Body: io.NopCloser(bytes.NewBufferString("mock-token")), + }, nil + } if strings.Contains(url, "tags/instance/Name") { return &http.Response{ StatusCode: 404, diff --git a/providers/os/id/awsec2/testdata/instance-identity_document_linux.toml b/providers/os/id/awsec2/testdata/instance-identity_document_linux.toml index fe308f1dd9..6f0fe79e62 100644 --- a/providers/os/id/awsec2/testdata/instance-identity_document_linux.toml +++ b/providers/os/id/awsec2/testdata/instance-identity_document_linux.toml @@ -10,7 +10,10 @@ stdout = "4.9.125-linuxkit" [files."/etc/redhat-release"] content = "Red Hat Enterprise Linux Server release 7.2 (Maipo)" -[commands."curl http://169.254.169.254/latest/dynamic/instance-identity/document"] +[commands."curl -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\" -X PUT \"http://169.254.169.254/latest/api/token\""] +stdout = "MYTOKEN" + +[commands."curl -H \"X-aws-ec2-metadata-token: MYTOKEN\" -v http://169.254.169.254/latest/dynamic/instance-identity/document"] stdout = """ { "devpayProductCodes" : null, @@ -31,5 +34,5 @@ stdout = """ } """ -[commands."curl http://169.254.169.254/latest/meta-data/tags/instance/Name"] +[commands."curl -H \"X-aws-ec2-metadata-token: MYTOKEN\" -v http://169.254.169.254/latest/meta-data/tags/instance/Name"] stdout = "ec2-name" \ No newline at end of file diff --git a/providers/os/id/awsec2/testdata/instance-identity_document_linux_no_tags.toml b/providers/os/id/awsec2/testdata/instance-identity_document_linux_no_tags.toml index 7a0d423768..6fbe2b1fb1 100644 --- a/providers/os/id/awsec2/testdata/instance-identity_document_linux_no_tags.toml +++ b/providers/os/id/awsec2/testdata/instance-identity_document_linux_no_tags.toml @@ -10,7 +10,10 @@ stdout = "4.9.125-linuxkit" [files."/etc/redhat-release"] content = "Red Hat Enterprise Linux Server release 7.2 (Maipo)" -[commands."curl http://169.254.169.254/latest/dynamic/instance-identity/document"] +[commands."curl -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\" -X PUT \"http://169.254.169.254/latest/api/token\""] +stdout = "MYTOKEN" + +[commands."curl -H \"X-aws-ec2-metadata-token: MYTOKEN\" -v http://169.254.169.254/latest/dynamic/instance-identity/document"] stdout = """ { "devpayProductCodes" : null, @@ -31,7 +34,7 @@ stdout = """ } """ -[commands."curl http://169.254.169.254/latest/meta-data/tags/instance/Name"] +[commands."curl -H \"X-aws-ec2-metadata-token: MYTOKEN\" -v http://169.254.169.254/latest/meta-data/tags/instance/Name"] stdout = """