Daniel López Azaña

Theme

Social Media

Blog

GNU/Linux, Open Source, Cloud Computing, DevOps and more...

How to share an AMI between 2 AWS accounts

Copy AMI using customer managed key for encryption

If you have an unencrypted AMI you can share it with another AWS account directly without doing anything special. But if the AMI is encrypted, things get complicated, as the destination account won’t have the encryption key to decrypt its snapshots and you won’t be able to share it.

Therefore, if you need to share an encrypted AMI from an EC2 instance from one AWS account to another, you’ll need to follow this procedure to make it work properly:

1.- Create a new Customer managed key in the AWS KMS service

You’ll need to create a new customer managed key in AWS KMS following these steps:

Adding special permissions to the KMS key

If you need to add special permissions to the KMS key, you can edit its JSON code directly. For example, in the following example you can add permissions to use the key for encryption and decryption to a specific IAM role. In the example, account aaaaaaaaaaaa is the source and bbbbbbbbbbbbb is the destination:

{
    "Version": "2012-10-17",
    "Id": "key-consolepolicy-3",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::aaaaaaaaaaaa:root",
                    "arn:aws:iam::bbbbbbbbbbbbb:role/bbbbbbbbbbbbb-admin"                    
                ]
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow access for Key Administrators",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::aaaaaaaaaaaa:user/username_with_admin_privileges_from_aaaaaaaaaaaa_account"
                ]
            },
            "Action": [
                "kms:Create*",
                "kms:Describe*",
                "kms:Enable*",
                "kms:List*",
                "kms:Put*",
                "kms:Update*",
                "kms:Revoke*",
                "kms:Disable*",
                "kms:Get*",
                "kms:Delete*",
                "kms:TagResource",
                "kms:UntagResource",
                "kms:ScheduleKeyDeletion",
                "kms:CancelKeyDeletion",
                "kms:ReplicateKey",
                "kms:UpdatePrimaryRegion"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::aaaaaaaaaaaa:root",
                    "arn:aws:iam::aaaaaaaaaaaa:role/aaaaaaaaaaaa-admin",
                    "arn:aws:iam::aaaaaaaaaaaa:user/username_with_admin_privileges_from_aaaaaaaaaaaa_account",
                    "arn:aws:iam::bbbbbbbbbbbb:root",
                    "arn:aws:iam::bbbbbbbbbbbb:role/bbbbbbbbbbbb-admin"
                ]
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::aaaaaaaaaaaa:root",
                    "arn:aws:iam::aaaaaaaaaaaa:role/aaaaaaaaaaaa-admin",
                    "arn:aws:iam::aaaaaaaaaaaa:user/username_with_admin_privileges_from_aaaaaaaaaaaa_account",
                    "arn:aws:iam::bbbbbbbbbbbb:root",
                    "arn:aws:iam::bbbbbbbbbbbb:role/bbbbbbbbbbbb-admin"
                ]
            },
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        }
    ]
}

2.- Copy the AMI using the new customer managed encryption key

Make a copy of the AMI you want to share with the other AWS account, but this time using the new encryption key you created in the previous step. To do this, go to the AMI section of Amazon EC2 service, select the AMI you want to share, and with the right button select the “Copy AMI” option. As you can see in the following screenshot, you’ll select the multi-account-shared-aws-key KMS key you just created:

Copy AMI using customer managed key for encryption

3.- Modify AMI permissions to share it with the destination account

Once copied, you’ll modify the permissions of the new AMI to add the account ID you want to share it with. Just click on the “Add account ID” button and enter the destination AWS account ID:

Edit AMI permissions to add shared account

4.- Verify the shared AMI is visible in the destination account

After this, if you access the destination account console, you can now see the shared AMI in the AMI list. But it’s important to select private images in the filter, otherwise it won’t show up since by default only images you own are shown. But in this case the owner is the source account.

Shared AMI from destination account

5.- (Optional) Create a copy in the destination account

Finally, if you want to keep a copy of the AMI in the destination account encrypted with its own keys and have the destination account ID appear as the owner, you’ll make a copy of it just as you did in step 2, but this time selecting the default encryption key of the destination account or another one you have created specifically for that account. This way you’ll have full ownership and control of the AMI in the destination account.

AWS EC2 AMI KMS Security
Daniel López Azaña

About the author

Daniel López Azaña

Tech entrepreneur and cloud architect with over 20 years of experience transforming infrastructures and automating processes.

Specialist in AI/LLM integration, Rust and Python development, and AWS & GCP architecture. Restless mind, idea generator, and passionate about technological innovation and AI.

Related articles

Script to automatically change all gp2 volumes to gp3 with aws-cli

Script to automatically change all gp2 volumes to gp3 with aws-cli

Last December Amazon announced its new EBS gp3 volumes, which offer better performance and a cost saving of 20% compared to those that have been used until now (gp2). Well, after successfully testing these new volumes with multiple clients, I can do nothing but recommend their use, because they are all advantages and in these 2 and a half months that have passed since the announcement I have not noticed any problems or side effects.

February 16, 2021
AWS security groups

How to automatically update all your AWS EC2 security groups when your dynamic IP changes

One of the biggest annoyances when working with AWS and your Internet connection has a dynamic IP is that when it changes, you immediately stop accessing to all servers and services protected by an EC2 security group whose rules only allow traffic to certain specific IP’s instead of allowing open connections to everyone (0.0.0.0.0/0).Certainly the simplest thing to do is always allowing traffic on a given port to everyone, so that even if you have a dynamic IP on your Internet connection you will always be able to continue accessing even if it changes. But opening traffic on a port to everyone is not the right way to proceed from a security point of view, because then any attacker will be able to access that port without restrictions, and that is not what you want.

January 12, 2021
Diagrama de una instancia EC2 con múltiples interfaces de red compartiendo la misma subred dentro de la misma zona de disponibilidad en AWS

How to use 2 network interfaces on the same AWS subnet in Linux

The following Linux procedure describes how to use at the same time 2 network interfaces connected to the same AWS subnet and, which is more important, how to make both communication works well internally (between hosts on the same subnet) and also externally (both interfaces visible from the Internet). This can be useful for example when you want the same EC2 instance to host a web server serving http or https requests and at the same time have a websockets server ws:// or wss:// listening on the same port 80 or 443 respectively. Although there are other ways to achieve this such as configuring Nginx to be able to discriminate web traffic (http) from websockets traffic (ws) and act as a proxy to redirect the corresponding requests to the websockets server, this other solution I propose seems simpler and to some extent more efficient because it is not necessary to redirect traffic, which will always introduce a small latency, and allows to keep both servers completely independent within the same host. The only drawback is that you will need to assign 2 Elastic IP addresses to the same EC2 instance instead of only 1, but at the same time this will give you more flexibility when establishing rules in the security groups or in the subnet NAT rules.

October 6, 2017

Comments

Be the first to comment

Submit comment