go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/connection/vagrant.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package connection 5 6 import ( 7 "errors" 8 "strings" 9 10 "go.mondoo.com/cnquery/providers-sdk/v1/inventory" 11 "go.mondoo.com/cnquery/providers-sdk/v1/vault" 12 "go.mondoo.com/cnquery/providers/os/connection/shared" 13 "go.mondoo.com/cnquery/providers/os/connection/vagrant" 14 "go.mondoo.com/cnquery/providers/os/id/ids" 15 ) 16 17 const ( 18 Vagrant shared.ConnectionType = "vagrant" 19 ) 20 21 var _ shared.Connection = &VagrantConnection{} 22 23 type VagrantConnection struct { 24 SshConnection 25 } 26 27 func NewVagrantConnection(id uint32, conf *inventory.Config, asset *inventory.Asset) (*VagrantConnection, error) { 28 // expect unix shell by default 29 conn, err := resolveVagrantSshConf(id, conf, asset) 30 if err != nil { 31 return nil, err 32 } 33 res := VagrantConnection{ 34 SshConnection: *conn, 35 } 36 37 return &res, nil 38 } 39 40 func (p *VagrantConnection) ID() uint32 { 41 return p.id 42 } 43 44 func (p *VagrantConnection) Name() string { 45 return string(Vagrant) 46 } 47 48 func (p *VagrantConnection) Type() shared.ConnectionType { 49 return Vagrant 50 } 51 52 func resolveVagrantSshConf(id uint32, conf *inventory.Config, root *inventory.Asset) (*SshConnection, error) { 53 // For now, we do not provide the conf to the local connection 54 // conf might include sudo, which is only intended for the actual vagrant connection 55 // local currently does not need it. Quite the contrary, it cause issues. 56 localProvider := NewLocalConnection(id, nil, root) 57 58 // we run status first, since vagrant ssh-config does not return a proper state 59 // if in a multi-vm setup not all vms are running 60 cmd, err := localProvider.RunCommand("vagrant status") 61 if err != nil { 62 return nil, err 63 } 64 65 vmStatus, err := vagrant.ParseVagrantStatus(cmd.Stdout) 66 if err != nil { 67 return nil, err 68 } 69 70 k := conf.Host 71 vm, ok := vmStatus[k] 72 if !ok { 73 return nil, errors.New("could not find vagrant host: " + k) 74 } 75 76 if !vm { 77 return nil, errors.New("vm is not ready: " + k) 78 } 79 80 cmd, err = localProvider.RunCommand("vagrant ssh-config " + k) 81 if err != nil { 82 return nil, err 83 } 84 85 vmSshConfig, err := vagrant.ParseVagrantSshConfig(cmd.Stdout) 86 if err != nil { 87 return nil, err 88 } 89 90 err = migrateVagrantAssetToSsh(id, vmSshConfig[k], conf, root) 91 if err != nil { 92 return nil, err 93 } 94 return NewSshConnection(id, root.Connections[0], root) 95 } 96 97 func migrateVagrantAssetToSsh(id uint32, sshConfig *vagrant.VagrantVmSSHConfig, rootTransportConfig *inventory.Config, asset *inventory.Asset) error { 98 if sshConfig == nil { 99 return errors.New("missing vagrant ssh config") 100 } 101 102 cc := &inventory.Config{ 103 // TODO: do we need to support winrm? 104 Type: "ssh", 105 Runtime: "vagrant", 106 Host: sshConfig.HostName, 107 Insecure: strings.ToLower(sshConfig.StrictHostKeyChecking) == "no", 108 109 Port: int32(sshConfig.Port), 110 Sudo: rootTransportConfig.Sudo, 111 } 112 113 // load secret 114 credential, err := vault.NewPrivateKeyCredentialFromPath(sshConfig.User, sshConfig.IdentityFile, "") 115 if err != nil { 116 return err 117 } 118 cc.Credentials = append(cc.Credentials, credential) 119 120 asset.Name = sshConfig.Host 121 asset.Connections = []*inventory.Config{cc} 122 asset.IdDetector = []string{ids.IdDetector_Hostname, ids.IdDetector_SshHostkey} 123 124 return nil 125 }