{"id":1162,"date":"2026-09-08T07:28:25","date_gmt":"2026-09-08T07:28:25","guid":{"rendered":"https:\/\/www.devopsschool.com\/tutorials\/?p=1162"},"modified":"2026-09-08T07:28:27","modified_gmt":"2026-09-08T07:28:27","slug":"aws-elastic-ip-cross-account-cross-organization-transfer-runbook","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/tutorials\/aws-elastic-ip-cross-account-cross-organization-transfer-runbook\/","title":{"rendered":"AWS Elastic IP Cross-Account \/ Cross-Organization Transfer Runbook"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>Use case:<\/strong> AWS Organization A \/ Account A \u2192 AWS Organization B \/ Account B<br><strong>Objective:<\/strong> Retain the exact same public IPv4 address while changing AWS account ownership.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">1. Executive Summary<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Final answer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Yes. AWS supports transferring a normal Amazon-provided Elastic IP address between AWS accounts that belong to completely different AWS Organizations.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The accounts <strong>do not need to belong to the same AWS Organization<\/strong>. AWS explicitly states that an Elastic IP can be transferred from <strong>any AWS account to any other AWS account in the same AWS Region<\/strong>. AWS also explicitly discusses an EIP being transferred to an account <strong>outside the Organization<\/strong>, confirming cross-Organization transfers are supported.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For this migration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AWS Organization A\n\u2514\u2500\u2500 Source Account A\n    \u2514\u2500\u2500 EIP 1.2.3.4\n\n             \u2193 ownership transfer\n\nAWS Organization B\n\u2514\u2500\u2500 Destination Account B\n    \u2514\u2500\u2500 SAME public EIP 1.2.3.4\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <strong>public IPv4 address remains the same<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>the EIP&#8217;s AWS <strong>allocation ID changes after successful transfer<\/strong>;<\/li>\n\n\n\n<li>tags do not transfer;<\/li>\n\n\n\n<li>EC2\/ENI\/NAT associations do not transfer;<\/li>\n\n\n\n<li>VPCs do not transfer;<\/li>\n\n\n\n<li>NAT gateways do not transfer;<\/li>\n\n\n\n<li>DNS resources do not transfer;<\/li>\n\n\n\n<li>PTR\/reverse-DNS configuration must be removed before acceptance;<\/li>\n\n\n\n<li>the source and destination must use the <strong>same AWS Region<\/strong>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">AWS&#8217;s Knowledge Center specifically shows the destination receiving a <strong>new <code>AllocationId<\/code><\/strong> after successful transfer.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Important distinction<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Operation<\/th><th>What it means<\/th><\/tr><\/thead><tbody><tr><td><strong>Transfer EIP<\/strong><\/td><td>Changes which AWS account owns the public IPv4 address<\/td><\/tr><tr><td><strong>Associate EIP<\/strong><\/td><td>Connects an EIP to an EC2 instance or ENI<\/td><\/tr><tr><td><strong>NAT Gateway EIP<\/strong><\/td><td>NAT gateway consumes an EIP; NAT gateway itself does not transfer<\/td><\/tr><tr><td><strong>Move EC2<\/strong><\/td><td>Separate migration operation<\/td><\/tr><tr><td><strong>Move NAT Gateway<\/strong><\/td><td>Not supported; recreate it<\/td><\/tr><tr><td><strong>Move VPC<\/strong><\/td><td>Not part of EIP transfer; recreate\/migrate networking independently<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">2. Supported and Unsupported Scenarios<\/h1>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Scenario<\/th><th>Supported?<\/th><th>Notes<\/th><\/tr><\/thead><tbody><tr><td>Same AWS account<\/td><td>N\/A<\/td><td>No ownership transfer needed; just associate\/disassociate<\/td><\/tr><tr><td>Different accounts, same Organization<\/td><td>\u2705<\/td><td>Supported<\/td><\/tr><tr><td>Different accounts, different Organizations<\/td><td>\u2705<\/td><td>Explicitly supported<\/td><\/tr><tr><td>Different Regions<\/td><td>\u274c<\/td><td>Source and destination must use same Region<\/td><\/tr><tr><td>Standard Amazon-provided EC2 EIP<\/td><td>\u2705<\/td><td>Normal supported case<\/td><\/tr><tr><td>BYOIP EIP<\/td><td>\u274c<\/td><td>AWS explicitly excludes BYOIP addresses<\/td><\/tr><tr><td>Amazon-provided contiguous EIP from IPAM pool<\/td><td>\u274c<\/td><td>Use IPAM sharing instead<\/td><\/tr><tr><td>Customer-owned IP \/ Outposts CoIP<\/td><td>\u274c<\/td><td>Cannot use EIP transfer<\/td><\/tr><tr><td>EIP associated with EC2<\/td><td>\u26a0\ufe0f<\/td><td>Transfer can be enabled, but acceptance fails until disassociated<\/td><\/tr><tr><td>EIP associated with ENI<\/td><td>\u26a0\ufe0f<\/td><td>Same restriction<\/td><\/tr><tr><td>Primary EIP on NAT Gateway<\/td><td>\u26a0\ufe0f<\/td><td>Must be freed before transfer completion; normally delete NAT gateway<\/td><\/tr><tr><td>Secondary EIP on NAT Gateway<\/td><td>\u26a0\ufe0f<\/td><td>Can be disassociated using NAT gateway address APIs<\/td><\/tr><tr><td>Reverse DNS\/PTR configured<\/td><td>\u26a0\ufe0f<\/td><td>Transfer can start, but destination cannot accept until PTR is removed<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">AWS documents the same-Region restriction, BYOIP\/IPAM\/CoIP exclusions, tags reset, reverse-DNS restriction, and cross-Organization behavior explicitly.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">3. Requirements and Prerequisites<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Record these before starting:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Source Account ID\nDestination Account ID\nAWS Region\nPublic EIP\nSource Allocation ID\nAssociation ID\nNetwork Interface ID\nInstance ID\nNAT Gateway ID\nSubnet ID\nAvailability Zone\nNetwork Border Group\nRoute tables\nEIP tags\nPTR record\nExternal allowlists\nTerraform resource addresses\/state\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export AWS_REGION=ap-northeast-1\n\nexport SOURCE_PROFILE=evp-staging-old\nexport DEST_PROFILE=evp-staging-new\n\nexport SOURCE_ACCOUNT_ID=111111111111\nexport DEST_ACCOUNT_ID=222222222222\n\nexport EIP=1.2.3.4\nexport SOURCE_ALLOCATION_ID=eipalloc-xxxxxxxxxxxxxxxxx\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">AWS CLI<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use <strong>AWS CLI v2<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AWS&#8217;s EIP-transfer documentation does not state a specific minimum CLI-v2 version. Current CLI v2 contains all required commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>enable-address-transfer\ndisable-address-transfer\naccept-address-transfer\ndescribe-address-transfers\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS CLI v1 entered maintenance mode in August 2026, so new production automation should use CLI v2.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws --version\n\naws ec2 enable-address-transfer help\naws ec2 accept-address-transfer help\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">4. IAM Permissions<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">The exact EC2 IAM actions exist in AWS&#8217;s current Service Authorization Reference.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Core source-account permissions<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>ec2:EnableAddressTransfer\nec2:DisableAddressTransfer\nec2:DescribeAddressTransfers\nec2:DescribeAddresses\nec2:DescribeAddressesAttribute\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Depending on the attachment:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ec2:DisassociateAddress\nec2:ResetAddressAttribute\n\nec2:DescribeInstances\nec2:DescribeNetworkInterfaces\n\nec2:DescribeNatGateways\nec2:DeleteNatGateway\n\nec2:DescribeRouteTables\nec2:DescribeSubnets\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>ec2:DisassociateAddress<\/code> is the documented action for EC2\/ENI EIP disassociation.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Core destination-account permissions<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>ec2:AcceptAddressTransfer\nec2:DescribeAddresses\nec2:DescribeAddressTransfers\nec2:CreateTags\nec2:AssociateAddress\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">NAT migration can additionally require:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ec2:CreateNatGateway\nec2:DescribeNatGateways\nec2:CreateRoute\nec2:ReplaceRoute\nec2:DeleteRoute\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Reverse DNS recreation can require:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ec2:ModifyAddressAttribute\nec2:DescribeAddressesAttribute\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS confirms <code>AcceptAddressTransfer<\/code>, <code>AssociateAddress<\/code>, <code>EnableAddressTransfer<\/code>, <code>DisableAddressTransfer<\/code>, <code>ResetAddressAttribute<\/code>, and the related Describe actions in its authorization reference.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">SCPs and permission boundaries<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">AWS Organizations itself is <strong>not required to perform the transfer<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, an SCP such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"Effect\": \"Deny\",\n  \"Action\": \"ec2:*\",\n  \"Resource\": \"*\"\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">could block the migration even when the IAM role itself has AdministratorAccess.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Permissions boundaries, SCPs, session policies, and IAM policies are evaluated together; an explicit deny wins.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">5. Destination EIP Quota<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Default AWS VPC quota:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Elastic IP addresses per Region = 5\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It is adjustable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The quota code is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>L-0263D0A3\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check destination quota:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws service-quotas get-service-quota \\\n  --service-code ec2 \\\n  --quota-code L-0263D0A3 \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Count destination EIPs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\" \\\n  --query 'length(Addresses)'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If quota is exhausted, acceptance can fail with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AddressLimitExceeded\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS explicitly documents this failure mode.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">6. Pre-Migration Discovery<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Confirm source identity<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected account:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>111111111111\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Do not continue if it differs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Discover the EIP<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For a specific EIP:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --public-ips \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Useful filtered output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --public-ips \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  --query 'Addresses&#91;0].{\n    PublicIp:PublicIp,\n    AllocationId:AllocationId,\n    AssociationId:AssociationId,\n    InstanceId:InstanceId,\n    NetworkInterfaceId:NetworkInterfaceId,\n    PrivateIpAddress:PrivateIpAddress,\n    NetworkBorderGroup:NetworkBorderGroup,\n    PublicIpv4Pool:PublicIpv4Pool,\n    Tags:Tags\n  }'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PublicIpv4Pool = amazon\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">for a conventional Amazon-provided EIP.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">7. Determine Whether EIP Belongs to a NAT Gateway<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-nat-gateways \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  --query \"NatGateways&#91;?NatGatewayAddresses&#91;?PublicIp=='${EIP}']].{\n    NatGatewayId:NatGatewayId,\n    State:State,\n    SubnetId:SubnetId,\n    VpcId:VpcId,\n    Addresses:NatGatewayAddresses\n  }\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you get a NAT gateway ID:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export SOURCE_NAT_GW_ID=nat-xxxxxxxxxxxxxxxxx\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inspect it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-nat-gateways \\\n  --nat-gateway-ids \"$SOURCE_NAT_GW_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Find routes using it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-route-tables \\\n  --filters \"Name=route.nat-gateway-id,Values=$SOURCE_NAT_GW_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">8. Why a NAT Gateway Does Not Transfer<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">An EIP transfer changes ownership of the <strong>IP address only<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The following remain in the source account:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>VPC\nSubnet\nInternet Gateway\nRoute Table\nNAT Gateway\nNAT Gateway ENI\nSecurity configuration\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For a conventional zonal NAT gateway, the primary EIP cannot simply be detached and moved while keeping the gateway alive.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AWS provides <code>DisassociateNatGatewayAddress<\/code> only for <strong>secondary<\/strong> EIPs. AWS explicitly states:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">You cannot disassociate your primary EIP.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Deleting the NAT gateway:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>disassociates the EIP;<\/li>\n\n\n\n<li>does <strong>not<\/strong> release the EIP;<\/li>\n\n\n\n<li>leaves routes pointing to the deleted NAT gateway in <code>blackhole<\/code> state until changed.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This is the crucial behavior for the migration.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">9. Pre-Transfer Evidence \/ Backup<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Create a migration directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p eip-transfer-backup\ncd eip-transfer-backup\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Save identity:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\" \\\n  &gt; source-account.json\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Save EIP:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --public-ips \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  &gt; source-eip.json\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Save tags separately:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --public-ips \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  --query 'Addresses&#91;0].Tags' \\\n  &gt; eip-tags.json\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inspect PTR:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses-attribute \\\n  --allocation-ids \"$SOURCE_ALLOCATION_ID\" \\\n  --attribute domain-name \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  &gt; reverse-dns.json 2&gt;&amp;1 || true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Save NAT gateway:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-nat-gateways \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  &gt; nat-gateways.json\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Save route tables:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-route-tables \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  &gt; route-tables.json\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Save ENIs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-network-interfaces \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  &gt; network-interfaces.json\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Document outside AWS:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MongoDB Atlas IP allowlists\nConfluent Cloud IP allowlists\nPartner\/vendor firewalls\nThird-party SaaS allowlists\nOffice\/on-prem firewalls\nExternal DNS records\nMonitoring dependencies\nWebhook\/firewall restrictions\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Because the <strong>public IP remains identical<\/strong>, existing IP allowlists normally do not need to change, but they absolutely should be tested after cutover.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">10. Reverse DNS \/ PTR Check<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses-attribute \\\n  --allocation-ids \"$SOURCE_ALLOCATION_ID\" \\\n  --attribute domain-name \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"Addresses\": &#91;\n    {\n      \"PublicIp\": \"1.2.3.4\",\n      \"AllocationId\": \"eipalloc-...\",\n      \"PtrRecord\": \"mail.example.com.\"\n    }\n  ]\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If a PTR exists, AWS allows transfer initiation, but destination acceptance fails until the PTR record is removed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Remove it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n\naws ec2 reset-address-attribute \\\n  --allocation-id \"$SOURCE_ALLOCATION_ID\" \\\n  --attribute domain-name \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS documents <code>reset-address-attribute<\/code> for PTR removal.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After the migration, recreate it with the <strong>new destination allocation ID<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 modify-address-attribute \\\n  --allocation-id \"$DEST_ALLOCATION_ID\" \\\n  --domain-name mail.example.com \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">11. AWS Console \u2014 Source Account<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use the source account.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Navigate:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AWS Console\n\u2192 EC2\n\u2192 Network &amp; Security\n\u2192 Elastic IP addresses\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Select EIP\n\u2192 Actions\n\u2192 Enable transfer\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS currently calls the operation <strong>Enable transfer<\/strong>. UI wording can evolve slightly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For multiple EIPs choose:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Single account\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Multiple accounts\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Enter:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Destination AWS Account ID\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>222222222222\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS requires confirmation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>enable\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then choose:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Submit\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The source account should show:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Transfer status = Pending\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS does <strong>not<\/strong> notify the destination account automatically.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">12. AWS CLI \u2014 Source Account<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">First verify identity:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 enable-address-transfer \\\n  --allocation-id \"$SOURCE_ALLOCATION_ID\" \\\n  --transfer-account-id \"$DEST_ACCOUNT_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This exact command\/API is documented by AWS.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"AddressTransfer\": {\n    \"PublicIp\": \"1.2.3.4\",\n    \"AllocationId\": \"eipalloc-source...\",\n    \"TransferAccountId\": \"222222222222\",\n    \"TransferOfferExpirationTimestamp\": \"...\",\n    \"AddressTransferStatus\": \"pending\"\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-address-transfers \\\n  --allocation-ids \"$SOURCE_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Look for:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AddressTransferStatus = pending\nTransferAccountId = destination account\nPublicIp = expected EIP\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">13. Transfer Expiration<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">The authoritative EC2 User Guide and EC2 API Reference state:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Destination has 7 days to accept the transfer.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After seven days, the transfer expires and ownership remains\/returns to the source account. Accepted transfers remain visible to the source for 14 days.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">AWS documentation inconsistency<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The currently generated AWS CLI reference contains a field description saying <strong>&#8220;seven hours&#8221;<\/strong> in some <code>TransferOfferExpirationTimestamp<\/code> output documentation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This conflicts with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>EC2 User Guide;<\/li>\n\n\n\n<li>VPC User Guide;<\/li>\n\n\n\n<li>EC2 <code>DescribeAddressTransfers<\/code> API Reference;<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">which consistently state <strong>seven days<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For operational planning, use the EC2 service documentation value:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>7 days.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Also inspect the actual:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>TransferOfferExpirationTimestamp\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">returned by AWS for your transfer.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">14. Destination Validation Before Acceptance<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm destination identity:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It must show:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Account = 222222222222\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm current Region:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws configure get region \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Still pass the Region explicitly anyway:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>--region ap-northeast-1\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check target VPC:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-vpcs \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check target public subnet:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-subnets \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check Internet Gateway:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-internet-gateways \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check EIP quota before acceptance.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">15. What Happens to the Allocation ID?<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This point is critical.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose source has:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Public IP:      1.2.3.4\nAllocation ID:  eipalloc-OLD111111\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After successful transfer:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Public IP:      1.2.3.4\nAllocation ID:  eipalloc-NEW222222\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS&#8217;s own Knowledge Center explicitly states:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>A successful transfer generates a new AllocationId in the destination owner&#8217;s account.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Therefore:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Public IPv4 = SAME\nAllocation ID = CHANGES\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Do <strong>not<\/strong> configure destination Terraform with the old allocation ID.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do <strong>not<\/strong> assume the <code>AllocationId<\/code> shown in the immediate <code>accept-address-transfer<\/code> response is the destination resource ID.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After acceptance always run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --public-ips \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and obtain the authoritative destination allocation ID.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">16. AWS Console \u2014 Destination Account<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Sign into the destination account.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Navigate:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AWS Console\n\u2192 EC2\n\u2192 Network &amp; Security\n\u2192 Elastic IP addresses\n\u2192 Actions\n\u2192 Accept transfer\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS does not automatically expose a normal &#8220;pending EIP&#8221; resource in the destination EIP inventory beforehand.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, enter the exact public IPv4 address:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1.2.3.4\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then choose:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Submit\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS&#8217;s console workflow explicitly requires entering the transferred EIP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After successful acceptance:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Destination owns EIP\nPublic IP remains identical\nEIP has new Allocation ID\nAddress is initially unassociated\nSource tags are absent\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">17. AWS CLI \u2014 Destination Acceptance<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Before ownership-changing operation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Accept:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 accept-address-transfer \\\n  --address \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The CLI syntax is current and documented.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Immediately discover destination allocation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --public-ips \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Capture it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export DEST_ALLOCATION_ID=\"$(\n  aws ec2 describe-addresses \\\n    --public-ips \"$EIP\" \\\n    --region \"$AWS_REGION\" \\\n    --profile \"$DEST_PROFILE\" \\\n    --query 'Addresses&#91;0].AllocationId' \\\n    --output text\n)\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Print:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"$DEST_ALLOCATION_ID\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --allocation-ids \"$DEST_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\" \\\n  --query 'Addresses&#91;0].{\n    PublicIp:PublicIp,\n    AllocationId:AllocationId,\n    AssociationId:AssociationId,\n    NetworkBorderGroup:NetworkBorderGroup,\n    Tags:Tags\n  }'\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">18. Tags<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">AWS explicitly states:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>EIP tags do not transfer.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">They are reset when ownership transfer completes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before migration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --allocation-ids \"$SOURCE_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  --query 'Addresses&#91;0].Tags' \\\n  &gt; eip-tags.json\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After acceptance:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 create-tags \\\n  --resources \"$DEST_ALLOCATION_ID\" \\\n  --tags file:\/\/eip-tags.json \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --allocation-ids \"$DEST_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\" \\\n  --query 'Addresses&#91;0].Tags'\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">19. EC2 Instance Migration Scenario<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Source:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>EC2-A\n\u2514\u2500\u2500 EIP X\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Destination:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>EC2-B\n\u2514\u2500\u2500 SAME EIP X\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Identify association:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --public-ips \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Capture:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export ASSOCIATION_ID=eipassoc-xxxxxxxx\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Disassociate:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n\naws ec2 disassociate-address \\\n  --association-id \"$ASSOCIATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS requires the EIP to be disassociated before destination acceptance; otherwise acceptance can fail with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>InvalidTransfer.AddressAssociated\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Accept from destination.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 associate-address \\\n  --allocation-id \"$DEST_ALLOCATION_ID\" \\\n  --instance-id i-xxxxxxxxxxxxxxxxx \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">20. ENI Migration Scenario<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Source:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ENI-A\n\u2514\u2500\u2500 EIP X\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Disassociate:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 disassociate-address \\\n  --association-id \"$ASSOCIATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After destination accepts:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 associate-address \\\n  --allocation-id \"$DEST_ALLOCATION_ID\" \\\n  --network-interface-id eni-xxxxxxxxxxxxxxxxx \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If targeting a specific secondary private IP:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 associate-address \\\n  --allocation-id \"$DEST_ALLOCATION_ID\" \\\n  --network-interface-id eni-xxxxxxxxxxxxxxxxx \\\n  --private-ip-address 10.20.1.100 \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">An EIP cannot be associated with an interface whose network border group is incompatible with the EIP.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">21. NAT Gateway Migration \u2014 Recommended Production Strategy<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This is the most important scenario.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Before<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Organization A\n\u2514\u2500\u2500 Source AWS Account\n    \u2514\u2500\u2500 VPC-A\n        \u251c\u2500\u2500 Public Subnet\n        \u2502   \u2514\u2500\u2500 NAT Gateway A\n        \u2502       \u2514\u2500\u2500 EIP X = 1.2.3.4\n        \u2502\n        \u2514\u2500\u2500 Private Subnets\n            \u2514\u2500\u2500 EKS \/ EC2 workloads\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">After<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Organization B\n\u2514\u2500\u2500 Destination AWS Account\n    \u2514\u2500\u2500 VPC-B\n        \u251c\u2500\u2500 Public Subnet\n        \u2502   \u2514\u2500\u2500 NAT Gateway B\n        \u2502       \u2514\u2500\u2500 SAME EIP X = 1.2.3.4\n        \u2502\n        \u2514\u2500\u2500 Private Subnets\n            \u2514\u2500\u2500 EKS \/ EC2 workloads\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Can EIP X move together with NAT Gateway A?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>No.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">NAT Gateway A remains in source account.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Can primary EIP be manually disassociated?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>No.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AWS allows explicit disassociation only for secondary NAT gateway EIPs; primary EIP cannot be removed that way.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What frees the primary EIP?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Delete the source NAT gateway.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n\naws ec2 delete-nat-gateway \\\n  --nat-gateway-id \"$SOURCE_NAT_GW_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS guarantees that deleting the NAT gateway:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>disassociates its EIP\ndoes NOT release the EIP\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is exactly what we need.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Never run<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 release-address ...\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">during this migration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is not part of ownership transfer.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">22. NAT Gateway Minimum-Downtime Sequence<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Phase A \u2014 Days\/hours before maintenance<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Fully prepare destination:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>VPC\nCIDRs\npublic\/private subnets\nInternet Gateway\nroute tables\nNACLs\nEKS\nsecurity\napplications\nTerraform\nvendor testing\nmonitoring\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Optionally create a temporary NAT gateway using a <strong>temporary EIP<\/strong> to validate destination connectivity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This allows destination workloads to be tested before final cutover.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Important limitation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A temporary EIP used as the <strong>primary EIP<\/strong> of a zonal NAT gateway cannot later simply be removed and replaced by the transferred EIP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Therefore if the final NAT must use only the transferred EIP:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>temporary NAT\n\u2192 validate\n\u2192 delete temporary NAT\n\u2192 create final NAT with transferred EIP\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Alternatively, a transferred EIP could be added as a secondary EIP, but the temporary primary remains. That is usually unsuitable when vendors require one deterministic egress IP.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">23. Can Routes Be Prepared?<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Yes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can pre-create:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Route tables\nAssociations\nSubnet mappings\nInternet Gateway\nDestination subnet layout\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">However, the actual route:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>0.0.0.0\/0 \u2192 final NAT Gateway\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">cannot point to a NAT gateway that does not yet exist.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If using a temporary NAT:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Before cutover:\n0.0.0.0\/0 \u2192 temporary NAT\n\nAfter final NAT available:\n0.0.0.0\/0 \u2192 final NAT\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 replace-route \\\n  --route-table-id rtb-xxxxxxxx \\\n  --destination-cidr-block 0.0.0.0\/0 \\\n  --nat-gateway-id \"$DEST_NAT_GW_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">24. Strict NAT Cutover Runbook<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Phase 1 \u2014 Preparation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91; ] Source account\n&#91; ] Destination account\n&#91; ] ap-northeast-1\n&#91; ] EIP\n&#91; ] Allocation ID\n&#91; ] NAT Gateway\n&#91; ] Routes\n&#91; ] tags\n&#91; ] PTR\n&#91; ] external allowlists\n&#91; ] destination quota\n&#91; ] target subnet\n&#91; ] target Internet Gateway\n&#91; ] Terraform\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Phase 2 \u2014 Pre-enable transfer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The source can initiate the transfer handshake before final cutover.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n\naws ec2 enable-address-transfer \\\n  --allocation-id \"$SOURCE_ALLOCATION_ID\" \\\n  --transfer-account-id \"$DEST_ACCOUNT_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-address-transfers \\\n  --allocation-ids \"$SOURCE_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Do <strong>not<\/strong> accept yet.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Phase 3 \u2014 Freeze<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Stop infrastructure changes involving:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>EIP\nNAT\nroute tables\nsubnets\nTerraform\nVPC\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Pause automatic Terraform applies.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Record final rollback point.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Phase 4 \u2014 Reduce Traffic<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Where possible:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>stop jobs\nstop batch traffic\ndrain application traffic\npause heavy outbound connections\nwait for Kafka\/Mongo long-lived connections to reduce\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Existing TCP connections will not survive the NAT replacement.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Phase 5 \u2014 Delete Source NAT<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n\naws ec2 delete-nat-gateway \\\n  --nat-gateway-id \"$SOURCE_NAT_GW_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Monitor:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-nat-gateways \\\n  --nat-gateway-ids \"$SOURCE_NAT_GW_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  --query 'NatGateways&#91;0].State' \\\n  --output text\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify EIP is no longer associated:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --public-ips \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You want no active association.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">25. Accept the Transfer<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Destination identity:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Accept:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 accept-address-transfer \\\n  --address \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Discover new allocation ID:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export DEST_ALLOCATION_ID=\"$(\n  aws ec2 describe-addresses \\\n    --public-ips \"$EIP\" \\\n    --region \"$AWS_REGION\" \\\n    --profile \"$DEST_PROFILE\" \\\n    --query 'Addresses&#91;0].AllocationId' \\\n    --output text\n)\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"Transferred EIP: $EIP\"\necho \"Destination allocation ID: $DEST_ALLOCATION_ID\"\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">26. Create Destination NAT Gateway<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Assume:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export DEST_PUBLIC_SUBNET_ID=subnet-xxxxxxxxxxxxxxxxx\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm destination:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Create:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 create-nat-gateway \\\n  --subnet-id \"$DEST_PUBLIC_SUBNET_ID\" \\\n  --allocation-id \"$DEST_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Capture the returned:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>NatGatewayId\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export DEST_NAT_GW_ID=nat-xxxxxxxxxxxxxxxxx\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Wait until:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>State = available\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-nat-gateways \\\n  --nat-gateway-ids \"$DEST_NAT_GW_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\" \\\n  --query 'NatGateways&#91;0].{\n    State:State,\n    NatGatewayId:NatGatewayId,\n    Addresses:NatGatewayAddresses\n  }'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The EIP network border group must match the NAT gateway&#8217;s AZ\/network border group.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">27. Update Destination Routes<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export DEST_PRIVATE_ROUTE_TABLE_ID=rtb-xxxxxxxxxxxxxxxxx\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Update:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 replace-route \\\n  --route-table-id \"$DEST_PRIVATE_ROUTE_TABLE_ID\" \\\n  --destination-cidr-block 0.0.0.0\/0 \\\n  --nat-gateway-id \"$DEST_NAT_GW_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-route-tables \\\n  --route-table-ids \"$DEST_PRIVATE_ROUTE_TABLE_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>0.0.0.0\/0\n    \u2192\nnew NAT Gateway\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">28. Validation<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">From EC2<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -s https:\/\/checkip.amazonaws.com\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1.2.3.4\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">From EKS<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl run eip-test \\\n  --image=curlimages\/curl \\\n  --rm -it \\\n  --restart=Never \\\n  -- https:\/\/checkip.amazonaws.com\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1.2.3.4\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>kubectl run<\/code> syntax is appropriate for creating a temporary one-shot curl pod.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For non-interactive CI-style validation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl run eip-test \\\n  --image=curlimages\/curl \\\n  --restart=Never \\\n  --command -- \\\n  curl -s https:\/\/checkip.amazonaws.com\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl logs eip-test\nkubectl delete pod eip-test\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">From multiple EKS namespaces<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl run eip-test \\\n  -n YOUR_NAMESPACE \\\n  --image=curlimages\/curl \\\n  --rm -it \\\n  --restart=Never \\\n  -- https:\/\/checkip.amazonaws.com\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">29. Vendor Validation<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Test at minimum:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MongoDB Atlas\nConfluent Cloud\nexternal REST APIs\nvendor allowlists\nwebhooks\ncontainer registries\nGitHub\nAWS APIs\nDatadog\nSentry\nthird-party SaaS endpoints\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Because the outbound IP remains the same, IP-based allowlists should continue to match.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, new TCP\/TLS sessions will be created after NAT replacement.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">30. DNS Behavior<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">A normal Route 53 or external DNS record does <strong>not<\/strong> transfer automatically with an EIP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>api.example.com \u2192 1.2.3.4\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If it already points to <code>1.2.3.4<\/code>, no DNS-value change is required because the public EIP itself remains unchanged.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But the hosted zone and DNS record still belong wherever they were originally managed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This migration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>transfers EIP ownership\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It does not:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>transfer Route 53 hosted zones\ntransfer Route 53 records\ntransfer DNS provider ownership\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">PTR\/reverse DNS is the special case and must be handled separately as described earlier.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">31. Terraform \/ IaC \u2014 Critical Rules<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This deserves careful handling.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose source Terraform contains:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>resource \"aws_eip\" \"nat\" {\n  domain = \"vpc\"\n\n  lifecycle {\n    prevent_destroy = true\n  }\n}\n\nresource \"aws_nat_gateway\" \"this\" {\n  allocation_id = aws_eip.nat.id\n  subnet_id     = aws_subnet.public.id\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Do <strong>not<\/strong> simply delete <code>aws_eip.nat<\/code> from Terraform and run apply blindly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The source state currently represents ownership of the EIP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A safe migration separates:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AWS ownership operations\nTerraform state ownership\nTerraform configuration\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp documents that <code>terraform state rm<\/code> removes the Terraform binding while leaving the remote object intact.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">32. Terraform Recommended Migration Sequence<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">A. Back up state<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform state pull &gt; source-state-before-eip-transfer.json\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">List resources:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform state list\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Identify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws_eip.nat\naws_nat_gateway.this\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Use the real module paths if applicable:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>module.vpc.aws_eip.nat&#91;0]\nmodule.vpc.aws_nat_gateway.this&#91;0]\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">B. Handle source NAT intentionally<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The NAT gateway must actually be deleted as part of the operational migration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <strong>EIP itself must not be released<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If lifecycle contains:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>prevent_destroy = true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">do not casually remove it merely to satisfy Terraform.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Separate NAT deletion from EIP state transition.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">C. After EIP ownership moves<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The source Terraform state must no longer claim ownership of the transferred EIP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform state rm 'aws_eip.nat'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform state rm 'module.vpc.aws_eip.nat&#91;0]'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This removes Terraform&#8217;s binding without attempting to destroy the remote resource.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Remove\/update the corresponding source configuration so a subsequent plan does not attempt to recreate an EIP.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">33. Destination Terraform Import<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Create the destination configuration first:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>resource \"aws_eip\" \"nat\" {\n  domain = \"vpc\"\n\n  tags = {\n    Name = \"evp-staging-nat\"\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then import using the <strong>new destination allocation ID<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform import \\\n  aws_eip.nat \\\n  \"$DEST_ALLOCATION_ID\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Current HashiCorp AWS Provider documentation explicitly imports <code>aws_eip<\/code> resources using their allocation ID.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Modern Terraform can also use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import {\n  to = aws_eip.nat\n  id = \"eipalloc-NEW...\"\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp recommends one remote object be bound to one Terraform resource address.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After import:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform plan\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>no EIP replacement\nno EIP release\nno unexpected allocation\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Investigate any EIP destroy\/replace action before applying.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">34. Destination NAT Terraform<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Then configure:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>resource \"aws_nat_gateway\" \"this\" {\n  allocation_id = aws_eip.nat.id\n  subnet_id     = aws_subnet.public.id\n\n  depends_on = &#91;\n    aws_internet_gateway.this\n  ]\n\n  tags = {\n    Name = \"evp-staging-nat\"\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Current AWS provider documentation warns against trying to attach NAT gateway EIPs through the generic EIP <code>network_interface<\/code> argument; NAT association should be managed by the NAT resource.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">35. Rollback<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Rollback depends on where you are.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Stage A \u2014 Transfer not initiated<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Nothing to reverse.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Stage B \u2014 Transfer pending, destination has not accepted<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Source still controls the transfer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Check identity:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Cancel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 disable-address-transfer \\\n  --allocation-id \"$SOURCE_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">AWS explicitly supports disabling a transfer whose status is pending.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If old NAT still exists, service continues normally.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Stage C \u2014 Old NAT deleted, but EIP not accepted<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Disable transfer:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 disable-address-transfer \\\n  --allocation-id \"$SOURCE_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then recreate source NAT using the EIP:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 create-nat-gateway \\\n  --subnet-id \"$SOURCE_PUBLIC_SUBNET_ID\" \\\n  --allocation-id \"$SOURCE_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Update source routes.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Stage D \u2014 Destination has accepted<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>disable-address-transfer<\/code> can no longer restore source ownership.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The destination now owns the public IP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To return it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Destination account\n\u2192 frees EIP\n\u2192 EnableAddressTransfer back to original account\n\u2192 Original account accepts\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Because AWS supports transfer between any two accounts in the same Region, the process can be reversed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Destination:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 enable-address-transfer \\\n  --allocation-id \"$DEST_ALLOCATION_ID\" \\\n  --transfer-account-id \"$SOURCE_ACCOUNT_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Original source then accepts:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 accept-address-transfer \\\n  --address \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The source will again receive a <strong>new allocation ID<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Stage E \u2014 Destination NAT already created<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Because the EIP is the primary EIP of the destination NAT gateway, first:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>delete destination NAT\nwait for EIP to become free\nreverse-transfer EIP\naccept in source\nobtain new allocation ID\nrecreate source NAT\nrestore source routes\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Rollback therefore causes another interruption.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">36. Downtime Analysis<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">AWS-documented facts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">AWS does not publish an exact duration guarantee for:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AcceptAddressTransfer completion\nNAT gateway deletion\nNAT gateway creation\nroute convergence\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Do not design the runbook around an assumed AWS SLA for these steps.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AWS does document that deleting a NAT gateway disassociates the EIP and leaves routes targeting it in <code>blackhole<\/code> state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AWS also warns in related NAT migrations that changing NAT routing or disassociating the EIP drops existing connections and they must reconnect.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Operational expectation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Typically the following are quick:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>enable transfer\naccept transfer\ndescribe-addresses\nroute-table API update\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">NAT gateway deletion\/creation tends to be the largest component and should be measured during staging rather than assigned an invented production duration.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Existing connections<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>TCP sessions reset\/lost\nKafka connections reconnect\nMongoDB connections reconnect\nHTTPS connections reconnect\nHTTP keepalive connections rebuild\nDNS unaffected if same EIP\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">37. Can This Be Zero Downtime?<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">For the strict requirement:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Source NAT\n\u2192 SAME sole EIP\n\u2192 Destination NAT\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>true zero downtime should not be promised.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is a point where:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>old NAT must stop owning EIP\n\u2193\nEIP ownership changes\n\u2193\nnew NAT is created\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The exact same EIP cannot simultaneously be the active primary EIP of both NAT gateways in two accounts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Therefore classify the design as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Minimum downtime\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">not:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Zero downtime\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Higher-availability alternative<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pre-run destination through:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>temporary EIP\n+\ntemporary NAT\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and temporarily allowlist both:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>OLD\/STABLE EIP\nTEMPORARY EIP\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This allows destination workloads to be validated and activated independently.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At final transfer, switch to the permanent EIP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This can reduce <strong>application migration risk<\/strong>, although the final same-EIP NAT transition still resets active connections.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">38. Security and Governance<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>separate AWS CLI profiles\nexplicit --profile on every command\nexplicit --region on every command\nSTS identity check before every write\nchange ticket\nmaintenance window\nTerraform freeze\nCloudTrail\npeer review\nrollback owner\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Never rely on:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AWS_PROFILE\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">alone for a high-impact migration if commands can easily run against the wrong account.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Explicitly specify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>--profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>--profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">39. CloudTrail Audit<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">CloudTrail records API operations using:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>eventSource = ec2.amazonaws.com\neventName   = requested EC2 API operation\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Important event names should therefore include:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>EnableAddressTransfer\nDisableAddressTransfer\nAcceptAddressTransfer\nDeleteNatGateway\nCreateNatGateway\nDisassociateAddress\nAssociateAddress\nResetAddressAttribute\nModifyAddressAttribute\nCreateTags\nReplaceRoute\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws cloudtrail lookup-events \\\n  --lookup-attributes \\\n    AttributeKey=EventName,AttributeValue=EnableAddressTransfer \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Destination:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws cloudtrail lookup-events \\\n  --lookup-attributes \\\n    AttributeKey=EventName,AttributeValue=AcceptAddressTransfer \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">CloudTrail supports searching recent management events by <code>EventName<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">40. Troubleshooting<\/h1>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Problem<\/th><th>Likely cause<\/th><th>Validation<\/th><th>Fix<\/th><\/tr><\/thead><tbody><tr><td>Transfer action unavailable<\/td><td>IAM\/SCP\/unsupported EIP<\/td><td>Check caller and EIP pool<\/td><td>Correct permissions \/ verify EIP type<\/td><\/tr><tr><td><code>UnauthorizedOperation<\/code><\/td><td>IAM, boundary, SCP<\/td><td>STS + IAM\/SCP review<\/td><td>Grant EC2 transfer action<\/td><\/tr><tr><td>Destination cannot accept<\/td><td>Still associated \/ PTR \/ quota<\/td><td>Inspect EIP, PTR, quota<\/td><td>Remove blocker<\/td><\/tr><tr><td><code>AddressLimitExceeded<\/code><\/td><td>Destination EIP quota reached<\/td><td>Service Quotas<\/td><td>Increase quota\/free EIP<\/td><\/tr><tr><td><code>InvalidTransfer.AddressAssociated<\/code><\/td><td>EIP still attached<\/td><td><code>describe-addresses<\/code><\/td><td>Disassociate\/delete NAT<\/td><\/tr><tr><td><code>InvalidTransfer.AddressCustomPtrSet<\/code><\/td><td>PTR exists<\/td><td><code>describe-addresses-attribute<\/code><\/td><td>Reset PTR<\/td><\/tr><tr><td>Wrong account<\/td><td>Bad profile<\/td><td><code>sts get-caller-identity<\/code><\/td><td>Stop immediately<\/td><\/tr><tr><td>Wrong Region<\/td><td>Source\/dest Region mismatch<\/td><td>explicit Region<\/td><td>Both must use <code>ap-northeast-1<\/code><\/td><\/tr><tr><td>Transfer expired<\/td><td>&gt;7 days<\/td><td><code>describe-address-transfers<\/code><\/td><td>Re-enable transfer<\/td><\/tr><tr><td>NAT EIP will not detach<\/td><td>Primary EIP<\/td><td>NAT address inspection<\/td><td>Delete NAT gateway<\/td><\/tr><tr><td>Terraform wants new EIP<\/td><td>Old state\/config mismatch<\/td><td><code>terraform plan<\/code><\/td><td>State reconcile\/import<\/td><\/tr><tr><td>Terraform wants destroy<\/td><td>Wrong ownership\/config<\/td><td>plan\/state inspection<\/td><td>Stop; reconcile state<\/td><\/tr><tr><td>NAT creation fails<\/td><td>EIP\/subnet\/NBG\/IGW\/quota issue<\/td><td>NAT failure message<\/td><td>Correct target networking<\/td><\/tr><tr><td>Traffic has wrong outbound IP<\/td><td>Route uses wrong NAT<\/td><td>route + <code>curl<\/code><\/td><td>Fix route<\/td><\/tr><tr><td>Vendor blocks traffic<\/td><td>Allowlist\/session issue<\/td><td>vendor logs<\/td><td>Validate allowlist\/connectivity<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">AWS specifically documents the three major transfer-acceptance errors:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AddressLimitExceeded\nInvalidTransfer.AddressCustomPtrSet\nInvalidTransfer.AddressAssociated\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">41. Complete Command Cheat Sheet<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Define:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export AWS_REGION=ap-northeast-1\n\nexport SOURCE_PROFILE=evp-staging-old\nexport DEST_PROFILE=evp-staging-new\n\nexport SOURCE_ACCOUNT_ID=111111111111\nexport DEST_ACCOUNT_ID=222222222222\n\nexport EIP=1.2.3.4\nexport SOURCE_ALLOCATION_ID=eipalloc-OLDXXXXXXXX\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">1. Verify source<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2. Inspect EIP<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --public-ips \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">3. Inspect PTR<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses-attribute \\\n  --allocation-ids \"$SOURCE_ALLOCATION_ID\" \\\n  --attribute domain-name \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">4. Export tags<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --allocation-ids \"$SOURCE_ALLOCATION_ID\" \\\n  --query 'Addresses&#91;0].Tags' \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\" \\\n  &gt; eip-tags.json\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">5. Enable transfer<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n\naws ec2 enable-address-transfer \\\n  --allocation-id \"$SOURCE_ALLOCATION_ID\" \\\n  --transfer-account-id \"$DEST_ACCOUNT_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">6. Verify pending<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-address-transfers \\\n  --allocation-ids \"$SOURCE_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">7. Free source EIP<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">EC2\/ENI:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 disassociate-address \\\n  --association-id \"$ASSOCIATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">NAT primary EIP:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$SOURCE_PROFILE\"\n\naws ec2 delete-nat-gateway \\\n  --nat-gateway-id \"$SOURCE_NAT_GW_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$SOURCE_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">8. Confirm destination<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">9. Accept<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 accept-address-transfer \\\n  --address \"$EIP\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">10. Obtain NEW allocation ID<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>export DEST_ALLOCATION_ID=\"$(\n  aws ec2 describe-addresses \\\n    --public-ips \"$EIP\" \\\n    --query 'Addresses&#91;0].AllocationId' \\\n    --output text \\\n    --region \"$AWS_REGION\" \\\n    --profile \"$DEST_PROFILE\"\n)\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">11. Verify<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 describe-addresses \\\n  --allocation-ids \"$DEST_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">12. Restore tags<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 create-tags \\\n  --resources \"$DEST_ALLOCATION_ID\" \\\n  --tags file:\/\/eip-tags.json \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">13. Create new NAT<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws sts get-caller-identity \\\n  --profile \"$DEST_PROFILE\"\n\naws ec2 create-nat-gateway \\\n  --subnet-id \"$DEST_PUBLIC_SUBNET_ID\" \\\n  --allocation-id \"$DEST_ALLOCATION_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">14. Update route<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>aws ec2 replace-route \\\n  --route-table-id \"$DEST_PRIVATE_ROUTE_TABLE_ID\" \\\n  --destination-cidr-block 0.0.0.0\/0 \\\n  --nat-gateway-id \"$DEST_NAT_GW_ID\" \\\n  --region \"$AWS_REGION\" \\\n  --profile \"$DEST_PROFILE\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">15. Test EKS<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl run eip-test \\\n  --image=curlimages\/curl \\\n  --rm -it \\\n  --restart=Never \\\n  -- https:\/\/checkip.amazonaws.com\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1.2.3.4\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">42. Architecture Diagram<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n\n    subgraph ORGA&#91;\"AWS Organization A\"]\n        subgraph SRCA&#91;\"Source AWS Account\"]\n            VPC1&#91;\"Source VPC\"]\n            SUB1&#91;\"Public Subnet\"]\n            NAT1&#91;\"NAT Gateway A\"]\n            EIP1&#91;\"EIP X&lt;br\/&gt;1.2.3.4&lt;br\/&gt;Old Allocation ID\"]\n\n            VPC1 --&gt; SUB1\n            SUB1 --&gt; NAT1\n            NAT1 --&gt; EIP1\n        end\n    end\n\n    EIP1 --&gt;|\"EIP ownership transfer&lt;br\/&gt;Same Region\"| EIP2\n\n    subgraph ORGB&#91;\"AWS Organization B\"]\n        subgraph DSTA&#91;\"Destination AWS Account\"]\n            VPC2&#91;\"Destination VPC\"]\n            SUB2&#91;\"Public Subnet\"]\n            NAT2&#91;\"NAT Gateway B\"]\n            EIP2&#91;\"SAME EIP X&lt;br\/&gt;1.2.3.4&lt;br\/&gt;NEW Allocation ID\"]\n\n            VPC2 --&gt; SUB2\n            SUB2 --&gt; NAT2\n            NAT2 --&gt; EIP2\n        end\n    end\n\n    VPC1 -. \"DOES NOT TRANSFER\" .-&gt; VPC2\n    NAT1 -. \"DOES NOT TRANSFER\" .-&gt; NAT2\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The transfer boundary is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>TRANSFERRED\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nPublic IPv4 ownership\n\n\nNOT TRANSFERRED\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nVPC\nNAT Gateway\nSubnet\nENI\nEC2\nRoute tables\nDNS\ntags\nassociation\nold allocation ID\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">43. Final Production Checklist<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>PREPARATION\n\n&#91; ] Source account ID confirmed\n&#91; ] Destination account ID confirmed\n&#91; ] AWS Region confirmed as ap-northeast-1\n&#91; ] Public EIP recorded\n&#91; ] Source Allocation ID recorded\n&#91; ] PublicIpv4Pool verified\n&#91; ] Network Border Group verified\n&#91; ] Association ID recorded\n&#91; ] ENI\/EC2 association checked\n&#91; ] NAT Gateway association checked\n&#91; ] NAT primary\/secondary status checked\n&#91; ] Source routes exported\n&#91; ] Tags exported\n&#91; ] PTR\/reverse DNS checked\n&#91; ] MongoDB Atlas allowlists documented\n&#91; ] Confluent allowlists documented\n&#91; ] Vendor allowlists documented\n&#91; ] DNS dependencies documented\n&#91; ] Destination EIP quota validated\n&#91; ] Destination VPC ready\n&#91; ] Destination public subnet ready\n&#91; ] Destination Internet Gateway ready\n&#91; ] Destination route tables ready\n&#91; ] Destination Terraform ready\n&#91; ] Source Terraform state backed up\n&#91; ] Rollback procedure reviewed\n&#91; ] Change window approved\n\n\nTRANSFER\n\n&#91; ] Terraform\/apply freeze active\n&#91; ] Source caller identity checked\n&#91; ] EIP transfer enabled\n&#91; ] Pending transfer verified\n&#91; ] Destination account ID verified in transfer\n&#91; ] Traffic drained where applicable\n&#91; ] PTR removed if applicable\n&#91; ] EC2\/ENI EIP disassociated OR source NAT deleted\n&#91; ] EIP confirmed free\n&#91; ] Destination caller identity checked\n&#91; ] Transfer accepted\n&#91; ] Destination ownership verified\n&#91; ] NEW Allocation ID recorded\n\n\nTARGET\n\n&#91; ] Tags recreated\n&#91; ] Destination NAT created\n&#91; ] NAT state = available\n&#91; ] NAT shows SAME public EIP\n&#91; ] Destination routes updated\n&#91; ] Private subnet route correct\n&#91; ] EKS outbound EIP verified\n&#91; ] EC2 outbound EIP verified\n&#91; ] MongoDB connectivity verified\n&#91; ] Kafka connectivity verified\n&#91; ] External APIs verified\n&#91; ] Vendor allowlists verified\n&#91; ] Application health verified\n&#91; ] Monitoring healthy\n\n\nIAC \/ CLEANUP\n\n&#91; ] Source Terraform no longer manages EIP\n&#91; ] Destination EIP imported using NEW Allocation ID\n&#91; ] terraform plan clean in source\n&#91; ] terraform plan clean in destination\n&#91; ] Temporary NAT\/EIP removed if applicable\n&#91; ] Old route-table entries removed\n&#91; ] Old infrastructure cleanup approved\n&#91; ] CloudTrail evidence captured\n&#91; ] Runbook updated\n&#91; ] Change ticket completed\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">44. Final Decision Table<\/h1>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Question<\/th><th>Answer<\/th><\/tr><\/thead><tbody><tr><td>Cross-account transfer?<\/td><td><strong>YES<\/strong><\/td><\/tr><tr><td>Cross-Organization transfer?<\/td><td><strong>YES<\/strong><\/td><\/tr><tr><td>Same Organization required?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>Same Region required?<\/td><td><strong>YES<\/strong><\/td><\/tr><tr><td>Exact public IPv4 retained?<\/td><td><strong>YES<\/strong><\/td><\/tr><tr><td>Allocation ID retained?<\/td><td><strong>NO \u2014 new allocation ID after transfer<\/strong><\/td><\/tr><tr><td>Tags retained?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>Standard DNS records transferred?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>Existing EIP association transferred?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>EC2 transferred?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>ENI transferred?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>NAT Gateway transferred?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>VPC transferred?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>BYOIP transferable using this mechanism?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>Outposts CoIP transferable?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>PTR may remain during acceptance?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>Transfer expires?<\/td><td><strong>YES \u2014 7 days<\/strong><\/td><\/tr><tr><td>Can pending transfer be cancelled?<\/td><td><strong>YES<\/strong><\/td><\/tr><tr><td>Can completed transfer simply be cancelled?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>Can ownership be transferred back afterward?<\/td><td><strong>YES \u2014 perform another transfer<\/strong><\/td><\/tr><tr><td>Can primary NAT EIP be manually removed?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>Does deleting NAT release the EIP?<\/td><td><strong>NO<\/strong><\/td><\/tr><tr><td>Does deleting NAT disassociate the EIP?<\/td><td><strong>YES<\/strong><\/td><\/tr><tr><td>True zero downtime with same sole NAT EIP?<\/td><td><strong>No practical guarantee; design for minimum downtime<\/strong><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Primary References<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">AWS EC2 \u2014 Elastic IP transfers:<br><a href=\"https:\/\/docs.aws.amazon.com\/AWSEC2\/latest\/UserGuide\/transfer-EIPs-intro-ec2.html?utm_source=chatgpt.com\">AWS: Transfer an Elastic IP address between AWS accounts<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AWS VPC \u2014 NAT gateway lifecycle:<br><a href=\"https:\/\/docs.aws.amazon.com\/vpc\/latest\/userguide\/nat-gateway-working-with.html?utm_source=chatgpt.com\">AWS: Work with NAT gateways<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AWS EC2 \u2014 Reverse DNS:<br><a href=\"https:\/\/docs.aws.amazon.com\/AWSEC2\/latest\/UserGuide\/Using_Elastic_Addressing_Reverse_DNS.html?utm_source=chatgpt.com\">AWS: Reverse DNS for Elastic IP addresses<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AWS IAM \u2014 EC2 actions:<br><a href=\"https:\/\/docs.aws.amazon.com\/service-authorization\/latest\/reference\/list_ec2.html?utm_source=chatgpt.com\">AWS: Actions, resources and condition keys for Amazon EC2<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AWS VPC quotas:<br><a href=\"https:\/\/docs.aws.amazon.com\/vpc\/latest\/userguide\/amazon-vpc-limits.html?utm_source=chatgpt.com\">AWS: Amazon VPC quotas<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AWS Knowledge Center \u2014 transfer verification\/new AllocationId:<br><a href=\"https:\/\/repost.aws\/knowledge-center\/vpc-transfer-elastic-ip-accounts?utm_source=chatgpt.com\">AWS: Transfer an Elastic IP between accounts<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp \u2014 <code>aws_eip<\/code> import\/current provider behavior:<br><a href=\"https:\/\/registry.terraform.io\/providers\/hashicorp\/aws\/latest\/docs\/resources\/eip?utm_source=chatgpt.com\">HashiCorp AWS Provider: aws_eip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Use case: AWS Organization A \/ Account A \u2192 AWS Organization B \/ Account BObjective: Retain the exact same public IPv4 address while changing AWS account ownership&#8230;. <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1162","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1162","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/comments?post=1162"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1162\/revisions"}],"predecessor-version":[{"id":1163,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1162\/revisions\/1163"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/media?parent=1162"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/categories?post=1162"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/tags?post=1162"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}