Copying AMIs between accounts is difficult, because even if an image is public, the snapshot behind it is private by default. Here we’ll talk about ways of getting around it.

The easy way is to start an instance with the desired image, then create a new image from the instance. We can then copy to another region if we want to.

A more involved approach is to copy the snapshot(s) to our account and then register the image. This does require knowing who the owner of the image is in order for them to share the snapshots with us.

Discovery

We’ll need to describe the image we want to copy to find the snapshot(s) that will need to be shared.

Example API Request

1
2
3
4
https://ec2.us-east-1.amazonaws.com
?Action=DescribeImages
&ImageId.1=ami-12345678
&*AUTHPARAMS*

Console - user@hostname ~ $

1
2
3
aws --region us-east-1 ec2 \
describe-images \
--image-ids "[\"ami-12345678\"]"

Output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
    "Images": [
        {
            "VirtualizationType": "paravirtual",
            "Name": "Example_Image",
            "Hypervisor": "xen",
            "ImageId": "ami-12345678",
            "RootDeviceType": "ebs",
            "State": "available",
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/sda",
                    "Ebs": {
                        "DeleteOnTermination": true,
                        "SnapshotId": "snap-23456789",
                        "VolumeSize": 10,
                        "VolumeType": "standard",
                        "Encrypted": false
                    }
                },
                {
                    "DeviceName": "/dev/sdb",
                    "VirtualName": "ephemeral0"
                },
                {
                    "DeviceName": "/dev/sdc",
                    "VirtualName": "ephemeral1"
                },
                {
                    "DeviceName": "/dev/sdd",
                    "VirtualName": "ephemeral2"
                },
                {
                    "DeviceName": "/dev/sde",
                    "VirtualName": "ephemeral3"
                }
            ],
            "Architecture": "x86_64",
            "ImageLocation": "234567890123/Example_Image",
            "KernelId": "aki-b4aa75dd",
            "OwnerId": "234567890123",
            "RootDeviceName": "/dev/sda",
            "Public": true,
            "ImageType": "machine",
            "Description": "Example Description"
        }
    ]
}

Note all the snapshots in BlockDeviceMappings, just snap-23456789 in this case.

Sharing

Looking at OwnerId of the image description, we’ll get account 234567890123 to share with us (account 123456789012).

With User

You can have the other account share it with specified users.

Example API Request

1
2
3
4
5
https://ec2.us-east-1.amazonaws.com
?Action=ModifySnapshotAttribute
&SnapshotId=snap-23456789
&CreateVolumePermission.Add.1.UserId=123456789012
&*AUTHPARAMS*

Console - user@hostname ~ $

1
2
3
4
5
6
7
8
9
10
aws --profile "account2" --region us-east-1 ec2 \
modify-snapshot-attribute \
--snapshot-id "snap-23456789" \
--create-volume-permission "{
    \"Add\": [
        {
            \"UserId\": \"123456789012\"
        }
    ]
}"

With Public

Or the other account can just make the snapshot(s) public.

Example API Request

1
2
3
4
5
https://ec2.us-east-1.amazonaws.com
?Action=ModifySnapshotAttribute
&SnapshotId=snap-23456789
&CreateVolumePermission.Add.1.Group=all
&*AUTHPARAMS*

Console - user@hostname ~ $

1
2
3
4
5
6
7
8
9
10
aws --profile "account2" --region us-east-1 ec2 \
modify-snapshot-attribute \
--snapshot-id "snap-23456789" \
--create-volume-permission "{
    \"Add\": [
        {
            \"Group\": \"all\"
        }
    ]
}"

Copy Snapshot

Now we copy the snapshot(s).

Example API Request

1
2
3
4
5
6
7
https://ec2.us-east-1.amazonaws.com
?Action=CopySnapshot
&SourceRegion=us-east-1
&SourceSnapshotId=snap-23456789
&DestinationRegion=us-east-1
&Description=Example&20Description
&*AUTHPARAMS*

