def CreateVolumeCopy(zone: str,
                     dst_zone: Optional[str] = None,
                     instance_id: Optional[str] = None,
                     volume_id: Optional[str] = None,
                     volume_type: Optional[str] = None,
                     src_profile: Optional[str] = None,
                     dst_profile: Optional[str] = None,
                     tags: Optional[Dict[str, str]] = None) -> 'ebs.AWSVolume':
  """Create a copy of an AWS EBS Volume.

  By default, the volume copy will be created in the same AWS account where
  the source volume sits. If you want the volume copy to be created in a
  different AWS account, you can specify one in the dst_profile parameter.
  The following example illustrates how you should configure your AWS
  credentials file for such a use case.

  # AWS credentials file
  [default] # default account to use with AWS
  aws_access_key_id=foo
  aws_secret_access_key=bar

  [investigation] # source account for a particular volume to be copied from
  aws_access_key_id=foo1
  aws_secret_access_key=bar1

  [forensics] # destination account to create the volume copy in
  aws_access_key_id=foo2
  aws_secret_access_key=bar2

  # Copies the boot volume from instance "instance_id" from the default AWS
  # account to the default AWS account.
  volume_copy = CreateVolumeCopy(zone, instance_id='instance_id')

  # Copies the boot volume from instance "instance_id" from the default AWS
  # account to the 'forensics' AWS account.
  volume_copy = CreateVolumeCopy(
      zone, instance_id='instance_id', dst_profile='forensics')

  # Copies the boot volume from instance "instance_id" from the
  # 'investigation' AWS account to the 'forensics' AWS account.
  volume_copy = CreateVolumeCopy(
      zone,
      instance_id='instance_id',
      src_profile='investigation',
      dst_profile='forensics')

  Args:
    zone (str): The AWS zone in which the volume is located, e.g. 'us-east-2b'.
    dst_zone (str): Optional. The AWS zone in which to create the volume
        copy. By default, this is the same as 'zone'.
    instance_id (str): Optional. Instance ID of the instance using the volume
        to be copied. If specified, the boot volume of the instance will be
        copied. If volume_id is also specified, then the volume pointed by
        that volume_id will be copied.
    volume_id (str): Optional. ID of the volume to copy. If not set,
        then instance_id needs to be set and the boot volume will be copied.
    volume_type (str): Optional. The volume type for the volume to be
        created. Can be one of 'standard'|'io1'|'gp2'|'gp3'|'sc1'|'st1'. The
        default behavior is to use the same volume type as the source volume.
    src_profile (str): Optional. If the AWS account containing the volume
        that needs to be copied is different from the default account
        specified in the AWS credentials file then you can specify a
        different profile name here (see example above).
    dst_profile (str): Optional. If the volume copy needs to be created in a
        different AWS account, you can specify a different profile name here
        (see example above).
    tags (Dict[str, str]): Optional. A dictionary of tags to add to the
          volume copy, for example {'TicketID': 'xxx'}.

  Returns:
    AWSVolume: An AWS EBS Volume object.

  Raises:
    ResourceCreationError: If there are errors copying the volume, or errors
        during KMS key creation/sharing if the target volume is encrypted.
    ValueError: If both instance_id and volume_id are missing, or if AWS
        account information could not be retrieved.
  """

  if not instance_id and not volume_id:
    raise ValueError(
        'You must specify at least one of [instance_id, volume_id].')

  source_account = account.AWSAccount(zone, aws_profile=src_profile)
  destination_account = account.AWSAccount(zone, aws_profile=dst_profile)
  kms_key_id = None

  try:
    if volume_id:
      volume_to_copy = source_account.ebs.GetVolumeById(volume_id)
    elif instance_id:
      instance = source_account.ec2.GetInstanceById(instance_id)
      volume_to_copy = instance.GetBootVolume()

    if not volume_type:
      volume_type = volume_to_copy.GetVolumeType()

    logger.info('Volume copy of {0:s} started...'.format(
        volume_to_copy.volume_id))
    snapshot = volume_to_copy.Snapshot()
    logger.info('Created snapshot: {0:s}'.format(snapshot.snapshot_id))

    source_account_id = source_account.ebs.GetAccountInformation().get(
        'Account')
    destination_account_id = destination_account.ebs.GetAccountInformation(
        ).get('Account')

    if not (source_account_id and destination_account_id):
      raise ValueError(
          'Could not retrieve AWS account ID: source {0!s}, dest: {1!s}'.format(
              source_account_id, destination_account_id))

    if source_account_id != destination_account_id:
      logger.info('External account detected: source account ID is {0:s} and '
                  'destination account ID is {1:s}'.format(
                      source_account_id, destination_account_id))
      if volume_to_copy.encrypted:
        logger.info(
            'Encrypted volume detected, generating one-time use CMK key')
        # Generate one-time use KMS key that will be shared with the
        # destination account.
        kms_key_id = source_account.kms.CreateKMSKey()
        source_account.kms.ShareKMSKeyWithAWSAccount(
            kms_key_id, destination_account_id)
        # Create a copy of the initial snapshot and encrypts it with the
        # shared key
        snapshot = snapshot.Copy(kms_key_id=kms_key_id, delete=True)
      snapshot.ShareWithAWSAccount(destination_account_id)
      logger.info('Snapshot successfully shared with external account')

    if dst_zone and dst_zone != zone:
      # Assign the new zone to the destination account and assign it to the
      # snapshot so that it can copy it
      destination_account = account.AWSAccount(
          dst_zone, aws_profile=dst_profile)
      snapshot.aws_account = destination_account
      snapshot = snapshot.Copy(delete=True, deletion_account=source_account)

    if tags and tags.get('Name'):
      new_volume = destination_account.ebs.CreateVolumeFromSnapshot(
          snapshot,
          volume_type=volume_type,
          volume_name=tags['Name'],
          tags=tags)
    else:
      new_volume = destination_account.ebs.CreateVolumeFromSnapshot(
          snapshot,
          volume_type=volume_type,
          volume_name_prefix='evidence',
          tags=tags)

    logger.info('Volume {0:s} successfully copied to {1:s}'.format(
        volume_to_copy.volume_id, new_volume.volume_id))
    logger.info('Cleaning up...')

    snapshot.Delete()
    # Delete the one-time use KMS key, if one was generated
    source_account.kms.DeleteKMSKey(kms_key_id)
    logger.info('Done')
  except (errors.LCFError, RuntimeError) as exception:
    raise errors.ResourceCreationError(
        'Copying volume {0:s}: {1!s}'.format(
            (volume_id or instance_id), exception), __name__) from exception

  return new_volume
