Example #1
0
    def ListVolumes(
        self,
        region: Optional[str] = None,
        # pylint: disable=line-too-long
        filters: Optional[List[Dict[str, Any]]] = None
    ) -> Dict[str, ebs.AWSVolume]:
        # pylint: enable=line-too-long
        """List volumes of an AWS account.

    Example usage:
      # List volumes attached to the instance 'some-instance-id'
      ListVolumes(filters=[
          {'Name':'attachment.instance-id', 'Values':['some-instance-id']}])

    Args:
      region (str): Optional. The region from which to list the volumes.
          If none provided, the default_region associated to the AWSAccount
          object will be used.
      filters (List[Dict]): Optional. Filters for the query. Filters are
          given as a list of dictionaries, e.g.: {'Name': 'someFilter',
          'Values': ['value1', 'value2']}.

    Returns:
      Dict[str, AWSVolume]: Dictionary mapping volume IDs (str) to their
          respective AWSVolume object.

    Raises:
      RuntimeError: If volumes can't be listed.
    """

        if not filters:
            filters = []

        volumes = {}
        client = self.ClientApi(common.EC2_SERVICE, region=region)
        responses = common.ExecuteRequest(client, 'describe_volumes',
                                          {'Filters': filters})
        for response in responses:
            for volume in response['Volumes']:
                volume_id = volume['VolumeId']
                aws_volume = ebs.AWSVolume(volume_id, self,
                                           self.default_region,
                                           volume['AvailabilityZone'],
                                           volume['Encrypted'])

                for tag in volume.get('Tags', []):
                    if tag.get('Key') == 'Name':
                        aws_volume.name = tag.get('Value')
                        break

                for attachment in volume.get('Attachments', []):
                    if attachment.get('State') == 'attached':
                        aws_volume.device_name = attachment.get('Device')
                        break

                volumes[volume_id] = aws_volume
        return volumes
import mock

from libcloudforensics.providers.aws.internal import account, common, ebs, ec2
from libcloudforensics.providers.aws.internal import log as aws_log
from libcloudforensics.providers.aws import forensics

FAKE_AWS_ACCOUNT = account.AWSAccount(default_availability_zone='fake-zone-2b')
FAKE_INSTANCE = ec2.AWSInstance(FAKE_AWS_ACCOUNT, 'fake-instance-id',
                                'fake-zone-2', 'fake-zone-2b')
FAKE_INSTANCE_WITH_NAME = ec2.AWSInstance(FAKE_AWS_ACCOUNT,
                                          'fake-instance-with-name-id',
                                          'fake-zone-2',
                                          'fake-zone-2b',
                                          name='fake-instance')
FAKE_VOLUME = ebs.AWSVolume('fake-volume-id', FAKE_AWS_ACCOUNT, 'fake-zone-2',
                            'fake-zone-2b', False)
FAKE_BOOT_VOLUME = ebs.AWSVolume('fake-boot-volume-id',
                                 FAKE_AWS_ACCOUNT,
                                 'fake-zone-2',
                                 'fake-zone-2b',
                                 False,
                                 name='fake-boot-volume',
                                 device_name='/dev/spf')
FAKE_SNAPSHOT = ebs.AWSSnapshot('fake-snapshot-id',
                                FAKE_AWS_ACCOUNT,
                                'fake-zone-2',
                                'fake-zone-2b',
                                FAKE_VOLUME,
                                name='fake-snapshot')
