Skip to content

Commit

Permalink
✨ Add support for scanning azure disks. (#2974)
Browse files Browse the repository at this point in the history
Signed-off-by: Preslav <[email protected]>
  • Loading branch information
preslavgerchev authored Jan 8, 2024
1 parent 7039a11 commit f1915b4
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 92 deletions.
4 changes: 4 additions & 0 deletions providers/azure/connection/azureinstancesnapshot/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ package azureinstancesnapshot
func SnapshotPlatformMrn(snapshotId string) string {
return "//platformid.api.mondoo.app/runtime/azure" + snapshotId
}

func DiskPlatformMrn(diskId string) string {
return "//platformid.api.mondoo.app/runtime/azure" + diskId
}
63 changes: 41 additions & 22 deletions providers/azure/connection/azureinstancesnapshot/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,24 @@ import (
"go.mondoo.com/cnquery/v9/providers/os/id/ids"
)

type scanTarget struct {
TargetType string
Target string
ResourceGroup string
}

const (
SnapshotConnectionType shared.ConnectionType = "azure-snapshot"
DiskTargetType string = "disk"
SnapshotTargetType string = "snapshot"
InstanceTargetType string = "instance"
)

// the instance from which we're performing the scan
type azureScannerInstance struct {
instanceInfo
}

type scanTarget struct {
TargetType string
Target string
ResourceGroup string
}

type mountInfo struct {
deviceName string
diskId string
Expand Down Expand Up @@ -99,7 +102,7 @@ func ParseTarget(conf *inventory.Config, scanner *azureScannerInstance) (scanTar
return scanTarget{
TargetType: conf.Options["type"],
Target: conf.Options["target"],
ResourceGroup: scanner.ResourceGroup,
ResourceGroup: scanner.resourceGroup,
}, nil
}
return scanTarget{
Expand Down Expand Up @@ -132,7 +135,7 @@ func NewAzureSnapshotConnection(id uint32, conf *inventory.Config, asset *invent
}

// determine the target
sc, err := NewSnapshotCreator(token, scanner.SubscriptionId)
sc, err := NewSnapshotCreator(token, scanner.subscriptionId)
if err != nil {
return nil, err
}
Expand All @@ -147,35 +150,35 @@ func NewAzureSnapshotConnection(id uint32, conf *inventory.Config, asset *invent
// setup disk image so and attach it to the instance
mi := mountInfo{}

diskName := "cnspec-" + target.Target + "-snapshot-" + time.Now().Format("2006-01-02t15-04-05z00-00")
diskName := "cnspec-" + target.TargetType + "-snapshot-" + time.Now().Format("2006-01-02t15-04-05z00-00")
switch target.TargetType {
case "instance":
instanceInfo, err := sc.InstanceInfo(target.ResourceGroup, target.Target)
case InstanceTargetType:
instanceInfo, err := sc.instanceInfo(target.ResourceGroup, target.Target)
if err != nil {
return nil, err
}
if instanceInfo.BootDiskId == "" {
if instanceInfo.bootDiskId == "" {
return nil, fmt.Errorf("could not find boot disk for instance %s", target.Target)
}

log.Debug().Str("boot disk", instanceInfo.BootDiskId).Msg("found boot disk for instance, cloning")
disk, err := sc.cloneDisk(instanceInfo.BootDiskId, scanner.ResourceGroup, diskName, scanner.Location, scanner.Vm.Zones)
log.Debug().Str("boot disk", instanceInfo.bootDiskId).Msg("found boot disk for instance, cloning")
disk, err := sc.cloneDisk(instanceInfo.bootDiskId, scanner.resourceGroup, diskName, scanner.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(target.ResourceGroup, target.Target)
asset.Name = instanceInfo.instanceName
conf.PlatformId = azcompute.MondooAzureInstanceID(*instanceInfo.vm.ID)
case SnapshotTargetType:
snapshotInfo, err := sc.snapshotInfo(target.ResourceGroup, target.Target)
if err != nil {
return nil, err
}

disk, err := sc.createSnapshotDisk(snapshotInfo.SnapshotId, scanner.ResourceGroup, diskName, scanner.Location, scanner.Vm.Zones)
disk, err := sc.createSnapshotDisk(snapshotInfo.snapshotId, scanner.resourceGroup, diskName, scanner.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")
Expand All @@ -184,7 +187,23 @@ func NewAzureSnapshotConnection(id uint32, conf *inventory.Config, asset *invent
mi.diskId = *disk.ID
mi.diskName = *disk.Name
asset.Name = target.Target
conf.PlatformId = SnapshotPlatformMrn(snapshotInfo.SnapshotId)
conf.PlatformId = SnapshotPlatformMrn(snapshotInfo.snapshotId)
case DiskTargetType:
diskInfo, err := sc.diskInfo(target.ResourceGroup, target.Target)
if err != nil {
return nil, err
}

disk, err := sc.cloneDisk(diskInfo.diskId, scanner.resourceGroup, diskName, scanner.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 target disk")
mi.diskId = *disk.ID
mi.diskName = *disk.Name
asset.Name = diskInfo.diskName
conf.PlatformId = DiskPlatformMrn(diskInfo.diskId)
default:
return nil, errors.New("invalid target type")
}
Expand Down Expand Up @@ -264,7 +283,7 @@ type AzureSnapshotConnection struct {
*fs.FileSystemConnection
opts map[string]string
volumeMounter *snapshot.VolumeMounter
snapshotCreator *SnapshotCreator
snapshotCreator *snapshotCreator
scanner azureScannerInstance
mountInfo mountInfo
identifier string
Expand Down Expand Up @@ -298,7 +317,7 @@ func (c *AzureSnapshotConnection) Close() {
}

if c.mountInfo.diskName != "" {
err := c.snapshotCreator.deleteCreatedDisk(c.scanner.ResourceGroup, c.mountInfo.diskName)
err := c.snapshotCreator.deleteCreatedDisk(c.scanner.resourceGroup, c.mountInfo.diskName)
if err != nil {
log.Error().Err(err).Msg("could not delete created disk")
}
Expand Down
66 changes: 54 additions & 12 deletions providers/azure/connection/azureinstancesnapshot/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ func TestParseTarget(t *testing.T) {
t.Run("parse snapshot target with just a resource name", func(t *testing.T) {
scanner := &azureScannerInstance{
instanceInfo: instanceInfo{
ResourceGroup: "my-rg",
InstanceName: "my-instance",
resourceGroup: "my-rg",
instanceName: "my-instance",
},
}
target := "my-other-snapshot"
Expand All @@ -30,13 +30,13 @@ func TestParseTarget(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "my-rg", scanTarget.ResourceGroup)
assert.Equal(t, target, scanTarget.Target)
assert.Equal(t, "snapshot", scanTarget.TargetType)
assert.Equal(t, SnapshotTargetType, scanTarget.TargetType)
})
t.Run("parse instance target with just a resource name", func(t *testing.T) {
scanner := &azureScannerInstance{
instanceInfo: instanceInfo{
ResourceGroup: "my-rg",
InstanceName: "my-instance",
resourceGroup: "my-rg",
instanceName: "my-instance",
},
}
target := "my-other-instance"
Expand All @@ -51,13 +51,34 @@ func TestParseTarget(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "my-rg", scanTarget.ResourceGroup)
assert.Equal(t, target, scanTarget.Target)
assert.Equal(t, "instance", scanTarget.TargetType)
assert.Equal(t, InstanceTargetType, scanTarget.TargetType)
})
t.Run("parse disk target with just a resource name", func(t *testing.T) {
scanner := &azureScannerInstance{
instanceInfo: instanceInfo{
resourceGroup: "my-rg",
instanceName: "my-instance",
},
}
target := "my-disk"

conf := &inventory.Config{
Options: map[string]string{
"target": target,
"type": "disk",
},
}
scanTarget, err := ParseTarget(conf, scanner)
assert.NoError(t, err)
assert.Equal(t, "my-rg", scanTarget.ResourceGroup)
assert.Equal(t, target, scanTarget.Target)
assert.Equal(t, DiskTargetType, scanTarget.TargetType)
})
t.Run("parse snapshot target with a fully qualifed Azure resource id", func(t *testing.T) {
scanner := &azureScannerInstance{
instanceInfo: instanceInfo{
ResourceGroup: "my-rg",
InstanceName: "my-instance",
resourceGroup: "my-rg",
instanceName: "my-instance",
},
}
target := "/subscriptions/f1a2873a-6c27-4097-aa7c-3df51f103e91/resourceGroups/my-other-rg/providers/Microsoft.Compute/snapshots/test-snp"
Expand All @@ -72,13 +93,13 @@ func TestParseTarget(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "my-other-rg", scanTarget.ResourceGroup)
assert.Equal(t, "test-snp", scanTarget.Target)
assert.Equal(t, "snapshot", scanTarget.TargetType)
assert.Equal(t, SnapshotTargetType, scanTarget.TargetType)
})
t.Run("parse instance target with a fully qualifed Azure resource id", func(t *testing.T) {
scanner := &azureScannerInstance{
instanceInfo: instanceInfo{
ResourceGroup: "my-rg",
InstanceName: "my-instance",
resourceGroup: "my-rg",
instanceName: "my-instance",
},
}
target := "/subscriptions/f1a2873a-6b27-4097-aa7c-3df51f103e96/resourceGroups/debian_group/providers/Microsoft.Compute/virtualMachines/debian"
Expand All @@ -93,6 +114,27 @@ func TestParseTarget(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "debian_group", scanTarget.ResourceGroup)
assert.Equal(t, "debian", scanTarget.Target)
assert.Equal(t, "instance", scanTarget.TargetType)
assert.Equal(t, InstanceTargetType, scanTarget.TargetType)
})
t.Run("parse disk target with a fully qualifed Azure resource id", func(t *testing.T) {
scanner := &azureScannerInstance{
instanceInfo: instanceInfo{
resourceGroup: "my-rg",
instanceName: "my-instance",
},
}
target := "/subscriptions/f1a2873a-6b27-4097-aa7c-3df51f103e96/resourceGroups/debian_group/providers/Microsoft.Compute/disks/disk-1"

conf := &inventory.Config{
Options: map[string]string{
"target": target,
"type": "disk",
},
}
scanTarget, err := ParseTarget(conf, scanner)
assert.NoError(t, err)
assert.Equal(t, "debian_group", scanTarget.ResourceGroup)
assert.Equal(t, "disk-1", scanTarget.Target)
assert.Equal(t, DiskTargetType, scanTarget.TargetType)
})
}
Loading

0 comments on commit f1915b4

Please sign in to comment.