def QueryMetrics(args: 'argparse.Namespace') -> None: """Query Azure Monitoring metrics for a resource. Args: args (argparse.Namespace): Arguments from ArgumentParser. Raises: RuntimeError: If from_date or to_date could not be parsed. """ az_account = account.AZAccount(args.default_resource_group_name) az_monitoring = monitoring.AZMonitoring(az_account) from_date, to_date = args.from_date, args.to_date if from_date and to_date: try: from_date = datetime.strptime(from_date, '%Y-%m-%dT%H:%M:%SZ') to_date = datetime.strptime(to_date, '%Y-%m-%dT%H:%M:%SZ') except ValueError as exception: raise RuntimeError( 'Cannot parse date: {0!s}'.format(exception)) from exception metrics = az_monitoring.GetMetricsForResource( args.resource_id, metrics=args.metrics, from_date=from_date, to_date=to_date, interval=args.interval, aggregation=args.aggregation or 'Total', qfilter=args.qfilter) for metric in metrics: logger.info('Metric: {0:s}'.format(metric)) for timestamp, value in metrics[metric].items(): logger.info(' Timestamp: {0:s}, value: {1:s}'.format(timestamp, value))
def StartAnalysisVm( resource_group_name: str, vm_name: str, boot_disk_size: int, ssh_public_key: str, cpu_cores: int = 4, memory_in_mb: int = 8192, region: str = 'eastus', attach_disks: Optional[List[str]] = None, tags: Optional[Dict[str, str]] = None, dst_profile: Optional[str] = None ) -> Tuple['compute.AZVirtualMachine', bool]: """Start a virtual machine for analysis purposes. Look for an existing Azure virtual machine with name vm_name. If found, this instance will be started and used as analysis VM. If not found, then a new vm with that name will be created, started and returned. Note that if a new vm is created, you should provide the ssh_public_key parameter. Args: resource_group_name (str): The resource group in which to create the analysis vm. vm_name (str): The name for the virtual machine. boot_disk_size (int): The size of the analysis VM boot disk (in GB). ssh_public_key (str): A SSH public key data (OpenSSH format) to associate with the VM, e.g. ssh-rsa AAAAB3NzaC1y... This must be provided as otherwise the VM will not be accessible. cpu_cores (int): Number of CPU cores for the analysis VM. memory_in_mb (int): The memory size (in MB) for the analysis VM. region (str): Optional. The region in which to create the VM. Default is eastus. attach_disks (List[str]): Optional. List of disk names to attach to the VM. tags (Dict[str, str]): Optional. A dictionary of tags to add to the instance, for example {'TicketID': 'xxx'}. An entry for the instance name is added by default. dst_profile (str): The name of the destination profile to use for the vm creation, i.e. the account information of the Azure account in which to create the vm. For more information on profiles, see GetCredentials() in libcloudforensics.providers.azure.internal.common.py Returns: Tuple[AZVirtualMachine, bool]: a tuple with a virtual machine object and a boolean indicating if the virtual machine was created or not. """ az_account = account.AZAccount(resource_group_name, default_region=region, profile_name=dst_profile) analysis_vm, created = az_account.GetOrCreateAnalysisVm(vm_name, boot_disk_size, cpu_cores, memory_in_mb, ssh_public_key, tags=tags) for disk_name in (attach_disks or []): analysis_vm.AttachDisk(az_account.GetDisk(disk_name)) return analysis_vm, created
def ListMetrics(args: 'argparse.Namespace') -> None: """List Azure Monitoring metrics for a resource. Args: args (argparse.Namespace): Arguments from ArgumentParser. """ az_account = account.AZAccount(args.default_resource_group_name) az_monitoring = monitoring.AZMonitoring(az_account) metrics = az_monitoring.ListAvailableMetricsForResource(args.resource_id) for metric in metrics: logger.info('Available metric: {0:s}'.format(metric))
def setUpClass(cls): try: project_info = utils.ReadProjectInfo( ['resource_group_name', 'instance_name']) except (OSError, RuntimeError, ValueError) as exception: raise unittest.SkipTest(str(exception)) cls.resource_group_name = project_info['resource_group_name'] cls.instance_to_analyse = project_info['instance_name'] cls.disk_to_copy = project_info.get('disk_name') cls.dst_region = project_info.get('dst_region') cls.az = account.AZAccount(cls.resource_group_name) cls.disks = [] # List of AZDisks for test cleanup
def ListDisks(args: 'argparse.Namespace') -> None: """List disks in Azure subscription. Args: args (argparse.Namespace): Arguments from ArgumentParser. """ az_account = account.AZAccount(args.default_resource_group_name) disks = az_account.compute.ListDisks( resource_group_name=args.resource_group_name) logger.info('Disks found:') for disk in disks: logger.info('Name: {0:s}, Region: {1:s}'.format(disk, disks[disk].region))
def ListInstances(args: 'argparse.Namespace') -> None: """List instances in Azure subscription. Args: args (argparse.Namespace): Arguments from ArgumentParser. """ az_account = account.AZAccount(args.default_resource_group_name) instances = az_account.compute.ListInstances( resource_group_name=args.resource_group_name) logger.info('Instances found:') for instance in instances.values(): boot_disk = instance.GetBootDisk().name logger.info('Name: {0:s}, Boot disk: {1:s}'.format(instance, boot_disk))
def setUpClass(cls): try: project_info = utils.ReadProjectInfo( ['resource_group_name', 'instance_name', 'ssh_public_key']) except (OSError, RuntimeError, ValueError) as exception: raise unittest.SkipTest(str(exception)) cls.resource_group_name = project_info['resource_group_name'] cls.instance_to_analyse = project_info['instance_name'] cls.ssh_public_key = project_info['ssh_public_key'] cls.disk_to_copy = project_info.get('disk_name') cls.dst_region = project_info.get('dst_region') cls.az = account.AZAccount(cls.resource_group_name) cls.analysis_vm_name = 'new-vm-for-analysis' cls.analysis_vm, _ = forensics.StartAnalysisVm(cls.resource_group_name, cls.analysis_vm_name, 50, cls.ssh_public_key) cls.disks = [] # List of AZDisks for test cleanup
from libcloudforensics.providers.azure.internal import account, compute, monitoring # pylint: disable=line-too-long RESOURCE_ID_PREFIX = ('/subscriptions/sub/resourceGroups/fake-resource-group' '/providers/Microsoft.Compute/type/') # pylint: disable=line-too-long with mock.patch( 'libcloudforensics.providers.azure.internal.common.GetCredentials' ) as mock_creds: mock_creds.return_value = ('fake-subscription-id', mock.Mock()) with mock.patch( 'libcloudforensics.providers.azure.internal.resource.AZResource.GetOrCreateResourceGroup' ) as mock_resource: # pylint: enable=line-too-long mock_resource.return_value = 'fake-resource-group' FAKE_ACCOUNT = account.AZAccount('fake-resource-group', default_region='fake-region') FAKE_INSTANCE = compute.AZComputeVirtualMachine( FAKE_ACCOUNT, RESOURCE_ID_PREFIX + 'fake-vm-name', 'fake-vm-name', 'fake-region', ['fake-zone']) FAKE_DISK = compute.AZComputeDisk(FAKE_ACCOUNT, RESOURCE_ID_PREFIX + 'fake-disk-name', 'fake-disk-name', 'fake-region', ['fake-zone']) FAKE_BOOT_DISK = compute.AZComputeDisk( FAKE_ACCOUNT, RESOURCE_ID_PREFIX + 'fake-boot-disk-name', 'fake-boot-disk-name', 'fake-region', ['fake-zone']) FAKE_SNAPSHOT = compute.AZComputeSnapshot(
def CreateDiskCopy( resource_group_name: str, instance_name: Optional[str] = None, disk_name: Optional[str] = None, disk_type: Optional[str] = None, region: str = 'eastus', src_profile: Optional[str] = None, dst_profile: Optional[str] = None) -> 'compute.AZComputeDisk': """Creates a copy of an Azure Compute Disk. Args: resource_group_name (str): The resource group in which to create the disk copy. instance_name (str): Optional. Instance name of the instance using the disk to be copied. If specified, the boot disk of the instance will be copied. If disk_name is also specified, then the disk pointed to by disk_name will be copied. disk_name (str): Optional. Name of the disk to copy. If not set, then instance_name needs to be set and the boot disk will be copied. disk_type (str): Optional. The sku name for the disk to create. Can be Standard_LRS, Premium_LRS, StandardSSD_LRS, or UltraSSD_LRS. The default behavior is to use the same disk type as the source disk. region (str): Optional. The region in which to create the disk copy. Default is eastus. src_profile (str): Optional. The name of the source profile to use for the disk copy, i.e. the account information of the Azure account that holds the disk. For more information on profiles, see GetCredentials() in libcloudforensics.providers.azure.internal.common.py. If not provided, credentials will be gathered from environment variables. dst_profile (str): Optional. The name of the destination profile to use for the disk copy. The disk will be copied into the account linked to this profile. If not provided, the default behavior is that the destination profile is the same as the source profile. For more information on profiles, see GetCredentials() in libcloudforensics.providers.azure.internal.common.py Returns: AZComputeDisk: An Azure Compute Disk object. Raises: ResourceCreationError: If there are errors copying the disk. ValueError: If both instance_name and disk_name are missing. """ if not instance_name and not disk_name: raise ValueError( 'You must specify at least one of [instance_name, disk_name].') src_account = account.AZAccount(resource_group_name, default_region=region, profile_name=src_profile) dst_account = account.AZAccount(resource_group_name, default_region=region, profile_name=(dst_profile or src_profile)) try: if disk_name: disk_to_copy = src_account.compute.GetDisk(disk_name) elif instance_name: instance = src_account.compute.GetInstance(instance_name) disk_to_copy = instance.GetBootDisk() logger.info('Disk copy of {0:s} started...'.format(disk_to_copy.name)) if not disk_type: disk_type = disk_to_copy.GetDiskType() snapshot = disk_to_copy.Snapshot() subscription_ids = src_account.resource.ListSubscriptionIDs() diff_account = dst_account.subscription_id not in subscription_ids diff_region = dst_account.default_region != snapshot.region # If the destination account is different from the source account or if the # destination region is different from the region in which the source # disk is, then we need to create the disk from a storage account in # which we import the previously created snapshot (cross-region/account # sharing). if diff_account or diff_region: logger.info( 'Copy requested in a different destination account/region.') # Create a link to download the snapshot snapshot_uri = snapshot.GrantAccessAndGetURI() # Make a snapshot copy in the destination account from the link new_disk = dst_account.compute.CreateDiskFromSnapshotURI( snapshot, snapshot_uri, disk_name_prefix=common.DEFAULT_DISK_COPY_PREFIX, disk_type=disk_type) # Revoke download link and delete the initial copy snapshot.RevokeAccessURI() else: new_disk = dst_account.compute.CreateDiskFromSnapshot( snapshot, disk_name_prefix=common.DEFAULT_DISK_COPY_PREFIX, disk_type=disk_type) snapshot.Delete() logger.info('Disk {0:s} successfully copied to {1:s}'.format( disk_to_copy.name, new_disk.name)) except (errors.LCFError, RuntimeError) as exception: raise errors.ResourceCreationError( 'Cannot copy disk "{0:s}": {1!s}'.format(str(disk_name), exception), __name__) return new_disk
def SetUp(self, remote_profile_name, analysis_resource_group_name, incident_id, ssh_public_key, remote_instance_name=None, disk_names=None, all_disks=False, analysis_profile_name=None, analysis_region=None, boot_disk_size=50, cpu_cores=4, memory_in_mb=8192): """Sets up a Microsoft Azure collector. This method creates and starts an analysis VM in the analysis account and selects disks to copy from the remote account. If disk_names is specified, it will copy the corresponding disks from the account, ignoring disks belonging to any specific instances. If remote_instance_name is specified, two behaviors are possible: * If no other parameters are specified, it will select the instance's boot disk * if all_disks is set to True, it will select all disks in the account that are attached to the instance disk_names takes precedence over instance_names Args: remote_profile_name (str): The Azure account in which the disk(s) exist(s). This is the profile name that is defined in your credentials file. analysis_resource_group_name (str): The Azure resource group name in which to create the VM. incident_id (str): Incident identifier used to name the analysis VM. ssh_public_key (str): The public SSH key to attach to the instance. remote_instance_name (str): Instance ID that needs forensicating. disk_names (str): Comma-separated list of disk names to copy. all_disks (bool): True if all disk attached to the source instance should be copied. analysis_profile_name (str): The Azure account in which to create the analysis VM. This is the profile name that is defined in your credentials file. analysis_region (str): The Azure region in which to create the VM. boot_disk_size (int): Optional. The size (in GB) of the boot disk for the analysis VM. Default is 50 GB. cpu_cores (int): Optional. The number of CPU cores to use for the analysis VM. Default is 4. memory_in_mb (int): Optional. The amount of memory in mb to use for the analysis VM. Default is 8Gb. """ if not (remote_instance_name or disk_names): self.ModuleError( 'You need to specify at least an instance name or disks to copy', critical=True) return if not ssh_public_key: self.ModuleError( 'You need to specify a SSH public key to add to the ' 'VM.', critical=True) return if not (remote_profile_name and analysis_resource_group_name): self.ModuleError( 'You must specify "remote_profile_name" and ' '"analysis_resource_group_name" parameters', critical=True) return self.remote_profile_name = remote_profile_name self.analysis_resource_group_name = analysis_resource_group_name self.analysis_profile_name = analysis_profile_name self.source_account = account.AZAccount( self.analysis_resource_group_name, profile_name=self.remote_profile_name) self.incident_id = incident_id self.remote_instance_name = remote_instance_name self.disk_names = disk_names.split(',') if disk_names else [] self.all_disks = all_disks self.analysis_region = analysis_region self.analysis_profile_name = analysis_profile_name or remote_profile_name analysis_vm_name = 'azure-forensics-vm-{0:s}'.format(self.incident_id) print('Your analysis VM will be: {0:s}'.format(analysis_vm_name)) self.state.StoreContainer( containers.TicketAttribute( name=self._ANALYSIS_VM_CONTAINER_ATTRIBUTE_NAME, type_=self._ANALYSIS_VM_CONTAINER_ATTRIBUTE_TYPE, value=analysis_vm_name)) self.analysis_vm, _ = az_forensics.StartAnalysisVm( self.analysis_resource_group_name, analysis_vm_name, boot_disk_size, ssh_public_key=ssh_public_key, cpu_cores=cpu_cores, memory_in_mb=memory_in_mb, region=self.analysis_region, dst_profile=self.analysis_profile_name, )