Console - user@hostname ~ $

1
2
3
4
5
6
aws --region us-east-1 ec2 \
copy-snapshot \
--source-region "us-east-1" \
--source-snapshot-id "snap-23456789" \
--destination-region "us-east-1" \
--description "Example Description"

Output

1
2
3
{
    "SnapshotId": "snap-abcdef01"
}

Register Image

And register the image once the snapshot(s) are copied.

Example API Request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
https://ec2.us-east-1.amazonaws.com/
?Action=RegisterImage
&Name=Example_Image_Name
&Description=Example%20Image%20Description
&Architecture=x86_64
&KernelId=aki-b4aa75dd
&RootDeviceName=/dev/sda
&BlockDeviceMapping.1.DeviceName=/dev/sda1
&BlockDeviceMapping.1.SnapshotId=snap-abcdef01
&BlockDeviceMapping.2.DeviceName=/dev/sdb
&BlockDeviceMapping.2.VirtualName=ephemeral0
&BlockDeviceMapping.3.DeviceName=/dev/sdc
&BlockDeviceMapping.3.VirtualName=ephemeral1
&BlockDeviceMapping.4.DeviceName=/dev/sdd
&BlockDeviceMapping.4.VirtualName=ephemeral2
&BlockDeviceMapping.5.DeviceName=/dev/sde
&BlockDeviceMapping.5.VirtualName=ephemeral3
&*AUTHPARAMS*

Console - user@hostname ~ $

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
aws --region=us-east-1 ec2 \
register-image \
--name "Example_Image_Name" \
--description "Example Image Description" \
--architecture x86_64 \
--kernel-id aki-b4aa75dd \
--root-device-name "/dev/sda" \
--block-device-mappings "[
    {
        \"DeviceName\": \"/dev/sda1\",
        \"Ebs\": {
            \"SnapshotId\": \"snap-abcdef01\"
        }
    },
    {
        \"DeviceName\": \"/dev/sdb\",
        \"VirtualName\": \"ephemeral0\"
    },
    {
        \"DeviceName\": \"/dev/sdc\",
        \"VirtualName\": \"ephemeral1\"
    },
    {
        \"DeviceName\": \"/dev/sdd\",
        \"VirtualName\": \"ephemeral2\"
    },
    {
        \"DeviceName\": \"/dev/sde\",
        \"VirtualName\": \"ephemeral3\"
    }
]"

Output

1
2
3
{
    "ImageId": "ami-a1b2c3d4"
}

Turn Off Sharing

With User

If the other account wants to revoke permission for a single user:

Example API Request

1
2
3
4
5
https://ec2.us-east-1.amazonaws.com
?Action=ModifySnapshotAttribute
&SnapshotId=snap-23456789
&CreateVolumePermission.Remove.1.UserId=123456789012
&*AUTHPARAMS*

Console - user@hostname ~ $

1
2
3
4
5
6
7
8
9
10
aws --profile "account2" --region us-east-1 ec2 \
modify-snapshot-attribute \
--snapshot-id "snap-23456789" \
--create-volume-permission "{
    \"Remove\": [
        {
            \"UserId\": \"123456789012\"
        }
    ]
}"

With Public

If the snapshot(s) were public and the other account now desires to have them be private again:

Example API Request

1
2
3
4
5
https://ec2.us-east-1.amazonaws.com
?Action=ModifySnapshotAttribute
&SnapshotId=snap-23456789
&CreateVolumePermission.Remove.1.Group=all
&*AUTHPARAMS*

Console - user@hostname ~ $

1
2
3
4
5
6
7
8
9
10
aws --profile "account2" --region us-east-1 ec2 \
modify-snapshot-attribute \
--snapshot-id "snap-23456789" \
--create-volume-permission "{
    \"Remove\": [
        {
            \"Group\": \"all\"
        }
    ]
}"