FAKE_CLOUDTRAIL = aws_log.AWSCloudTrail(FAKE_AWS_ACCOUNT)
FAKE_EVENT_LIST = [
Example #3
0
    def CreateVolumeFromSnapshot(
            self,
            snapshot: ebs.AWSSnapshot,
            volume_name: Optional[str] = None,
            volume_name_prefix: str = '',
            kms_key_id: Optional[str] = None) -> ebs.AWSVolume:
        """Create a new volume based on a snapshot.

    Args:
      snapshot (AWSSnapshot): Snapshot to use.
      volume_name (str): Optional. String to use as new volume name.
      volume_name_prefix (str): Optional. String to prefix the volume name with.
      kms_key_id (str): Optional. A KMS key id to encrypt the volume with.

    Returns:
      AWSVolume: An AWS EBS Volume.

    Raises:
      ValueError: If the volume name does not comply with the RegEx.
      RuntimeError: If the volume could not be created.
    """

        if not volume_name:
            volume_name = self._GenerateVolumeName(
                snapshot, volume_name_prefix=volume_name_prefix)

        if not common.REGEX_TAG_VALUE.match(volume_name):
            raise ValueError('Volume name {0:s} does not comply with '
                             '{1:s}'.format(volume_name,
                                            common.REGEX_TAG_VALUE.pattern))

        client = self.ClientApi(common.EC2_SERVICE)
        create_volume_args = {
            'AvailabilityZone':
            snapshot.availability_zone,
            'SnapshotId':
            snapshot.snapshot_id,
            'TagSpecifications':
            [common.GetTagForResourceType('volume', volume_name)]
        }
        if kms_key_id:
            create_volume_args['Encrypted'] = True
            create_volume_args['KmsKeyId'] = kms_key_id
        try:
            volume = client.create_volume(**create_volume_args)
            volume_id = volume['VolumeId']
            # Wait for volume creation completion
            client.get_waiter('volume_available').wait(VolumeIds=[volume_id])
        except (client.exceptions.ClientError,
                botocore.exceptions.WaiterError) as exception:
            raise RuntimeError('Could not create volume {0:s} from snapshot '
                               '{1:s}: {2:s}'.format(volume_name,
                                                     snapshot.name,
                                                     str(exception)))

        zone = volume['AvailabilityZone']
        encrypted = volume['Encrypted']

        return ebs.AWSVolume(volume_id,
                             self,
                             self.default_region,
                             zone,
                             encrypted,
                             name=volume_name)
    def CreateVolumeFromSnapshot(
            self,
            snapshot: ebs.AWSSnapshot,
            volume_name: Optional[str] = None,
            volume_name_prefix: Optional[str] = None,
            kms_key_id: Optional[str] = None,
            tags: Optional[Dict[str, str]] = None) -> ebs.AWSVolume:
        """Create a new volume based on a snapshot.

    Args:
      snapshot (AWSSnapshot): Snapshot to use.
      volume_name (str): Optional. String to use as new volume name.
      volume_name_prefix (str): Optional. String to prefix the volume name with.
      kms_key_id (str): Optional. A KMS key id to encrypt the volume with.
      tags (Dict[str, str]): Optional. A dictionary of tags to add to the
          volume, for example {'TicketID': 'xxx'}. An entry for the volume
          name is added by default.

    Returns:
      AWSVolume: An AWS EBS Volume.

    Raises:
      ValueError: If the volume name does not comply with the RegEx.
      RuntimeError: If the volume could not be created.
    """

        if not volume_name:
            volume_name = self._GenerateVolumeName(
                snapshot, volume_name_prefix=volume_name_prefix)

        if len(volume_name) > 255:
            raise ValueError(
                'Volume name {0:s} is too long (>255 chars)'.format(
                    volume_name))

        if not tags:
            tags = {}
        tags['Name'] = volume_name

        client = self.ClientApi(common.EC2_SERVICE)
        create_volume_args = {
            'AvailabilityZone': snapshot.availability_zone,
            'SnapshotId': snapshot.snapshot_id,
            'TagSpecifications': [common.CreateTags(common.VOLUME, tags)]
        }
        if kms_key_id:
            create_volume_args['Encrypted'] = True
            create_volume_args['KmsKeyId'] = kms_key_id
        try:
            volume = client.create_volume(**create_volume_args)
            volume_id = volume['VolumeId']
            # Wait for volume creation completion
            client.get_waiter('volume_available').wait(VolumeIds=[volume_id])
        except (client.exceptions.ClientError,
                botocore.exceptions.WaiterError) as exception:
            raise RuntimeError('Could not create volume {0:s} from snapshot '
                               '{1:s}: {2:s}'.format(volume_name,
                                                     snapshot.name,
                                                     str(exception)))

        zone = volume['AvailabilityZone']
        encrypted = volume['Encrypted']

        return ebs.AWSVolume(volume_id,
                             self,
                             self.default_region,
                             zone,
                             encrypted,
                             name=volume_name)
    def CreateVolumeFromSnapshot(
            self,
            snapshot: ebs.AWSSnapshot,
            volume_name: Optional[str] = None,
            volume_name_prefix: Optional[str] = None,
            volume_type: str = 'gp2',
            kms_key_id: Optional[str] = None,
            tags: Optional[Dict[str, str]] = None) -> ebs.AWSVolume:
        """Create a new volume based on a snapshot.

    Args:
      snapshot (AWSSnapshot): Snapshot to use.
      volume_name (str): Optional. String to use as new volume name.
      volume_name_prefix (str): Optional. String to prefix the volume name with.
      volume_type (str): Optional. The volume type for the volume to create.
          Can be one of 'standard'|'io1'|'gp2'|'sc1'|'st1'. The default is
          'gp2'.
      kms_key_id (str): Optional. A KMS key id to encrypt the volume with.
      tags (Dict[str, str]): Optional. A dictionary of tags to add to the
          volume, for example {'TicketID': 'xxx'}. An entry for the volume
          name is added by default.

    Returns:
      AWSVolume: An AWS EBS Volume.

    Raises:
      ValueError: If the volume name does not comply with the RegEx,
          or if the volume type is invalid.
      RuntimeError: If the volume could not be created.
    """

        if volume_type not in ['standard', 'io1', 'gp2', 'sc1', 'st1']:
            raise ValueError(
                'Volume type must be one of [standard, io1, gp2, sc1, '
                'st1]. Got: {0:s}'.format(volume_type))

        if not volume_name:
            volume_name = self._GenerateVolumeName(
                snapshot, volume_name_prefix=volume_name_prefix)

        if len(volume_name) > 255:
            raise ValueError(
                'Volume name {0:s} is too long (>255 chars)'.format(
                    volume_name))

        if not tags:
            tags = {}
        tags['Name'] = volume_name

        client = self.ClientApi(common.EC2_SERVICE)
        create_volume_args = {
            'AvailabilityZone': snapshot.availability_zone,
            'SnapshotId': snapshot.snapshot_id,
            'TagSpecifications': [common.CreateTags(common.VOLUME, tags)],
            'VolumeType': volume_type
        }
        if kms_key_id:
            create_volume_args['Encrypted'] = True
            create_volume_args['KmsKeyId'] = kms_key_id
        if volume_type == 'io1':
            # If using the io1 volume type, we must specify Iops, see
            # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/
            # services/ec2.html#EC2.Client.create_volume. io1 volumes allow for a
            # ratio of 50 IOPS per 1 GiB.
            create_volume_args['Iops'] = self.ResourceApi(
                common.EC2_SERVICE).Snapshot(
                    snapshot.snapshot_id).volume_size * 50
        try:
            volume = client.create_volume(**create_volume_args)
            volume_id = volume['VolumeId']
            # Wait for volume creation completion
            client.get_waiter('volume_available').wait(VolumeIds=[volume_id])
        except (client.exceptions.ClientError,
                botocore.exceptions.WaiterError) as exception:
            raise RuntimeError('Could not create volume {0:s} from snapshot '
                               '{1:s}: {2:s}'.format(volume_name,
                                                     snapshot.name,
                                                     str(exception)))

        zone = volume['AvailabilityZone']
        encrypted = volume['Encrypted']

        return ebs.AWSVolume(volume_id,
                             self,
                             self.default_region,
                             zone,
                             encrypted,
                             name=volume_name)