From 6eb57f9421e96cbcbe5627dbbfbed2cc315f6fba Mon Sep 17 00:00:00 2001 From: Preslav Gerchev Date: Fri, 5 Jan 2024 09:57:21 +0200 Subject: [PATCH] =?UTF-8?q?=E2=AD=90=EF=B8=8F=20Azure=20snapshot/instance?= =?UTF-8?q?=20scanning=20(#2943)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ⭐️ Azure snapshot/instance scanning Signed-off-by: Preslav * go mods. * Add tests for LUN parsing, simplify conf for the snapshot provider --------- Signed-off-by: Preslav --- providers-sdk/v1/plugin/ids.go | 10 - providers/azure/config/config.go | 12 +- providers/azure/connection/{ => auth}/auth.go | 5 +- .../connection/azureinstancesnapshot/lun.go | 114 +++++++ .../azureinstancesnapshot/lun_test.go | 31 ++ .../azureinstancesnapshot/platform.go | 8 + .../azureinstancesnapshot/provider.go | 306 +++++++++++++++++ .../azureinstancesnapshot/snapshot.go | 308 ++++++++++++++++++ providers/azure/connection/connection.go | 12 +- providers/azure/connection/shared/shared.go | 18 + providers/azure/go.mod | 32 +- providers/azure/go.sum | 87 +++++ providers/azure/provider/provider.go | 64 +++- providers/azure/resources/compute.go | 1 + providers/azure/resources/discovery.go | 6 +- providers/os/id/azcompute/azcompute.go | 7 +- 16 files changed, 992 insertions(+), 29 deletions(-) delete mode 100644 providers-sdk/v1/plugin/ids.go rename providers/azure/connection/{ => auth}/auth.go (92%) create mode 100644 providers/azure/connection/azureinstancesnapshot/lun.go create mode 100644 providers/azure/connection/azureinstancesnapshot/lun_test.go create mode 100644 providers/azure/connection/azureinstancesnapshot/platform.go create mode 100644 providers/azure/connection/azureinstancesnapshot/provider.go create mode 100644 providers/azure/connection/azureinstancesnapshot/snapshot.go create mode 100644 providers/azure/connection/shared/shared.go diff --git a/providers-sdk/v1/plugin/ids.go b/providers-sdk/v1/plugin/ids.go deleted file mode 100644 index 84406b79ea..0000000000 --- a/providers-sdk/v1/plugin/ids.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Mondoo, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package plugin - -// TODO: this may need a new home - -func MondooAzureInstanceID(instanceID string) string { - return "//platformid.api.mondoo.app/runtime/azure" + instanceID -} diff --git a/providers/azure/config/config.go b/providers/azure/config/config.go index 887560a87e..2274d84db6 100644 --- a/providers/azure/config/config.go +++ b/providers/azure/config/config.go @@ -5,15 +5,19 @@ package config import ( "go.mondoo.com/cnquery/v9/providers-sdk/v1/plugin" + "go.mondoo.com/cnquery/v9/providers/azure/connection/azureinstancesnapshot" "go.mondoo.com/cnquery/v9/providers/azure/provider" "go.mondoo.com/cnquery/v9/providers/azure/resources" ) var Config = plugin.Provider{ - Name: "azure", - ID: "go.mondoo.com/cnquery/v9/providers/azure", - Version: "9.1.16", - ConnectionTypes: []string{provider.ConnectionType}, + Name: "azure", + ID: "go.mondoo.com/cnquery/v9/providers/azure", + Version: "9.1.16", + ConnectionTypes: []string{ + provider.ConnectionType, + string(azureinstancesnapshot.SnapshotConnectionType), + }, Connectors: []plugin.Connector{ { Name: "azure", diff --git a/providers/azure/connection/auth.go b/providers/azure/connection/auth/auth.go similarity index 92% rename from providers/azure/connection/auth.go rename to providers/azure/connection/auth/auth.go index 2946e43d05..1aa7639f51 100644 --- a/providers/azure/connection/auth.go +++ b/providers/azure/connection/auth/auth.go @@ -1,7 +1,7 @@ // Copyright (c) Mondoo, Inc. // SPDX-License-Identifier: BUSL-1.1 -package connection +package auth import ( "fmt" @@ -13,7 +13,7 @@ import ( "go.mondoo.com/cnquery/v9/providers-sdk/v1/vault" ) -func getTokenCredential(credential *vault.Credential, tenantId, clientId string) (azcore.TokenCredential, error) { +func GetTokenCredential(credential *vault.Credential, tenantId, clientId string) (azcore.TokenCredential, error) { var azCred azcore.TokenCredential var err error // fallback to CLI authorizer if no credentials are specified @@ -24,7 +24,6 @@ func getTokenCredential(credential *vault.Credential, tenantId, clientId string) return nil, errors.Wrap(err, "error creating CLI credentials") } } else { - // we only support private key authentication for ms 365 switch credential.Type { case vault.CredentialType_pkcs12: certs, privateKey, err := azidentity.ParseCertificates(credential.Secret, []byte(credential.Password)) diff --git a/providers/azure/connection/azureinstancesnapshot/lun.go b/providers/azure/connection/azureinstancesnapshot/lun.go new file mode 100644 index 0000000000..be0b4df753 --- /dev/null +++ b/providers/azure/connection/azureinstancesnapshot/lun.go @@ -0,0 +1,114 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package azureinstancesnapshot + +import ( + "fmt" + "io" + "strconv" + "strings" + + "github.com/cockroachdb/errors" + "github.com/rs/zerolog/log" + "go.mondoo.com/cnquery/v9/providers/os/connection" +) + +type deviceInfo struct { + // the LUN number, e.g. 3 + Lun int32 + // where the disk is mounted, e.g. /dev/sda + VolumePath string +} + +func (a *azureScannerInstance) getAvailableLun(mountedDevices []deviceInfo) (int32, error) { + takenLuns := []int32{} + for _, d := range mountedDevices { + 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 getMountedDevices(localConn *connection.LocalConnection) ([]deviceInfo, error) { + cmd, err := 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) +} + +func getMatchingDevice(mountedDevices []deviceInfo, lun int32) (deviceInfo, error) { + for _, d := range mountedDevices { + if d.Lun == lun { + return d, nil + } + } + return deviceInfo{}, errors.New("could not find matching device") +} + +// 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) ([]deviceInfo, error) { + lines := strings.Split(strings.TrimSpace(output), "\n") + mountedDevices := []deviceInfo{} + 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, deviceInfo{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 new file mode 100644 index 0000000000..5f2d65a0f1 --- /dev/null +++ b/providers/azure/connection/azureinstancesnapshot/lun_test.go @@ -0,0 +1,31 @@ +// 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 := []deviceInfo{ + {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) +} diff --git a/providers/azure/connection/azureinstancesnapshot/platform.go b/providers/azure/connection/azureinstancesnapshot/platform.go new file mode 100644 index 0000000000..34c96e1906 --- /dev/null +++ b/providers/azure/connection/azureinstancesnapshot/platform.go @@ -0,0 +1,8 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package azureinstancesnapshot + +func SnapshotPlatformMrn(snapshotId string) string { + return "//platformid.api.mondoo.app/runtime/azure" + snapshotId +} diff --git a/providers/azure/connection/azureinstancesnapshot/provider.go b/providers/azure/connection/azureinstancesnapshot/provider.go new file mode 100644 index 0000000000..c4ab8df816 --- /dev/null +++ b/providers/azure/connection/azureinstancesnapshot/provider.go @@ -0,0 +1,306 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package azureinstancesnapshot + +import ( + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/cockroachdb/errors" + "github.com/rs/zerolog/log" + "go.mondoo.com/cnquery/v9/mrn" + "go.mondoo.com/cnquery/v9/providers-sdk/v1/inventory" + "go.mondoo.com/cnquery/v9/providers-sdk/v1/vault" + "go.mondoo.com/cnquery/v9/providers/azure/connection/auth" + "go.mondoo.com/cnquery/v9/providers/azure/connection/shared" + "go.mondoo.com/cnquery/v9/providers/os/connection" + "go.mondoo.com/cnquery/v9/providers/os/connection/snapshot" + "go.mondoo.com/cnquery/v9/providers/os/detector" + "go.mondoo.com/cnquery/v9/providers/os/id/azcompute" + "go.mondoo.com/cnquery/v9/providers/os/id/ids" +) + +type scanTarget struct { + TargetType string + TargetName string +} + +const ( + SnapshotConnectionType shared.ConnectionType = "azure-snapshot" +) + +// the instance from which we're performing the scan +type azureScannerInstance struct { + instanceInfo +} + +type mountInfo struct { + deviceName string + diskId string + diskName string +} + +func determineScannerInstanceInfo(localConn *connection.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 + } + + instanceInfo, err := InstanceInfo(resourceGrp, instanceName, subId, token) + if err != nil { + return nil, err + } + return &azureScannerInstance{ + instanceInfo: instanceInfo, + }, nil +} + +func ParseTarget(conf *inventory.Config) scanTarget { + return scanTarget{ + TargetType: conf.Options["type"], + TargetName: conf.Options["target-name"], + } +} + +func NewAzureSnapshotConnection(id uint32, conf *inventory.Config, asset *inventory.Asset) (*AzureSnapshotConnection, error) { + target := ParseTarget(conf) + + var cred *vault.Credential + if len(conf.Credentials) > 0 { + cred = conf.Credentials[0] + } + token, err := auth.GetTokenCredential(cred, conf.Options["tenant-id"], conf.Options["client-id"]) + if err != nil { + return nil, err + } + localConn := connection.NewLocalConnection(id, conf, asset) + + // check if we run on an azure instance + scanner, err := determineScannerInstanceInfo(localConn, token) + if err != nil { + return nil, err + } + + // determine the target + sc, err := NewSnapshotCreator(token, scanner.SubscriptionId) + if err != nil { + return nil, err + } + + c := &AzureSnapshotConnection{ + opts: conf.Options, + snapshotCreator: sc, + scanner: *scanner, + identifier: conf.PlatformId, + } + + // setup disk image so and attach it to the instance + mi := mountInfo{} + + diskName := "cnspec-" + target.TargetName + "-snapshot-" + time.Now().Format("2006-01-02t15-04-05z00-00") + switch target.TargetType { + case "instance": + instanceInfo, err := sc.InstanceInfo(scanner.ResourceGroup, target.TargetName) + if err != nil { + return nil, err + } + if instanceInfo.BootDiskId == "" { + return nil, fmt.Errorf("could not find boot disk for instance %s", target.TargetName) + } + + log.Debug().Str("boot disk", instanceInfo.BootDiskId).Msg("found boot disk for instance, cloning") + disk, err := sc.cloneDisk(instanceInfo.BootDiskId, scanner.ResourceGroup, diskName, instanceInfo.Location, scanner.Vm.Zones) + if err != nil { + log.Error().Err(err).Msg("could not complete disk cloning") + return nil, errors.Wrap(err, "could not complete disk cloning") + } + log.Debug().Str("disk", *disk.ID).Msg("cloned disk from instance boot disk") + mi.diskId = *disk.ID + mi.diskName = *disk.Name + asset.Name = instanceInfo.InstanceName + conf.PlatformId = azcompute.MondooAzureInstanceID(*instanceInfo.Vm.ID) + case "snapshot": + snapshotInfo, err := sc.SnapshotInfo(scanner.ResourceGroup, target.TargetName) + if err != nil { + return nil, err + } + + disk, err := sc.createSnapshotDisk(snapshotInfo.SnapshotId, scanner.ResourceGroup, diskName, snapshotInfo.Location, scanner.Vm.Zones) + if err != nil { + log.Error().Err(err).Msg("could not complete snapshot disk creation") + return nil, errors.Wrap(err, "could not create disk from snapshot") + } + log.Debug().Str("disk", *disk.ID).Msg("created disk from snapshot") + mi.diskId = *disk.ID + mi.diskName = *disk.Name + asset.Name = target.TargetName + conf.PlatformId = SnapshotPlatformMrn(snapshotInfo.SnapshotId) + default: + return nil, errors.New("invalid target type") + } + + // fetch the mounted devices. we want to find an available LUN to mount the disk at + mountedDevices, err := getMountedDevices(localConn) + if err != nil { + return nil, err + } + lun, err := scanner.getAvailableLun(mountedDevices) + if err != nil { + return nil, err + } + err = sc.attachDisk(scanner.instanceInfo, mi.diskName, mi.diskId, lun) + if err != nil { + c.Close() + return nil, err + } + + // refetch the mounted devices, we now are looking for the specific LUN that we just attached. + // we don't know from the Azure API where it will be mounted, we need to look it up + mountedDevices, err = getMountedDevices(localConn) + if err != nil { + c.Close() + return nil, err + } + matchingDevice, err := getMatchingDevice(mountedDevices, lun) + if err != nil { + c.Close() + return nil, err + } + mi.deviceName = matchingDevice.VolumePath + + // mount volume + shell := []string{"sh", "-c"} + volumeMounter := snapshot.NewVolumeMounter(shell) + volumeMounter.VolumeAttachmentLoc = mi.deviceName + err = volumeMounter.Mount() + if err != nil { + log.Error().Err(err).Msg("unable to complete mount step") + c.Close() + return nil, err + } + + conf.Options["path"] = volumeMounter.ScanDir + // create and initialize fs provider + fsConn, err := connection.NewFileSystemConnection(id, &inventory.Config{ + Path: volumeMounter.ScanDir, + PlatformId: conf.PlatformId, + Options: conf.Options, + Type: conf.Type, + Record: conf.Record, + }, asset) + if err != nil { + c.Close() + return nil, err + } + + c.FileSystemConnection = fsConn + c.mountInfo = mi + 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 + asset.Platform.Kind = c.Kind() + asset.Platform.Runtime = c.Runtime() + return c, nil +} + +type AzureSnapshotConnection struct { + *connection.FileSystemConnection + opts map[string]string + volumeMounter *snapshot.VolumeMounter + snapshotCreator *SnapshotCreator + scanner azureScannerInstance + mountInfo mountInfo + identifier string +} + +func (c *AzureSnapshotConnection) Close() { + log.Debug().Msg("closing azure snapshot connection") + if c == nil { + return + } + + if c.opts != nil { + if c.opts[snapshot.NoSetup] == "true" { + return + } + } + + err := c.volumeMounter.UnmountVolumeFromInstance() + if err != nil { + log.Error().Err(err).Msg("unable to unmount volume") + } + + if c.snapshotCreator != nil { + err = c.snapshotCreator.detachDisk(c.mountInfo.diskName, c.scanner.instanceInfo) + if err != nil { + log.Error().Err(err).Msg("unable to detach volume") + } + + err = c.snapshotCreator.deleteCreatedDisk(c.scanner.ResourceGroup, c.mountInfo.diskName) + if err != nil { + log.Error().Err(err).Msg("could not delete created disk") + } + } + + err = c.volumeMounter.RemoveTempScanDir() + if err != nil { + log.Error().Err(err).Msg("unable to remove dir") + } +} + +func (c *AzureSnapshotConnection) Kind() string { + return "api" +} + +func (c *AzureSnapshotConnection) Runtime() string { + return "azure-vm" +} + +func (c *AzureSnapshotConnection) Identifier() (string, error) { + return c.identifier, nil +} + +func (c *AzureSnapshotConnection) Type() shared.ConnectionType { + return SnapshotConnectionType +} + +func (c *AzureSnapshotConnection) Config() *inventory.Config { + return c.FileSystemConnection.Conf +} diff --git a/providers/azure/connection/azureinstancesnapshot/snapshot.go b/providers/azure/connection/azureinstancesnapshot/snapshot.go new file mode 100644 index 0000000000..899957cbc6 --- /dev/null +++ b/providers/azure/connection/azureinstancesnapshot/snapshot.go @@ -0,0 +1,308 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package azureinstancesnapshot + +import ( + "context" + "time" + + "github.com/rs/zerolog/log" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + compute "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute" +) + +const ( + createdByLabel = "created-by" + createdValue = "cnspec" +) + +func NewSnapshotCreator(token azcore.TokenCredential, subscriptionId string) (*SnapshotCreator, error) { + createdByVal := createdValue + sc := &SnapshotCreator{ + labels: map[string]*string{ + createdByLabel: &createdByVal, + }, + token: token, + subscriptionId: subscriptionId, + } + return sc, nil +} + +type SnapshotCreator struct { + subscriptionId string + token azcore.TokenCredential + opts *policy.ClientOptions + labels map[string]*string +} + +func (sc *SnapshotCreator) snapshotClient() (*compute.SnapshotsClient, error) { + return compute.NewSnapshotsClient(sc.subscriptionId, sc.token, sc.opts) +} + +func (sc *SnapshotCreator) diskClient() (*compute.DisksClient, error) { + return compute.NewDisksClient(sc.subscriptionId, sc.token, sc.opts) +} + +func (sc *SnapshotCreator) computeClient() (*compute.VirtualMachinesClient, error) { + return computeClient(sc.token, sc.subscriptionId, sc.opts) +} + +func computeClient(token azcore.TokenCredential, subId string, opts *policy.ClientOptions) (*compute.VirtualMachinesClient, error) { + return compute.NewVirtualMachinesClient(subId, token, opts) +} + +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 (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 +} + +type snapshotInfo struct { + PlatformMrn string + ResourceGroup string + SnapshotName string + SnapshotId string + Location string +} + +func (sc *SnapshotCreator) SnapshotInfo(resourceGroup, snapshotName string) (snapshotInfo, error) { + ctx := context.Background() + si := snapshotInfo{} + + snapshotSvc, err := sc.snapshotClient() + if err != nil { + return si, err + } + + snapshot, err := snapshotSvc.Get(ctx, resourceGroup, snapshotName, &compute.SnapshotsClientGetOptions{}) + if err != nil { + return si, err + } + + si.SnapshotName = *snapshot.Name + si.SnapshotId = *snapshot.ID + si.Location = *snapshot.Location + return si, nil +} + +// createDisk creates a new disk +func (sc *SnapshotCreator) createDisk(disk compute.Disk, resourceGroupName, diskName string) (compute.Disk, error) { + ctx := context.Background() + + diskSvc, err := sc.diskClient() + if err != nil { + return compute.Disk{}, err + } + + poller, err := diskSvc.BeginCreateOrUpdate(ctx, resourceGroupName, diskName, disk, &compute.DisksClientBeginCreateOrUpdateOptions{}) + if err != nil { + return compute.Disk{}, err + } + resp, err := poller.PollUntilDone(context.Background(), &runtime.PollUntilDoneOptions{ + Frequency: 5 * time.Second, + }) + if err != nil { + return compute.Disk{}, err + } + return resp.Disk, nil +} + +// createSnapshotDisk creates a new disk from a snapshot +func (sc *SnapshotCreator) createSnapshotDisk(sourceSnaphotId, resourceGroupName, diskName, location string, zones []*string) (compute.Disk, error) { + // create a new disk from snapshot + createOpt := compute.DiskCreateOptionCopy + disk := compute.Disk{ + Location: &location, + Zones: zones, + Name: &diskName, + Properties: &compute.DiskProperties{ + CreationData: &compute.CreationData{ + SourceResourceID: &sourceSnaphotId, + CreateOption: &createOpt, + }, + }, + Tags: sc.labels, + } + return sc.createDisk(disk, resourceGroupName, diskName) +} + +// cloneDisk clones a provided disk +func (sc *SnapshotCreator) cloneDisk(sourceDiskId, resourceGroupName, diskName string, location string, zones []*string) (compute.Disk, error) { + // create a new disk by copying another disk + createOpt := compute.DiskCreateOptionCopy + disk := compute.Disk{ + Location: &location, + Zones: zones, + Name: &diskName, + Properties: &compute.DiskProperties{ + CreationData: &compute.CreationData{ + SourceResourceID: &sourceDiskId, + CreateOption: &createOpt, + }, + }, + Tags: sc.labels, + } + return sc.createDisk(disk, resourceGroupName, diskName) +} + +// attachDisk attaches a disk to an instance +func (sc *SnapshotCreator) attachDisk(targetInstance instanceInfo, diskName, diskId string, lun int32) error { + ctx := context.Background() + log.Debug().Str("disk-name", diskName).Int32("LUN", lun).Msg("attach disk") + computeSvc, err := sc.computeClient() + if err != nil { + return err + } + attachOpt := compute.DiskCreateOptionTypesAttach + // 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{ + Name: &diskName, + CreateOption: &attachOpt, + Lun: &lun, + ManagedDisk: &compute.ManagedDiskParameters{ + ID: &diskId, + }, + }) + vm := compute.VirtualMachine{ + Location: &targetInstance.Location, + Properties: &compute.VirtualMachineProperties{ + StorageProfile: &compute.StorageProfile{ + DataDisks: disks, + }, + }, + } + + poller, err := computeSvc.BeginCreateOrUpdate(ctx, targetInstance.ResourceGroup, targetInstance.InstanceName, vm, &compute.VirtualMachinesClientBeginCreateOrUpdateOptions{}) + if err != nil { + return err + } + start := time.Now() + for { + log.Debug().Str("disk-name", diskName).Str("elapsed", time.Duration(time.Since(start)).String()).Msg("polling for disk attach") + _, err := poller.Poll(ctx) + if err != nil { + return err + } + + if poller.Done() { + break + } + time.Sleep(5 * time.Second) + } + + _, err = poller.Result(ctx) + return err +} + +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.VirtualMachine{ + Location: &targetInstance.Location, + Properties: &compute.VirtualMachineProperties{ + StorageProfile: &compute.StorageProfile{ + DataDisks: targetInstance.Vm.Properties.StorageProfile.DataDisks, + }, + }, + } + + poller, err := computeSvc.BeginCreateOrUpdate(ctx, targetInstance.ResourceGroup, targetInstance.InstanceName, vm, &compute.VirtualMachinesClientBeginCreateOrUpdateOptions{}) + if err != nil { + return err + } + start := time.Now() + for { + log.Debug().Str("disk-name", diskName).Str("elapsed", time.Duration(time.Since(start)).String()).Msg("polling for disk detachment") + _, err := poller.Poll(ctx) + if err != nil { + return err + } + + if poller.Done() { + break + } + time.Sleep(5 * time.Second) + } + + _, err = poller.Result(ctx) + return err +} + +// deleteCreatedDisk deletes the given disk if it matches the created label +func (sc *SnapshotCreator) deleteCreatedDisk(resourceGroup, diskName string) error { + ctx := context.Background() + + diskSvc, err := sc.diskClient() + if err != nil { + return err + } + + disk, err := diskSvc.Get(ctx, resourceGroup, diskName, &compute.DisksClientGetOptions{}) + if err != nil { + return err + } + + // only delete the volume if we created it, e.g., if we're scanning a snapshot + if val, ok := disk.Tags[createdByLabel]; ok && *val == createdValue { + poller, err := diskSvc.BeginDelete(ctx, resourceGroup, diskName, &compute.DisksClientBeginDeleteOptions{}) + if err != nil { + return err + } + _, err = poller.PollUntilDone(context.Background(), &runtime.PollUntilDoneOptions{ + Frequency: 5 * time.Second, + }) + if err != nil { + return err + } + log.Debug().Str("disk", diskName).Msg("deleted temporary disk created by cnspec") + } else { + log.Debug().Str("disk", diskName).Msg("skipping disk deletion, not created by cnspec") + } + + return nil +} diff --git a/providers/azure/connection/connection.go b/providers/azure/connection/connection.go index 8eba5d614b..8528ec184e 100644 --- a/providers/azure/connection/connection.go +++ b/providers/azure/connection/connection.go @@ -9,6 +9,8 @@ import ( "github.com/pkg/errors" "go.mondoo.com/cnquery/v9/providers-sdk/v1/inventory" "go.mondoo.com/cnquery/v9/providers-sdk/v1/vault" + "go.mondoo.com/cnquery/v9/providers/azure/connection/auth" + "go.mondoo.com/cnquery/v9/providers/azure/connection/shared" ) const ( @@ -39,7 +41,7 @@ func NewAzureConnection(id uint32, asset *inventory.Asset, conf *inventory.Confi cred = conf.Credentials[0] } - token, err := getTokenCredential(cred, tenantId, clientId) + token, err := auth.GetTokenCredential(cred, tenantId, clientId) if err != nil { return nil, errors.Wrap(err, "cannot fetch credentials for microsoft provider") } @@ -79,3 +81,11 @@ func (p *AzureConnection) PlatformId() string { func (p *AzureConnection) ClientOptions() policy.ClientOptions { return p.clientOptions } + +func (p *AzureConnection) Config() *inventory.Config { + return p.Conf +} + +func (p *AzureConnection) Type() shared.ConnectionType { + return "azure" +} diff --git a/providers/azure/connection/shared/shared.go b/providers/azure/connection/shared/shared.go new file mode 100644 index 0000000000..b267c6df6b --- /dev/null +++ b/providers/azure/connection/shared/shared.go @@ -0,0 +1,18 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package shared + +import ( + "go.mondoo.com/cnquery/v9/providers-sdk/v1/inventory" +) + +type ConnectionType string + +type AzureConnection interface { + ID() uint32 + Name() string + Type() ConnectionType + Config() *inventory.Config + Asset() *inventory.Asset +} diff --git a/providers/azure/go.mod b/providers/azure/go.mod index 31771feb37..3e45d98075 100644 --- a/providers/azure/go.mod +++ b/providers/azure/go.mod @@ -32,6 +32,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/security/armsecurity v0.12.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql v1.2.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 + github.com/cockroachdb/errors v1.11.1 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.31.0 github.com/stretchr/testify v1.8.4 @@ -50,9 +51,12 @@ require ( github.com/99designs/keyring v1.2.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect github.com/GoogleCloudPlatform/berglas v1.0.3 // indirect github.com/Masterminds/semver v1.5.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect github.com/aws/aws-sdk-go v1.49.13 // indirect github.com/aws/aws-sdk-go-v2 v1.24.0 // indirect github.com/aws/aws-sdk-go-v2/config v1.26.2 // indirect @@ -61,6 +65,10 @@ require ( github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.142.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect v1.20.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.24.6 // indirect + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.21.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.0 // indirect @@ -69,13 +77,21 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.26.6 // indirect github.com/aws/smithy-go v1.19.0 // indirect + github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231213181459-b0fcec718dc6 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect - github.com/cockroachdb/errors v1.11.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/redact v1.1.5 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect github.com/danieljoos/wincred v1.2.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/distribution/reference v0.5.0 // indirect + github.com/docker/cli v24.0.7+incompatible // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/docker v24.0.7+incompatible // indirect + github.com/docker/docker-credential-helpers v0.8.0 // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect github.com/fatih/color v1.16.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -83,12 +99,14 @@ require ( github.com/go-jose/go-jose/v3 v3.0.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-containerregistry v0.17.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.5.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect @@ -107,8 +125,13 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/vault/api v1.10.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect + github.com/hnakamur/go-scp v1.0.2 // indirect github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.17.2 // 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/kylelemons/godebug v1.1.0 // indirect @@ -122,16 +145,21 @@ require ( github.com/mtibben/percent v0.2.1 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/oklog/run v1.1.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect + github.com/pkg/sftp v1.13.6 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/segmentio/fasthash v1.0.3 // indirect github.com/segmentio/ksuid v1.0.4 // indirect + github.com/sethvargo/go-password v0.2.0 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.11.0 // indirect + github.com/vbatts/tar-split v0.11.5 // indirect go.mondoo.com/ranger-rpc v0.5.3 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect @@ -140,6 +168,7 @@ require ( go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect golang.org/x/crypto v0.17.0 // indirect + golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.15.0 // indirect golang.org/x/sync v0.5.0 // indirect @@ -147,6 +176,7 @@ require ( golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.16.1 // indirect google.golang.org/api v0.154.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect diff --git a/providers/azure/go.sum b/providers/azure/go.sum index 0c61dbe188..854659bc1b 100644 --- a/providers/azure/go.sum +++ b/providers/azure/go.sum @@ -77,13 +77,21 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql v1.2.0 h1:S087d github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql v1.2.0/go.mod h1:B4cEyXrWBmbfMDAPnpJ1di7MAt5DKP57jPEObAvZChg= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0/go.mod h1:T5RfihdXtBDxt1Ch2wobif3TvzTdumDy29kahv6AV9A= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 h1:hVeq+yCyUi+MsoO/CU95yqCIcdzra5ovzk8Q2BBpV2M= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/GoogleCloudPlatform/berglas v1.0.3 h1:NjJYDz13vWct7+joxkBkIZhD6Cmwf5XP5t0jGTvHyJk= github.com/GoogleCloudPlatform/berglas v1.0.3/go.mod h1:JBsGyi6Z5RwyHXMdEebok6MChukLE+dWXzPor2aeMtw= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/aws/aws-sdk-go v1.49.13 h1:f4mGztsgnx2dR9r8FQYa9YW/RsKb+N7bgef4UGrOW1Y= github.com/aws/aws-sdk-go v1.49.13/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk= @@ -100,6 +108,14 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrw github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.142.0 h1:VrFC1uEZjX4ghkm/et8ATVGb1mT75Iv8aPKPjUE+F8A= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.142.0/go.mod h1:qjhtI9zjpUHRc6khtrIM9fb48+ii6+UikL3/b+MKYn0= +github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect v1.20.5 h1:TXrkR0m/qOpNqkvYlveiIDON/JoZdq+Z51PPqY1l0wg= +github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect v1.20.5/go.mod h1:V4hO0p/grXSB8GoEr2koPfgMpEFS3ndx5fxgzzQo2M4= +github.com/aws/aws-sdk-go-v2/service/ecr v1.24.6 h1:cT7h+GWP2k0hJSsPmppKgxl4C9R6gCC5/oF4oHnmpK4= +github.com/aws/aws-sdk-go-v2/service/ecr v1.24.6/go.mod h1:AOHmGMoPtSY9Zm2zBuwUJQBisIvYAZeA1n7b6f4e880= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.21.5 h1:PQp21GBlGNaQ+AVJAB8w2KTmLx0DkFS2fDET2Iy3+f0= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.21.5/go.mod h1:WMntdAol8KgeYsa5sDZPsRTXs4jVZIMYu0eQVVIQxnc= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU= @@ -116,6 +132,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.26.6 h1:HJeiuZ2fldpd0WqngyMR6KW7ofkX github.com/aws/aws-sdk-go-v2/service/sts v1.26.6/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU= github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231213181459-b0fcec718dc6 h1:PlJRmqKlSlEUlwem1c3zdPaEMtJc/ktnV7naD5Qvsx4= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231213181459-b0fcec718dc6/go.mod h1:08sPJIlDHu4HwQ1xScPgsBWezvM6U10ghGKBJu0mowA= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -133,16 +151,35 @@ github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZe github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +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/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg= +github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= +github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY= github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -167,8 +204,13 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -206,6 +248,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.17.0 h1:5p+zYs/R4VGHkhyvgWurWrpJ2hW4Vv9fQI+GzdcwXLk= +github.com/google/go-containerregistry v0.17.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= @@ -249,6 +293,10 @@ github.com/hashicorp/vault/api v1.10.0 h1:/US7sIjWN6Imp4o/Rj1Ce2Nr5bki/AXi9vAW3p github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +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/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= @@ -259,11 +307,21 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +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/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +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= @@ -289,6 +347,10 @@ github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJ github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= @@ -296,6 +358,10 @@ github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1n github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= +github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= @@ -303,6 +369,8 @@ github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzL 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= @@ -322,6 +390,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.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI= +github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE= 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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -346,6 +416,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= +github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -369,7 +441,9 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -379,6 +453,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -390,6 +466,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 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.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -406,12 +483,15 @@ golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -419,18 +499,21 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.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.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -444,6 +527,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -495,6 +580,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8= diff --git a/providers/azure/provider/provider.go b/providers/azure/provider/provider.go index 4d8e8d0614..ed0659534d 100644 --- a/providers/azure/provider/provider.go +++ b/providers/azure/provider/provider.go @@ -14,6 +14,8 @@ import ( "go.mondoo.com/cnquery/v9/providers-sdk/v1/upstream" "go.mondoo.com/cnquery/v9/providers-sdk/v1/vault" "go.mondoo.com/cnquery/v9/providers/azure/connection" + "go.mondoo.com/cnquery/v9/providers/azure/connection/azureinstancesnapshot" + "go.mondoo.com/cnquery/v9/providers/azure/connection/shared" "go.mondoo.com/cnquery/v9/providers/azure/resources" ) @@ -80,6 +82,14 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) Options: opts, } + // handle azure subcommands + if len(req.Args) >= 3 && req.Args[0] == "compute" { + err := handleAzureComputeSubcommands(req.Args, config) + if err != nil { + return nil, err + } + } + asset := inventory.Asset{ Connections: []*inventory.Config{config}, } @@ -101,10 +111,37 @@ func parseDiscover(flags map[string]*llx.Primitive) *inventory.Discovery { return &inventory.Discovery{Targets: targets} } +func handleAzureComputeSubcommands(args []string, config *inventory.Config) error { + switch args[1] { + case "instance": + config.Type = string(azureinstancesnapshot.SnapshotConnectionType) + config.Discover = nil + config.Options["type"] = "instance" + config.Options["target-name"] = args[2] + return nil + case "snapshot": + config.Type = string(azureinstancesnapshot.SnapshotConnectionType) + config.Options["type"] = "snapshot" + config.Options["target-name"] = args[2] + config.Discover = nil + return nil + default: + return errors.New("unknown subcommand " + args[1]) + } +} + // Shutdown is automatically called when the shell closes. // It is not necessary to implement this method. // If you want to do some cleanup, you can do it here. func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { + for i := range s.runtimes { + runtime := s.runtimes[i] + sharedConn := runtime.Connection.(shared.AzureConnection) + if sharedConn.Type() == azureinstancesnapshot.SnapshotConnectionType { + conn := runtime.Connection.(*azureinstancesnapshot.AzureSnapshotConnection) + conn.Close() + } + } return &plugin.ShutdownRes{}, nil } @@ -130,7 +167,7 @@ func (s *Service) Connect(req *plugin.ConnectReq, callback plugin.ProviderCallba } // discovery assets for further scanning - inventory, err := s.discover(conn, conn.Conf) + inventory, err := s.discover(conn) if err != nil { return nil, err } @@ -143,7 +180,7 @@ func (s *Service) Connect(req *plugin.ConnectReq, callback plugin.ProviderCallba }, nil } -func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*connection.AzureConnection, error) { +func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (shared.AzureConnection, error) { if len(req.Asset.Connections) == 0 { return nil, errors.New("no connection options for asset") } @@ -151,7 +188,20 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] s.lastConnectionID++ - conn, err := connection.NewAzureConnection(s.lastConnectionID, asset, conf) + var conn shared.AzureConnection + var err error + + switch conf.Type { + case string(azureinstancesnapshot.SnapshotConnectionType): + // An AzureSnapshotConnection is a wrapper around a FilesystemConnection + // To make sure the connection is later handled by the os provider, override the type + conf.Type = "filesystem" + s.lastConnectionID++ + conn, err = azureinstancesnapshot.NewAzureSnapshotConnection(s.lastConnectionID, conf, asset) + default: + s.lastConnectionID++ + conn, err = connection.NewAzureConnection(s.lastConnectionID, asset, conf) + } if err != nil { return nil, err } @@ -176,7 +226,7 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba return conn, err } -func (s *Service) detect(asset *inventory.Asset, conn *connection.AzureConnection) error { +func (s *Service) detect(asset *inventory.Asset, conn shared.AzureConnection) error { // TODO: what do i put here return nil } @@ -268,8 +318,8 @@ func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { return &plugin.StoreRes{}, nil } -func (s *Service) discover(conn *connection.AzureConnection, conf *inventory.Config) (*inventory.Inventory, error) { - if conn.Conf.Discover == nil { +func (s *Service) discover(conn shared.AzureConnection) (*inventory.Inventory, error) { + if conn.Config().Discover == nil { return nil, nil } @@ -279,5 +329,5 @@ func (s *Service) discover(conn *connection.AzureConnection, conf *inventory.Con return nil, errors.New("connection " + strconv.FormatUint(uint64(conn.ID()), 10) + " not found") } - return resources.Discover(runtime, conf) + return resources.Discover(runtime, conn.Config()) } diff --git a/providers/azure/resources/compute.go b/providers/azure/resources/compute.go index 2f3200861b..747829e1f8 100644 --- a/providers/azure/resources/compute.go +++ b/providers/azure/resources/compute.go @@ -7,6 +7,7 @@ import ( "context" "encoding/json" "errors" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" compute "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute" network "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork" diff --git a/providers/azure/resources/discovery.go b/providers/azure/resources/discovery.go index 23e8be4d2f..095f8d870d 100644 --- a/providers/azure/resources/discovery.go +++ b/providers/azure/resources/discovery.go @@ -62,6 +62,10 @@ type subWithConfig struct { conf *inventory.Config } +func MondooAzureInstanceID(instanceID string) string { + return "//platformid.api.mondoo.app/runtime/azure" + instanceID +} + func Discover(runtime *plugin.Runtime, rootConf *inventory.Config) (*inventory.Inventory, error) { conn := runtime.Connection.(*connection.AzureConnection) assets := []*inventory.Asset{} @@ -264,7 +268,7 @@ func discoverInstances(runtime *plugin.Runtime, subsWithConfigs []subWithConfig) return nil, err } enrichWithLabels(asset, labels) - asset.PlatformIds = []string{plugin.MondooAzureInstanceID(vm.Id.Data)} + asset.PlatformIds = []string{MondooAzureInstanceID(vm.Id.Data)} asset.Platform.Runtime = "azure" asset.Platform.Kind = "virtualmachine" assets = append(assets, asset) diff --git a/providers/os/id/azcompute/azcompute.go b/providers/os/id/azcompute/azcompute.go index 385cf5b607..038968eec6 100644 --- a/providers/os/id/azcompute/azcompute.go +++ b/providers/os/id/azcompute/azcompute.go @@ -10,7 +10,6 @@ import ( "strings" "go.mondoo.com/cnquery/v9/providers-sdk/v1/inventory" - "go.mondoo.com/cnquery/v9/providers-sdk/v1/plugin" "go.mondoo.com/cnquery/v9/providers/os/connection/shared" "go.mondoo.com/cnquery/v9/providers/os/resources/powershell" "go.mondoo.com/cnquery/v9/utils/multierr" @@ -21,6 +20,10 @@ const ( metadataIdentityScriptWindows = `Invoke-RestMethod -TimeoutSec 1 -Headers @{"Metadata"="true"} -Method GET -URI http://169.254.169.254/metadata/instance?api-version=2021-02-01 -UseBasicParsing | ConvertTo-Json` ) +func MondooAzureInstanceID(instanceID string) string { + return "//platformid.api.mondoo.app/runtime/azure" + instanceID +} + type instanceMetadata struct { Compute struct { ResourceID string `json:"resourceID"` @@ -86,7 +89,7 @@ func (m *commandInstanceMetadata) Identify() (Identity, error) { } return Identity{ - InstanceID: plugin.MondooAzureInstanceID(md.Compute.ResourceID), + InstanceID: MondooAzureInstanceID(md.Compute.ResourceID), AccountID: "//platformid.api.mondoo.app/runtime/azure/subscriptions/" + md.Compute.SubscriptionID, }, nil }