Create a copy of an AWS EBS Volume.

By default, the volume copy will be created in the same AWS account where
the source volume sits. If you want the volume copy to be created in a
different AWS account, you can specify one in the dst_profile parameter.
The following example illustrates how you should configure your AWS
credentials file for such a use case.

# AWS credentials file
[default] # default account to use with AWS
aws_access_key_id=foo
aws_secret_access_key=bar

[investigation] # source account for a particular volume to be copied from
aws_access_key_id=foo1
aws_secret_access_key=bar1

[forensics] # destination account to create the volume copy in
aws_access_key_id=foo2
aws_secret_access_key=bar2

# Copies the boot volume from instance "instance_id" from the default AWS
# account to the default AWS account.
volume_copy = CreateVolumeCopy(zone, instance_id='instance_id')

# Copies the boot volume from instance "instance_id" from the default AWS
# account to the 'forensics' AWS account.
volume_copy = CreateVolumeCopy(
zone, instance_id='instance_id', dst_profile='forensics')

# Copies the boot volume from instance "instance_id" from the
# 'investigation' AWS account to the 'forensics' AWS account.
volume_copy = CreateVolumeCopy(
zone,
instance_id='instance_id',
src_profile='investigation',
dst_profile='forensics')

Args:
zone (str): The AWS zone in which the volume is located, e.g. 'us-east-2b'.
dst_zone (str): Optional. The AWS zone in which to create the volume
copy. By default, this is the same as 'zone'.
instance_id (str): Optional. Instance ID of the instance using the volume
to be copied. If specified, the boot volume of the instance will be
copied. If volume_id is also specified, then the volume pointed by
that volume_id will be copied.
volume_id (str): Optional. ID of the volume to copy. If not set,
then instance_id needs to be set and the boot volume will be copied.
volume_type (str): Optional. The volume type for the volume to be
created. Can be one of 'standard'|'io1'|'gp2'|'gp3'|'sc1'|'st1'. The
default behavior is to use the same volume type as the source volume.
src_profile (str): Optional. If the AWS account containing the volume
that needs to be copied is different from the default account
specified in the AWS credentials file then you can specify a
different profile name here (see example above).
dst_profile (str): Optional. If the volume copy needs to be created in a
different AWS account, you can specify a different profile name here
(see example above).
tags (Dict[str, str]): Optional. A dictionary of tags to add to the
volume copy, for example {'TicketID': 'xxx'}.

Returns:
AWSVolume: An AWS EBS Volume object.

Raises:
ResourceCreationError: If there are errors copying the volume, or errors
during KMS key creation/sharing if the target volume is encrypted.
ValueError: If both instance_id and volume_id are missing, or if AWS
account information could not be retrieved.
libcloudforensics/providers/aws/forensics.py