Beispiel #1
0
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
Beispiel #3
0
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))
Beispiel #4
0
 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
Beispiel #5
0
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))
Beispiel #6
0
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))
Beispiel #7
0
 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
Beispiel #8
0
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(
Beispiel #9
0
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
Beispiel #10
0
    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,
        )