From 971489933c9f86b7812c7557e117ec5c6a82978f Mon Sep 17 00:00:00 2001 From: Preslav Gerchev Date: Mon, 27 May 2024 12:27:50 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=B9=20Rework=20azure=20snapshot=20conn?= =?UTF-8?q?ection=20to=20use=20device=20connection.=20Drop=20all=20flags?= =?UTF-8?q?=20that=20were=20used=20as=20a=20temporary=20workaround.=20(#40?= =?UTF-8?q?85)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Preslav --- providers/azure/config/config.go | 21 -- .../azureinstancesnapshot/instance.go | 84 +++++++ .../azureinstancesnapshot/instance_test.go | 71 ++++++ .../connection/azureinstancesnapshot/lun.go | 193 ---------------- .../azureinstancesnapshot/lun_test.go | 138 ------------ .../azureinstancesnapshot/provider.go | 209 ++++-------------- .../azureinstancesnapshot/provider_test.go | 12 +- .../azureinstancesnapshot/scanner.go | 60 +++++ .../connection/azureinstancesnapshot/setup.go | 44 +--- .../azureinstancesnapshot/snapshot.go | 65 +----- providers/azure/go.mod | 8 + providers/azure/go.sum | 30 +++ providers/azure/provider/provider.go | 20 -- 13 files changed, 318 insertions(+), 637 deletions(-) create mode 100644 providers/azure/connection/azureinstancesnapshot/instance.go create mode 100644 providers/azure/connection/azureinstancesnapshot/instance_test.go delete mode 100644 providers/azure/connection/azureinstancesnapshot/lun.go delete mode 100644 providers/azure/connection/azureinstancesnapshot/lun_test.go create mode 100644 providers/azure/connection/azureinstancesnapshot/scanner.go diff --git a/providers/azure/config/config.go b/providers/azure/config/config.go index 69ce1eff40..1d4213ec32 100644 --- a/providers/azure/config/config.go +++ b/providers/azure/config/config.go @@ -98,27 +98,6 @@ var Config = plugin.Provider{ Desc: "Comma-separated list of Azure subscriptions to exclude.", Option: plugin.FlagOption_Hidden, }, - { - Long: "skip-snapshot-cleanup", - Type: plugin.FlagType_Bool, - Default: "", - Desc: "If set, no cleanup will be performed for the snapshot connection.", - Option: plugin.FlagOption_Hidden, - }, - { - Long: "skip-snapshot-setup", - Type: plugin.FlagType_Bool, - Default: "", - Desc: "If set, no setup will be performed for the snapshot connection. It is expected that the target's disk is already attached. Use together with --lun.", - Option: plugin.FlagOption_Hidden, - }, - { - Long: "lun", - Type: plugin.FlagType_Int, - Default: "", - Desc: "The logical unit number of the attached disk that should be scanned. Use together with --skip-snapshot-setup.", - Option: plugin.FlagOption_Hidden, - }, }, }, }, diff --git a/providers/azure/connection/azureinstancesnapshot/instance.go b/providers/azure/connection/azureinstancesnapshot/instance.go new file mode 100644 index 0000000000..5c1abf28bd --- /dev/null +++ b/providers/azure/connection/azureinstancesnapshot/instance.go @@ -0,0 +1,84 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package azureinstancesnapshot + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + compute "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute" + "github.com/cockroachdb/errors" + "github.com/rs/zerolog/log" +) + +type instanceInfo struct { + subscriptionId string + resourceGroup string + instanceName string + location string + bootDiskId string + zones []*string + // Attach the entire VM response as well + vm compute.VirtualMachine +} + +func (s *instanceInfo) getFirstAvailableLun() (int, error) { + takenLuns := []int{} + + if s.vm.Properties.StorageProfile == nil { + return 0, errors.New("instance storage profile not found") + } + if s.vm.Properties.StorageProfile.DataDisks == nil { + return 0, errors.New("instance data disks not found") + } + + for _, disk := range s.vm.Properties.StorageProfile.DataDisks { + takenLuns = append(takenLuns, int(*disk.Lun)) + } + + availableLuns := []int{} + for i := 0; i < 64; i++ { + // exclude the taken LUNs + available := true + for _, d := range takenLuns { + if i == d { + available = false + break + } + } + if available { + availableLuns = append(availableLuns, i) + } else { + // log just for visibility + log.Debug().Int("LUN", i).Msg("azure snapshot> LUN is taken, skipping") + } + } + if len(availableLuns) == 0 { + return 0, errors.New("no available LUNs") + } + return availableLuns[0], nil +} + +func GetInstanceInfo(resourceGroup, instanceName, subId string, token azcore.TokenCredential) (instanceInfo, error) { + ctx := context.Background() + ii := instanceInfo{} + + computeSvc, err := computeClient(token, subId, nil) + if err != nil { + return ii, err + } + + instance, err := computeSvc.Get(ctx, resourceGroup, instanceName, &compute.VirtualMachinesClientGetOptions{}) + if err != nil { + return ii, err + } + ii.resourceGroup = resourceGroup + ii.instanceName = *instance.Name + ii.bootDiskId = *instance.Properties.StorageProfile.OSDisk.ManagedDisk.ID + ii.location = *instance.Location + ii.subscriptionId = subId + ii.zones = instance.Zones + ii.vm = instance.VirtualMachine + return ii, nil +} diff --git a/providers/azure/connection/azureinstancesnapshot/instance_test.go b/providers/azure/connection/azureinstancesnapshot/instance_test.go new file mode 100644 index 0000000000..46bce90dc1 --- /dev/null +++ b/providers/azure/connection/azureinstancesnapshot/instance_test.go @@ -0,0 +1,71 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package azureinstancesnapshot + +import ( + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute" + "github.com/stretchr/testify/require" +) + +func TestGetFirstAvailableLun(t *testing.T) { + t.Run("no luns available", func(t *testing.T) { + instanceInfo := &instanceInfo{ + vm: armcompute.VirtualMachine{ + Properties: &armcompute.VirtualMachineProperties{ + StorageProfile: &armcompute.StorageProfile{ + DataDisks: []*armcompute.DataDisk{}, + }, + }, + }, + } + // fill in all available LUNs for the scanner + for i := int32(0); i < 64; i++ { + instanceInfo.vm.Properties.StorageProfile.DataDisks = append(instanceInfo.vm.Properties.StorageProfile.DataDisks, &armcompute.DataDisk{ + Lun: to.Ptr(i), + }) + } + + _, err := instanceInfo.getFirstAvailableLun() + require.Error(t, err) + }) + t.Run("first available lun on a scanner with no disks", func(t *testing.T) { + instanceInfo := instanceInfo{ + vm: armcompute.VirtualMachine{ + Properties: &armcompute.VirtualMachineProperties{ + StorageProfile: &armcompute.StorageProfile{ + DataDisks: []*armcompute.DataDisk{}, + }, + }, + }, + } + + lun, err := instanceInfo.getFirstAvailableLun() + require.NoError(t, err) + require.Equal(t, 0, lun) + }) + t.Run("first available lun on a scanner with some disks", func(t *testing.T) { + instanceInfo := instanceInfo{ + vm: armcompute.VirtualMachine{ + Properties: &armcompute.VirtualMachineProperties{ + StorageProfile: &armcompute.StorageProfile{ + DataDisks: []*armcompute.DataDisk{}, + }, + }, + }, + } + // fill in 15 luns + for i := int32(0); i < 16; i++ { + instanceInfo.vm.Properties.StorageProfile.DataDisks = append(instanceInfo.vm.Properties.StorageProfile.DataDisks, &armcompute.DataDisk{ + Lun: to.Ptr(i), + }) + } + + lun, err := instanceInfo.getFirstAvailableLun() + require.NoError(t, err) + require.Equal(t, 16, lun) + }) +} diff --git a/providers/azure/connection/azureinstancesnapshot/lun.go b/providers/azure/connection/azureinstancesnapshot/lun.go deleted file mode 100644 index c788b1f4a3..0000000000 --- a/providers/azure/connection/azureinstancesnapshot/lun.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) Mondoo, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package azureinstancesnapshot - -import ( - "encoding/json" - "fmt" - "io" - "strconv" - "strings" - - "github.com/cockroachdb/errors" - "github.com/rs/zerolog/log" -) - -type scsiDeviceInfo struct { - // the LUN, e.g. 3 - Lun int32 - // where the disk is mounted, e.g. /dev/sda - VolumePath string -} - -type scsiDevices = []scsiDeviceInfo - -// TODO: we should combine this with the OS-connection blockDevices struct -type blockDevices struct { - BlockDevices []blockDevice `json:"blockDevices,omitempty"` -} - -type blockDevice struct { - Name string `json:"name,omitempty"` - FsType string `json:"fstype,omitempty"` - Label string `json:"label,omitempty"` - Uuid string `json:"uuid,omitempty"` - Mountpoint []string `json:"mountpoints,omitempty"` - Children []blockDevice `json:"children,omitempty"` -} - -func getAvailableLun(scsiDevices scsiDevices) (int32, error) { - takenLuns := []int32{} - for _, d := range scsiDevices { - takenLuns = append(takenLuns, d.Lun) - } - - availableLuns := []int32{} - // the available LUNs are 0-63, so we exclude everything thats in takenLuns - for i := int32(0); i < 64; i++ { - exists := false - for _, d := range takenLuns { - if d == i { - exists = true - break - } - } - if exists { - // log just for visibility - log.Debug().Int32("LUN", i).Msg("azure snapshot> LUN is taken, skipping") - } else { - availableLuns = append(availableLuns, i) - } - } - if len(availableLuns) == 0 { - return 0, errors.New("no available LUNs to attach disk to") - } - return availableLuns[0], nil -} - -// https://learn.microsoft.com/en-us/azure/virtual-machines/linux/azure-to-guest-disk-mapping -// for more information. we want to find the LUNs of the data disks and their mount location -func (c *AzureSnapshotConnection) listScsiDevices() ([]scsiDeviceInfo, error) { - cmd, err := c.localConn.RunCommand("lsscsi --brief") - if err != nil { - return nil, err - } - if cmd.ExitStatus != 0 { - outErr, err := io.ReadAll(cmd.Stderr) - if err != nil { - return nil, err - } - return nil, fmt.Errorf("failed to list logical unit numbers: %s", outErr) - } - data, err := io.ReadAll(cmd.Stdout) - if err != nil { - return nil, err - } - output := string(data) - return parseLsscsiOutput(output) -} - -// https://learn.microsoft.com/en-us/azure/virtual-machines/linux/azure-to-guest-disk-mapping -// for more information. we want to find the LUNs of the data disks and their mount location -func (c *AzureSnapshotConnection) listBlockDevices() (*blockDevices, error) { - cmd, err := c.localConn.RunCommand("lsblk -f --json") - if err != nil { - return nil, err - } - if cmd.ExitStatus != 0 { - outErr, err := io.ReadAll(cmd.Stderr) - if err != nil { - return nil, err - } - return nil, fmt.Errorf("failed to list logical unit numbers: %s", outErr) - } - data, err := io.ReadAll(cmd.Stdout) - if err != nil { - return nil, err - } - blockEntries := &blockDevices{} - if err := json.Unmarshal(data, blockEntries); err != nil { - return nil, err - } - return blockEntries, nil -} - -func filterScsiDevices(scsiDevices scsiDevices, lun int32) []scsiDeviceInfo { - matching := []scsiDeviceInfo{} - for _, d := range scsiDevices { - if d.Lun == lun { - matching = append(matching, d) - } - } - - return matching -} - -// there can be multiple devices mounted at the same LUN. the Azure API only provides -// the LUN so we need to find all the blocks, mounted at that LUN. then we find the first one -// that has no mounted partitions and use that as the target device. this is a best-effort approach -func findMatchingDeviceByBlock(scsiDevices scsiDevices, blockDevices *blockDevices) (string, error) { - matchingBlocks := []blockDevice{} - for _, device := range scsiDevices { - for _, block := range blockDevices.BlockDevices { - devName := "/dev/" + block.Name - if devName == device.VolumePath { - matchingBlocks = append(matchingBlocks, block) - } - } - } - - if len(matchingBlocks) == 0 { - return "", errors.New("no matching blocks found") - } - - var target string - for _, b := range matchingBlocks { - log.Debug().Str("name", b.Name).Msg("azure snapshot> checking block") - mounted := false - for _, ch := range b.Children { - if len(ch.Mountpoint) > 0 && ch.Mountpoint[0] != "" { - log.Debug().Str("name", ch.Name).Msg("azure snapshot> has mounted partitons, skipping") - mounted = true - } - if !mounted { - target = "/dev/" + b.Name - } - } - } - - return target, nil -} - -// parses the output from running 'lsscsi --brief' and gets the device info, the output looks like this: -// [0:0:0:0] /dev/sda -// [1:0:0:0] /dev/sdb -func parseLsscsiOutput(output string) (scsiDevices, error) { - lines := strings.Split(strings.TrimSpace(output), "\n") - mountedDevices := []scsiDeviceInfo{} - for _, line := range lines { - log.Debug().Str("line", line).Msg("azure snapshot> parsing lsscsi output") - if line == "" { - continue - } - parts := strings.Fields(strings.TrimSpace(line)) - if len(parts) != 2 { - return nil, fmt.Errorf("invalid lsscsi output: %s", line) - } - lunInfo := parts[0] - path := parts[1] - // trim the [], turning [1:0:0:0] into 1:0:0:0 - trimLun := strings.Trim(lunInfo, "[]") - splitLun := strings.Split(trimLun, ":") - // the LUN is the last one - lun := splitLun[len(splitLun)-1] - lunInt, err := strconv.Atoi(lun) - if err != nil { - return nil, err - } - mountedDevices = append(mountedDevices, scsiDeviceInfo{Lun: int32(lunInt), VolumePath: path}) - } - - return mountedDevices, nil -} diff --git a/providers/azure/connection/azureinstancesnapshot/lun_test.go b/providers/azure/connection/azureinstancesnapshot/lun_test.go deleted file mode 100644 index f71617c006..0000000000 --- a/providers/azure/connection/azureinstancesnapshot/lun_test.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) Mondoo, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package azureinstancesnapshot - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestParseLsscsiOutput(t *testing.T) { - // different padding for the device names on purpose + an extra blank line - output := ` - [0:0:0:0] /dev/sda - [0:0:1:1] /dev/sdb - [0:0:1:2] /dev/sdc - [0:0:0:3] /dev/sdd - - ` - devices, err := parseLsscsiOutput(output) - assert.NoError(t, err) - assert.Len(t, devices, 4) - expected := scsiDevices{ - {Lun: 0, VolumePath: "/dev/sda"}, - {Lun: 1, VolumePath: "/dev/sdb"}, - {Lun: 2, VolumePath: "/dev/sdc"}, - {Lun: 3, VolumePath: "/dev/sdd"}, - } - assert.ElementsMatch(t, expected, devices) -} - -func TestFilterScsiDevices(t *testing.T) { - devices := scsiDevices{ - {Lun: 0, VolumePath: "/dev/sda"}, - {Lun: 1, VolumePath: "/dev/sdb"}, - {Lun: 2, VolumePath: "/dev/sdc"}, - {Lun: 3, VolumePath: "/dev/sdd"}, - } - - filtered := filterScsiDevices(devices, int32(1)) - expected := scsiDevices{ - {Lun: 1, VolumePath: "/dev/sdb"}, - } - assert.ElementsMatch(t, expected, filtered) - - filtered = filterScsiDevices(devices, int32(4)) - assert.Len(t, filtered, 0) -} - -func TestFindDeviceByBlock(t *testing.T) { - devices := scsiDevices{ - {Lun: 0, VolumePath: "/dev/sda"}, - {Lun: 0, VolumePath: "/dev/sdb"}, - } - t.Run("find device by block", func(t *testing.T) { - blockDevices := &blockDevices{ - BlockDevices: []blockDevice{ - { - Name: "sda", - Children: []blockDevice{ - { - Name: "sda1", - Mountpoint: []string{"/"}, - }, - }, - }, - { - Name: "sdb", - Children: []blockDevice{ - { - Name: "sdb1", - Mountpoint: []string{""}, - }, - }, - }, - }, - } - target, err := findMatchingDeviceByBlock(devices, blockDevices) - assert.NoError(t, err) - expected := "/dev/sdb" - assert.Equal(t, expected, target) - }) - - t.Run("no matches", func(t *testing.T) { - blockDevices := &blockDevices{ - BlockDevices: []blockDevice{ - { - Name: "sdc", - Children: []blockDevice{ - { - Name: "sdc1", - Mountpoint: []string{"/"}, - }, - }, - }, - { - Name: "sdc", - Children: []blockDevice{ - { - Name: "sdc1", - Mountpoint: []string{"/tmp"}, - }, - }, - }, - }, - } - _, err := findMatchingDeviceByBlock(devices, blockDevices) - assert.Error(t, err) - }) - t.Run("empty target as all blocks are mounted", func(t *testing.T) { - blockDevices := &blockDevices{ - BlockDevices: []blockDevice{ - { - Name: "sda", - Children: []blockDevice{ - { - Name: "sda1", - Mountpoint: []string{"/"}, - }, - }, - }, - { - Name: "sdb", - Children: []blockDevice{ - { - Name: "sdb1", - Mountpoint: []string{"/tmp"}, - }, - }, - }, - }, - } - target, err := findMatchingDeviceByBlock(devices, blockDevices) - assert.NoError(t, err) - assert.Empty(t, target) - }) -} diff --git a/providers/azure/connection/azureinstancesnapshot/provider.go b/providers/azure/connection/azureinstancesnapshot/provider.go index 59bce3b0ae..a5b4121f30 100644 --- a/providers/azure/connection/azureinstancesnapshot/provider.go +++ b/providers/azure/connection/azureinstancesnapshot/provider.go @@ -4,24 +4,18 @@ package azureinstancesnapshot import ( - "strconv" + "fmt" - "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/cockroachdb/errors" "github.com/rs/zerolog/log" - "go.mondoo.com/cnquery/v11/mrn" "go.mondoo.com/cnquery/v11/providers-sdk/v1/inventory" "go.mondoo.com/cnquery/v11/providers-sdk/v1/plugin" "go.mondoo.com/cnquery/v11/providers-sdk/v1/util/azauth" "go.mondoo.com/cnquery/v11/providers-sdk/v1/vault" "go.mondoo.com/cnquery/v11/providers/azure/connection/shared" - "go.mondoo.com/cnquery/v11/providers/os/connection/fs" + "go.mondoo.com/cnquery/v11/providers/os/connection/device" "go.mondoo.com/cnquery/v11/providers/os/connection/local" - "go.mondoo.com/cnquery/v11/providers/os/connection/snapshot" - "go.mondoo.com/cnquery/v11/providers/os/detector" - "go.mondoo.com/cnquery/v11/providers/os/id/azcompute" - "go.mondoo.com/cnquery/v11/providers/os/id/ids" ) const ( @@ -34,13 +28,16 @@ const ( Lun string = "lun" ) -// the instance from which we're performing the scan -type azureScannerInstance struct { - subscriptionId string - resourceGroup string - name string - // holds extra information about the instance, fetched via the Azure API - instanceInfo *instanceInfo +type AzureSnapshotConnection struct { + // the device connection, used to mount the disk once we attach it to the VM + *device.DeviceConnection + // the snapshot creator, used to create snapshots and disks via the Azure API + snapshotCreator *snapshotCreator + // the VM we are connected to + instanceInfo instanceInfo + // only set if the connection mounts the disk. used for detaching the disk via the Azure API + mountedDiskInfo mountedDiskInfo + identifier string } type assetInfo struct { @@ -55,57 +52,12 @@ type scanTarget struct { SubscriptionId string } -type mountInfo struct { - deviceName string -} - type mountedDiskInfo struct { diskId string diskName string } -func determineScannerInstanceInfo(localConn *local.LocalConnection, token azcore.TokenCredential) (*azureScannerInstance, error) { - pf, detected := detector.DetectOS(localConn) - if !detected { - return nil, errors.New("could not detect platform") - } - scannerInstanceInfo, err := azcompute.Resolve(localConn, pf) - if err != nil { - return nil, errors.Wrap(err, "Azure snapshot provider must run from an Azure VM instance") - } - identity, err := scannerInstanceInfo.Identify() - if err != nil { - return nil, errors.Wrap(err, "Azure snapshot provider must run from an Azure VM instance") - } - instanceID := identity.InstanceID - - // parse the platform id - // platformid.api.mondoo.app/runtime/azure/subscriptions/f1a2873a-6b27-4097-aa7c-3df51f103e96/resourceGroups/preslav-test-ssh_group/providers/Microsoft.Compute/virtualMachines/preslav-test-ssh - platformMrn, err := mrn.NewMRN(instanceID) - if err != nil { - return nil, err - } - subId, err := platformMrn.ResourceID("subscriptions") - if err != nil { - return nil, err - } - resourceGrp, err := platformMrn.ResourceID("resourceGroups") - if err != nil { - return nil, err - } - instanceName, err := platformMrn.ResourceID("virtualMachines") - if err != nil { - return nil, err - } - - return &azureScannerInstance{ - subscriptionId: subId, - resourceGroup: resourceGrp, - name: instanceName, - }, nil -} - -func ParseTarget(conf *inventory.Config, scanner *azureScannerInstance) (scanTarget, error) { +func ParseTarget(conf *inventory.Config, scanner azureScannerInstance) (scanTarget, error) { target := conf.Options["target"] if target == "" { return scanTarget{}, errors.New("target is required") @@ -137,11 +89,11 @@ func NewAzureSnapshotConnection(id uint32, conf *inventory.Config, asset *invent if err != nil { return nil, err } - // local connection is required here to run lsscsi and lsblk to identify where the mounted disk is + localConn := local.NewConnection(id, conf, asset) // 1. check if we run on an azure instance - scanner, err := determineScannerInstanceInfo(localConn, token) + scanner, err := determineScannerInstanceInfo(localConn) if err != nil { return nil, err } @@ -157,77 +109,37 @@ func NewAzureSnapshotConnection(id uint32, conf *inventory.Config, asset *invent return nil, err } + instanceInfo, err := GetInstanceInfo(scanner.resourceGroup, scanner.name, scanner.subscriptionId, token) + if err != nil { + return nil, err + } + c := &AzureSnapshotConnection{ - opts: conf.Options, snapshotCreator: sc, - scanner: *scanner, identifier: conf.PlatformId, - localConn: localConn, + instanceInfo: instanceInfo, } - var lun int32 - // 3. we either clone the target disk/snapshot and mount it - // or we skip the setup and expect the disk to be already attached - if !c.skipSetup() { - instanceInfo, err := InstanceInfo(scanner.resourceGroup, scanner.name, scanner.subscriptionId, token) - if err != nil { - return nil, err - } - c.scanner.instanceInfo = &instanceInfo - scsiDevices, err := c.listScsiDevices() - if err != nil { - c.Close() - return nil, err - } - lun, err = getAvailableLun(scsiDevices) - if err != nil { - c.Close() - return nil, err - } - diskInfo, ai, err := c.setupDiskAndMount(target, lun) - if err != nil { - c.Close() - return nil, err - } - asset.Name = ai.assetName - conf.PlatformId = ai.platformId - c.mountedDiskInfo = diskInfo - } else { - log.Debug().Msg("skipping snapshot setup, expect that disk is already attached") - if c.opts[Lun] == "" { - return nil, errors.New("lun is required to hint where the target disk is located") - } - lunOpt, err := strconv.Atoi(c.opts[Lun]) - if err != nil { - return nil, errors.Wrap(err, "could not parse lun") - } - lun = int32(lunOpt) - asset.Name = target.Target - } - - // 4. once mounted (either by the connection or from the outside), identify the disk by the provided LUN - mi, err := c.identifyDisk(lun) + lun, err := c.instanceInfo.getFirstAvailableLun() if err != nil { c.Close() return nil, err } - c.mountInfo = mi - // 5. mount volume - shell := []string{"sh", "-c"} - volumeMounter := snapshot.NewVolumeMounter(shell) - volumeMounter.VolumeAttachmentLoc = c.mountInfo.deviceName - err = volumeMounter.Mount() + diskInfo, ai, err := c.setupDiskAndMount(target, lun) if err != nil { - log.Error().Err(err).Msg("unable to complete mount step") c.Close() return nil, err } + asset.Name = ai.assetName + conf.PlatformId = ai.platformId + c.mountedDiskInfo = diskInfo - conf.Options["path"] = volumeMounter.ScanDir - // create and initialize fs provider - fsConn, err := fs.NewConnection(id, &inventory.Config{ - Path: volumeMounter.ScanDir, + // note: this is important for the device manager to know which LUN to use + conf.Options[Lun] = fmt.Sprintf("%d", lun) + conf.Options[device.PlatformIdInject] = ai.platformId + // create and initialize device conn provider + deviceConn, err := device.NewDeviceConnection(id, &inventory.Config{ PlatformId: conf.PlatformId, Options: conf.Options, Type: conf.Type, @@ -238,17 +150,7 @@ func NewAzureSnapshotConnection(id uint32, conf *inventory.Config, asset *invent return nil, err } - c.FileSystemConnection = fsConn - c.volumeMounter = volumeMounter - - var ok bool - asset.IdDetector = []string{ids.IdDetector_Hostname} - asset.Platform, ok = detector.DetectOS(fsConn) - if !ok { - c.Close() - return nil, errors.New("failed to detect OS") - } - asset.Id = conf.Type + c.DeviceConnection = deviceConn asset.Platform.Kind = c.Kind() asset.Platform.Runtime = c.Runtime() return c, nil @@ -256,64 +158,31 @@ func NewAzureSnapshotConnection(id uint32, conf *inventory.Config, asset *invent var _ plugin.Closer = (*AzureSnapshotConnection)(nil) -type AzureSnapshotConnection struct { - *fs.FileSystemConnection - opts map[string]string - volumeMounter *snapshot.VolumeMounter - snapshotCreator *snapshotCreator - scanner azureScannerInstance - mountInfo mountInfo - // only set if the connection mounts the disk. used for cleanup - mountedDiskInfo mountedDiskInfo - identifier string - // used on the target VM to run commands, related to finding the target disk by LUN - localConn *local.LocalConnection -} - func (c *AzureSnapshotConnection) Close() { log.Debug().Msg("closing azure snapshot connection") if c == nil { return } - if c.volumeMounter != nil { - err := c.volumeMounter.UnmountVolumeFromInstance() - if err != nil { - log.Error().Err(err).Msg("unable to unmount volume") - } + // we first close the device connection, which will unmount the disk + if c.DeviceConnection != nil { + c.DeviceConnection.Close() } - if c.skipDiskCleanup() { - log.Debug().Msgf("skipping azure snapshot cleanup, %s flag is set to true", SkipCleanup) - } else if c.snapshotCreator != nil { + if c.snapshotCreator != nil { if c.mountedDiskInfo.diskName != "" { - err := c.snapshotCreator.detachDisk(c.mountedDiskInfo.diskName, c.scanner.instanceInfo) + err := c.snapshotCreator.detachDisk(c.mountedDiskInfo.diskName, c.instanceInfo) if err != nil { log.Error().Err(err).Msg("unable to detach volume") } } if c.mountedDiskInfo.diskName != "" { - err := c.snapshotCreator.deleteCreatedDisk(c.scanner.resourceGroup, c.mountedDiskInfo.diskName) + err := c.snapshotCreator.deleteCreatedDisk(c.instanceInfo.resourceGroup, c.mountedDiskInfo.diskName) if err != nil { log.Error().Err(err).Msg("could not delete created disk") } } } - - if c.volumeMounter != nil { - err := c.volumeMounter.RemoveTempScanDir() - if err != nil { - log.Error().Err(err).Msg("unable to remove dir") - } - } -} - -func (c *AzureSnapshotConnection) skipDiskCleanup() bool { - return c.opts[SkipCleanup] == "true" -} - -func (c *AzureSnapshotConnection) skipSetup() bool { - return c.opts[SkipSetup] == "true" } func (c *AzureSnapshotConnection) Kind() string { @@ -333,5 +202,5 @@ func (c *AzureSnapshotConnection) Type() shared.ConnectionType { } func (c *AzureSnapshotConnection) Config() *inventory.Config { - return c.FileSystemConnection.Conf + return c.DeviceConnection.Conf } diff --git a/providers/azure/connection/azureinstancesnapshot/provider_test.go b/providers/azure/connection/azureinstancesnapshot/provider_test.go index d12426135d..e61b66d12c 100644 --- a/providers/azure/connection/azureinstancesnapshot/provider_test.go +++ b/providers/azure/connection/azureinstancesnapshot/provider_test.go @@ -12,7 +12,7 @@ import ( func TestParseTarget(t *testing.T) { t.Run("parse snapshot target with just a resource name", func(t *testing.T) { - scanner := &azureScannerInstance{ + scanner := azureScannerInstance{ resourceGroup: "my-rg", name: "my-instance", } @@ -31,7 +31,7 @@ func TestParseTarget(t *testing.T) { assert.Equal(t, SnapshotTargetType, scanTarget.TargetType) }) t.Run("parse instance target with just a resource name", func(t *testing.T) { - scanner := &azureScannerInstance{ + scanner := azureScannerInstance{ resourceGroup: "my-rg", name: "my-instance", } @@ -50,7 +50,7 @@ func TestParseTarget(t *testing.T) { assert.Equal(t, InstanceTargetType, scanTarget.TargetType) }) t.Run("parse disk target with just a resource name", func(t *testing.T) { - scanner := &azureScannerInstance{ + scanner := azureScannerInstance{ resourceGroup: "my-rg", name: "my-instance", } @@ -69,7 +69,7 @@ func TestParseTarget(t *testing.T) { assert.Equal(t, DiskTargetType, scanTarget.TargetType) }) t.Run("parse snapshot target with a fully qualified Azure resource ID", func(t *testing.T) { - scanner := &azureScannerInstance{} + scanner := azureScannerInstance{} target := "/subscriptions/f1a2873a-6c27-4097-aa7c-3df51f103e91/resourceGroups/my-other-rg/providers/Microsoft.Compute/snapshots/test-snp" conf := &inventory.Config{ @@ -85,7 +85,7 @@ func TestParseTarget(t *testing.T) { assert.Equal(t, SnapshotTargetType, scanTarget.TargetType) }) t.Run("parse instance target with a fully qualified Azure resource ID", func(t *testing.T) { - scanner := &azureScannerInstance{} + scanner := azureScannerInstance{} target := "/subscriptions/f1a2873a-6b27-4097-aa7c-3df51f103e96/resourceGroups/debian_group/providers/Microsoft.Compute/virtualMachines/debian" conf := &inventory.Config{ @@ -101,7 +101,7 @@ func TestParseTarget(t *testing.T) { assert.Equal(t, InstanceTargetType, scanTarget.TargetType) }) t.Run("parse disk target with a fully qualified Azure resource ID", func(t *testing.T) { - scanner := &azureScannerInstance{} + scanner := azureScannerInstance{} target := "/subscriptions/f1a2873a-6b27-4097-aa7c-3df51f103e96/resourceGroups/debian_group/providers/Microsoft.Compute/disks/disk-1" conf := &inventory.Config{ diff --git a/providers/azure/connection/azureinstancesnapshot/scanner.go b/providers/azure/connection/azureinstancesnapshot/scanner.go new file mode 100644 index 0000000000..d5a51e9074 --- /dev/null +++ b/providers/azure/connection/azureinstancesnapshot/scanner.go @@ -0,0 +1,60 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package azureinstancesnapshot + +import ( + "github.com/cockroachdb/errors" + "go.mondoo.com/cnquery/v11/mrn" + "go.mondoo.com/cnquery/v11/providers/os/connection/local" + "go.mondoo.com/cnquery/v11/providers/os/detector" + "go.mondoo.com/cnquery/v11/providers/os/id/azcompute" +) + +// the VM from which we're performing the scan +type azureScannerInstance struct { + subscriptionId string + resourceGroup string + name string +} + +func determineScannerInstanceInfo(localConn *local.LocalConnection) (azureScannerInstance, error) { + pf, detected := detector.DetectOS(localConn) + if !detected { + return azureScannerInstance{}, errors.New("could not detect platform") + } + scannerInstanceInfo, err := azcompute.Resolve(localConn, pf) + if err != nil { + return azureScannerInstance{}, errors.Wrap(err, "Azure snapshot provider must run from an Azure VM instance") + } + identity, err := scannerInstanceInfo.Identify() + if err != nil { + return azureScannerInstance{}, errors.Wrap(err, "Azure snapshot provider must run from an Azure VM instance") + } + instanceID := identity.InstanceID + + // parse the platform id + // platformid.api.mondoo.app/runtime/azure/subscriptions/f1a2873a-6b27-4097-aa7c-3df51f103e96/resourceGroups/preslav-test-ssh_group/providers/Microsoft.Compute/virtualMachines/preslav-test-ssh + platformMrn, err := mrn.NewMRN(instanceID) + if err != nil { + return azureScannerInstance{}, err + } + subId, err := platformMrn.ResourceID("subscriptions") + if err != nil { + return azureScannerInstance{}, err + } + resourceGrp, err := platformMrn.ResourceID("resourceGroups") + if err != nil { + return azureScannerInstance{}, err + } + instanceName, err := platformMrn.ResourceID("virtualMachines") + if err != nil { + return azureScannerInstance{}, err + } + + return azureScannerInstance{ + subscriptionId: subId, + resourceGroup: resourceGrp, + name: instanceName, + }, nil +} diff --git a/providers/azure/connection/azureinstancesnapshot/setup.go b/providers/azure/connection/azureinstancesnapshot/setup.go index 358c72dc44..fc63b7f180 100644 --- a/providers/azure/connection/azureinstancesnapshot/setup.go +++ b/providers/azure/connection/azureinstancesnapshot/setup.go @@ -13,40 +13,12 @@ import ( "go.mondoo.com/cnquery/v11/providers/os/id/azcompute" ) -func (c *AzureSnapshotConnection) identifyDisk(lun int32) (mountInfo, error) { - scsiDevices, err := c.listScsiDevices() - if err != nil { - return mountInfo{}, err - } - - // only interested in the scsi devices that match the provided LUN - filteredScsiDevices := filterScsiDevices(scsiDevices, lun) - if len(filteredScsiDevices) == 0 { - return mountInfo{}, errors.New("no matching scsi devices found") - } - - // if we have exactly one device present at the LUN we can directly point the volume mounter towards it - if len(filteredScsiDevices) == 1 { - return mountInfo{deviceName: filteredScsiDevices[0].VolumePath}, nil - } - - blockDevices, err := c.listBlockDevices() - if err != nil { - return mountInfo{}, err - } - target, err := findMatchingDeviceByBlock(filteredScsiDevices, blockDevices) - if err != nil { - return mountInfo{}, err - } - return mountInfo{deviceName: target}, nil -} - -func (c *AzureSnapshotConnection) setupDiskAndMount(target scanTarget, lun int32) (mountedDiskInfo, assetInfo, error) { +func (c *AzureSnapshotConnection) setupDiskAndMount(target scanTarget, lun int) (mountedDiskInfo, assetInfo, error) { mi, ai, err := c.setupDisk(target) if err != nil { return mountedDiskInfo{}, assetInfo{}, err } - err = c.snapshotCreator.attachDisk(c.scanner.instanceInfo, mi.diskName, mi.diskId, lun) + err = c.snapshotCreator.attachDisk(c.instanceInfo, mi.diskName, mi.diskId, lun) if err != nil { return mountedDiskInfo{}, assetInfo{}, err } @@ -55,9 +27,6 @@ func (c *AzureSnapshotConnection) setupDiskAndMount(target scanTarget, lun int32 } func (c *AzureSnapshotConnection) setupDisk(target scanTarget) (mountedDiskInfo, assetInfo, error) { - if c.scanner.instanceInfo == nil { - return mountedDiskInfo{}, assetInfo{}, errors.New("cannot setup disk, instance info not found") - } mi := mountedDiskInfo{} ai := assetInfo{} h := sha256.New() @@ -73,6 +42,7 @@ func (c *AzureSnapshotConnection) setupDisk(target scanTarget) (mountedDiskInfo, diskName := fmt.Sprintf("mondoo-snapshot-%s-%s", diskHash[:8], now.Format("2006-01-02t15-04-05z00-00")) switch target.TargetType { case InstanceTargetType: + log.Debug().Str("instance", target.Target).Msg("azure snapshot> targeting instance") instanceInfo, err := c.snapshotCreator.instanceInfo(target.ResourceGroup, target.Target) if err != nil { return mountedDiskInfo{}, assetInfo{}, err @@ -82,7 +52,7 @@ func (c *AzureSnapshotConnection) setupDisk(target scanTarget) (mountedDiskInfo, } log.Debug().Str("boot disk", instanceInfo.bootDiskId).Msg("found boot disk for instance, cloning") - disk, err := c.snapshotCreator.cloneDisk(instanceInfo.bootDiskId, c.scanner.resourceGroup, diskName, c.scanner.instanceInfo.location, c.scanner.instanceInfo.vm.Zones) + disk, err := c.snapshotCreator.cloneDisk(instanceInfo.bootDiskId, c.instanceInfo.resourceGroup, diskName, c.instanceInfo.location, c.instanceInfo.vm.Zones) if err != nil { log.Error().Err(err).Msg("could not complete disk cloning") return mountedDiskInfo{}, assetInfo{}, errors.Wrap(err, "could not complete disk cloning") @@ -93,12 +63,13 @@ func (c *AzureSnapshotConnection) setupDisk(target scanTarget) (mountedDiskInfo, ai.assetName = instanceInfo.instanceName ai.platformId = azcompute.MondooAzureInstanceID(*instanceInfo.vm.ID) case SnapshotTargetType: + log.Debug().Str("snapshot", target.Target).Msg("azure snapshot> targeting snapshot") snapshotInfo, err := c.snapshotCreator.snapshotInfo(target.ResourceGroup, target.Target) if err != nil { return mountedDiskInfo{}, assetInfo{}, err } - disk, err := c.snapshotCreator.createSnapshotDisk(snapshotInfo.snapshotId, c.scanner.resourceGroup, diskName, c.scanner.instanceInfo.location, c.scanner.instanceInfo.vm.Zones) + disk, err := c.snapshotCreator.createSnapshotDisk(snapshotInfo.snapshotId, c.instanceInfo.resourceGroup, diskName, c.instanceInfo.location, c.instanceInfo.vm.Zones) if err != nil { log.Error().Err(err).Msg("could not complete snapshot disk creation") return mountedDiskInfo{}, assetInfo{}, errors.Wrap(err, "could not create disk from snapshot") @@ -109,12 +80,13 @@ func (c *AzureSnapshotConnection) setupDisk(target scanTarget) (mountedDiskInfo, ai.assetName = target.Target ai.platformId = SnapshotPlatformMrn(snapshotInfo.snapshotId) case DiskTargetType: + log.Debug().Str("disk", target.Target).Msg("azur snapshot> targeting disk") diskInfo, err := c.snapshotCreator.diskInfo(target.ResourceGroup, target.Target) if err != nil { return mountedDiskInfo{}, assetInfo{}, err } - disk, err := c.snapshotCreator.cloneDisk(diskInfo.diskId, c.scanner.resourceGroup, diskName, c.scanner.instanceInfo.location, c.scanner.instanceInfo.vm.Zones) + disk, err := c.snapshotCreator.cloneDisk(diskInfo.diskId, c.instanceInfo.resourceGroup, diskName, c.instanceInfo.location, c.instanceInfo.vm.Zones) if err != nil { log.Error().Err(err).Msg("could not complete disk cloning") return mountedDiskInfo{}, assetInfo{}, errors.Wrap(err, "could not complete disk cloning") diff --git a/providers/azure/connection/azureinstancesnapshot/snapshot.go b/providers/azure/connection/azureinstancesnapshot/snapshot.go index 069454b0b4..d764ba2023 100644 --- a/providers/azure/connection/azureinstancesnapshot/snapshot.go +++ b/providers/azure/connection/azureinstancesnapshot/snapshot.go @@ -5,7 +5,6 @@ package azureinstancesnapshot import ( "context" - "errors" "time" "github.com/rs/zerolog/log" @@ -29,17 +28,6 @@ type snapshotCreator struct { labels map[string]*string } -type instanceInfo struct { - subscriptionId string - resourceGroup string - instanceName string - location string - bootDiskId string - zones []*string - // Attach the entire VM response as well - vm compute.VirtualMachine -} - type snapshotInfo struct { snapshotName string snapshotId string @@ -81,30 +69,7 @@ func computeClient(token azcore.TokenCredential, subId string, opts *policy.Clie } func (sc *snapshotCreator) instanceInfo(resourceGroup, instanceName string) (instanceInfo, error) { - return InstanceInfo(resourceGroup, instanceName, sc.subscriptionId, sc.token) -} - -func InstanceInfo(resourceGroup, instanceName, subId string, token azcore.TokenCredential) (instanceInfo, error) { - ctx := context.Background() - ii := instanceInfo{} - - computeSvc, err := computeClient(token, subId, nil) - if err != nil { - return ii, err - } - - instance, err := computeSvc.Get(ctx, resourceGroup, instanceName, &compute.VirtualMachinesClientGetOptions{}) - if err != nil { - return ii, err - } - ii.resourceGroup = resourceGroup - ii.instanceName = *instance.Name - ii.bootDiskId = *instance.Properties.StorageProfile.OSDisk.ManagedDisk.ID - ii.location = *instance.Location - ii.subscriptionId = subId - ii.zones = instance.Zones - ii.vm = instance.VirtualMachine - return ii, nil + return GetInstanceInfo(resourceGroup, instanceName, sc.subscriptionId, sc.token) } func (sc *snapshotCreator) snapshotInfo(resourceGroup, snapshotName string) (snapshotInfo, error) { @@ -208,34 +173,32 @@ func (sc *snapshotCreator) cloneDisk(sourceDiskId, resourceGroupName, diskName s } // attachDisk attaches a disk to an instance -func (sc *snapshotCreator) attachDisk(targetInstance *instanceInfo, diskName, diskId string, lun int32) error { - if targetInstance == nil { - return errors.New("targetInstance is nil, cannot attach disk") - } +func (sc *snapshotCreator) attachDisk(targetInstance instanceInfo, diskName, diskId string, lun int) error { ctx := context.Background() - log.Debug().Str("disk-name", diskName).Int32("LUN", lun).Msg("attach disk") + log.Debug().Str("disk-name", diskName).Int("LUN", lun).Msg("attach disk") computeSvc, err := sc.computeClient() if err != nil { return err } + newDisks := []*compute.DataDisk{} // the Azure API requires all disks to be specified, even the already attached ones. // we simply attach the new disk to the end of the already present list of data disks - disks := targetInstance.vm.Properties.StorageProfile.DataDisks - disks = append(disks, &compute.DataDisk{ + newDisks = append(newDisks, targetInstance.vm.Properties.StorageProfile.DataDisks...) + newDisks = append(newDisks, &compute.DataDisk{ Name: &diskName, CreateOption: to.Ptr(compute.DiskCreateOptionTypesAttach), DeleteOption: to.Ptr(compute.DiskDeleteOptionTypesDelete), Caching: to.Ptr(compute.CachingTypesNone), - Lun: &lun, + Lun: to.Ptr(int32(lun)), ManagedDisk: &compute.ManagedDiskParameters{ - ID: &diskId, + ID: to.Ptr(diskId), }, }) - props := targetInstance.vm.Properties - props.StorageProfile.DataDisks = disks vm := compute.VirtualMachineUpdate{ Properties: &compute.VirtualMachineProperties{ - StorageProfile: props.StorageProfile, + StorageProfile: &compute.StorageProfile{ + DataDisks: newDisks, + }, }, } @@ -261,17 +224,13 @@ func (sc *snapshotCreator) attachDisk(targetInstance *instanceInfo, diskName, di return err } -func (sc *snapshotCreator) detachDisk(diskName string, targetInstance *instanceInfo) error { - if targetInstance == nil { - return errors.New("targetInstance is nil, cannot detach disk") - } +func (sc *snapshotCreator) detachDisk(diskName string, targetInstance instanceInfo) error { ctx := context.Background() log.Debug().Str("instance-name", targetInstance.instanceName).Msg("detach disk from instance") computeSvc, err := sc.computeClient() if err != nil { return err } - // we stored the disks as they were before attaching the new one in the targetInstance. // we simply use that list which will result in the new disk being detached vm := compute.VirtualMachineUpdate{ diff --git a/providers/azure/go.mod b/providers/azure/go.mod index dc4dccc421..b183088b0d 100644 --- a/providers/azure/go.mod +++ b/providers/azure/go.mod @@ -89,6 +89,8 @@ require ( github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.161.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect v1.23.6 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.28.3 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.8 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect @@ -201,6 +203,7 @@ require ( github.com/hashicorp/vault/api v1.14.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect + github.com/hnakamur/go-scp v1.0.2 // indirect github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jgautheron/goconst v1.7.1 // indirect @@ -211,9 +214,11 @@ require ( github.com/julz/importas v0.1.0 // indirect github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/kisielk/errcheck v1.7.0 // indirect github.com/kkHAIKE/contextcheck v1.1.5 // indirect github.com/klauspost/compress v1.17.4 // indirect + github.com/kr/fs v0.1.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/kulti/thelper v0.6.3 // indirect @@ -252,6 +257,7 @@ require ( github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + github.com/pkg/sftp v1.13.6 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polyfloyd/go-errorlint v1.5.1 // indirect github.com/prometheus/client_golang v1.19.1 // indirect @@ -277,6 +283,7 @@ require ( github.com/securego/gosec/v2 v2.20.1-0.20240525090044-5f0084eb01a9 // indirect github.com/segmentio/fasthash v1.0.3 // indirect github.com/segmentio/ksuid v1.0.4 // indirect + github.com/sethvargo/go-password v0.3.0 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/sirupsen/logrus v1.9.3 // indirect @@ -347,6 +354,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.4.7 // indirect + howett.net/plist v1.0.1 // indirect moul.io/http2curl v1.0.0 // indirect mvdan.cc/gofumpt v0.6.0 // indirect mvdan.cc/unparam v0.0.0-20240427195214-063aff900ca1 // indirect diff --git a/providers/azure/go.sum b/providers/azure/go.sum index b1357175bb..f2594be08c 100644 --- a/providers/azure/go.sum +++ b/providers/azure/go.sum @@ -154,6 +154,10 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 h1:4OYVp0705xu8yjdyoWi github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7/go.mod h1:vd7ESTEvI76T2Na050gODNmNU7+OyKrIKroYTu4ABiI= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.161.4 h1:JBcPadBAnSwqUZQ1o2XOkTXy7GBcidpupkXZf02parw= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.161.4/go.mod h1:iJ2sQeUTkjNp3nL7kE/Bav0xXYhtiRCRP5ZXk4jFhCQ= +github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect v1.23.6 h1:BnSoZkU8mVfQYGEZ1s8TGcZ5L24ATs0xJ+7GIPIC12w= +github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect v1.23.6/go.mod h1:Egll0ipi6HYnWKjGrwYbBlwUAKl/jb7mOpR6CCkuU9A= github.com/aws/aws-sdk-go-v2/service/ecr v1.28.3 h1:NsP8PA4Kw1sA6UKl3ZFRIcA9dWomePbmoRIvfOl+HKs= github.com/aws/aws-sdk-go-v2/service/ecr v1.28.3/go.mod h1:X52zjAVRaXklEU1TE/wO8kyyJSr9cJx9ZsqliWbyRys= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.8 h1:TUUD/99lvNFDTAPT5aR58Yu+Yn7z8lZtaiiXQJRWhMs= @@ -227,7 +231,10 @@ github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= github.com/daixiang0/gci v0.13.4 h1:61UGkmpoAcxHM2hhNkZEf5SzwQtWJXTSws7jaPyqwlw= @@ -450,10 +457,15 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/hnakamur/go-scp v1.0.2 h1:i2I0O0pjAaX4BXJFrp1blsIdjOBekc5QOaB0AbdO1d0= +github.com/hnakamur/go-scp v1.0.2/go.mod h1:Dh9GtPFBkiDI1KY1nmf+W7eVCWWmRjJitkCYgvWv+Zc= +github.com/hnakamur/go-sshd v0.0.0-20170228152141-dccc3399d26a h1:p8dbHRhXhPSwVZqk76FguLzyeCZuvCqFlaYSqXOzbyI= +github.com/hnakamur/go-sshd v0.0.0-20170228152141-dccc3399d26a/go.mod h1:R+6I3EdoV6ofbNqJsArhT9+Pnu57DxtmDJAQfxkCbGo= github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8= github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= @@ -476,6 +488,8 @@ github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV0= github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= @@ -484,9 +498,13 @@ github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LX github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -592,6 +610,8 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjL github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= +github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -652,6 +672,8 @@ github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtr github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= +github.com/sethvargo/go-password v0.3.0 h1:OLFHZ91Z7NiNP3dnaPxLxCDXlb6TBuxFzMvv6bu+Ptw= +github.com/sethvargo/go-password v0.3.0/go.mod h1:p6we8DZ0eyYXof9pon7Cqrw98N4KTaYiadDml1dUEEw= github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec= github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= @@ -791,7 +813,9 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= @@ -834,6 +858,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -865,6 +890,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200828081204-131dc92a58d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -896,6 +922,7 @@ golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -994,6 +1021,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -1007,6 +1035,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs= honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= +howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= +howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8= moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE= mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo= diff --git a/providers/azure/provider/provider.go b/providers/azure/provider/provider.go index f45c90789c..6adabe7346 100644 --- a/providers/azure/provider/provider.go +++ b/providers/azure/provider/provider.go @@ -6,7 +6,6 @@ package provider import ( "context" "errors" - "fmt" "go.mondoo.com/cnquery/v11" "go.mondoo.com/cnquery/v11/llx" @@ -45,9 +44,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) subscriptionsToExclude := flags["subscriptions-exclude"] certificatePath := flags["certificate-path"] certificateSecret := flags["certificate-secret"] - skipSnapshotCleanup := flags["skip-snapshot-cleanup"] - skipSnapshotSetup := flags["skip-snapshot-setup"] - lun := flags["lun"] opts := map[string]string{} creds := []*vault.Credential{} @@ -62,22 +58,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) if len(subscriptionsToExclude.Value) > 0 { opts["subscriptions-exclude"] = string(subscriptionsToExclude.Value) } - if len(lun.Value) > 0 { - opts[azureinstancesnapshot.Lun] = fmt.Sprint(lun.RawData().Value.(int64)) - } - // the presence of the flag indicates that we should skip cleanup - if skipCleanup := skipSnapshotCleanup.RawData().Value.(bool); skipCleanup { - opts[azureinstancesnapshot.SkipCleanup] = "true" - } - // the presence of the flag indicates that we should skip setup. the disk we're trying to scan - // is already attached. Rely on the lun parameter to give us a hint as to the location of the disk - if skipSetup := skipSnapshotSetup.RawData().Value.(bool); skipSetup { - opts[azureinstancesnapshot.SkipSetup] = "true" - // we cannot detach the disk if we didn't attach it. - // we cannot delete the disk as we do not know it's azure resource id - // explicitly set the cleanup flag to false for clarity - opts[azureinstancesnapshot.SkipCleanup] = "true" - } if len(clientSecret.Value) > 0 { creds = append(creds, &vault.Credential{ Type: vault.CredentialType_password,