Description
Ensure that no Amazon EC2 instance is both reachable from the Internet through a public IPv4 address and attached to an IAM instance profile (IAM role). Instances that have no public IP address, or that have no instance profile, are compliant.
Rationale
An instance with a public IP address is directly exposed to attacks from the Internet. If it also has an IAM role, an attacker who exploits the instance, for example through a server-side request forgery flaw that reaches the instance metadata service, can obtain the role's temporary credentials and use them to call AWS APIs and access data. Internet-facing workloads should sit behind a load balancer with no public IP, and instance roles should follow least privilege and use IMDSv2.
Impact
Reduces the risk of IAM role credentials being stolen from Internet-exposed instances
Removing the instance profile stops the application on the instance from calling AWS APIs with that role, which can break the workload
Removing the public IP address stops direct Internet access to the instance; users must connect through a load balancer, VPN, bastion host or AWS Systems Manager Session Manager
Default Value
New instances have no instance profile unless one is selected at launch. Whether an instance gets a public IPv4 address depends on the subnet's auto-assign public IPv4 setting or the launch settings; in a default VPC, the default subnets assign public IPv4 addresses.
Pre-Requisites
IAM permissions: ec2:DescribeInstances, ec2:DescribeIamInstanceProfileAssociations, ec2:DisassociateIamInstanceProfile, ec2:AssociateIamInstanceProfile, ec2:DescribeAddresses, ec2:DisassociateAddress, ec2:ModifyNetworkInterfaceAttribute and iam:PassRole
Confirmation from the application owner whether the instance needs its IAM role, its public IP address, or both, so the right fix can be chosen
Remediation
Test Plan
Console:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the Amazon EC2 console and select Instances.
For each instance, check the Public IPv4 address and the IAM Role shown in the instance details.
Repeat for each region in use.
If an instance has both a public IPv4 address and an IAM role, follow the implementation steps.
CLI:
List the instances that have both a public IPv4 address and an instance profile:
aws ec2 describe-instances --region <REGION> --filters Name=instance-state-name,Values=pending,running,stopping,stopped --query "Reservations[].Instances[?PublicIpAddress!=null && IamInstanceProfile!=null][].[InstanceId,PublicIpAddress,IamInstanceProfile.Arn]" --output table
An instance fails if it is listed by this command. Terminated instances are not evaluated.
Implementation Steps
Console:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the Amazon EC2 console and select Instances.
If the instance does not need its IAM role:
select the instance and choose Actions, then Security, then Modify IAM role,
set IAM role to No IAM Role and choose Update IAM role.
If the instance needs its IAM role, remove its Internet exposure instead:
if an Elastic IP address is attached, select Elastic IPs under Network & Security, select the address and choose Actions, then Disassociate Elastic IP address,
after disassociating an Elastic IP, an instance that was launched with an auto-assigned public IP receives a new public IP address, so check the instance's Public IPv4 address again and remove it if it is not empty,
if the public IPv4 address was assigned automatically, it can be removed in place: open the instance's primary network interface and turn off its auto-assign public IP setting.
Repeat for each affected instance in each region in use.
CLI:
Find the instance profile association ID of the instance:
aws ec2 describe-iam-instance-profile-associations --filters Name=instance-id,Values=<INSTANCE_ID> --region <REGION> --query "IamInstanceProfileAssociations[].[AssociationId,IamInstanceProfile.Arn,State]" --output table
Remove the instance profile from the instance:
aws ec2 disassociate-iam-instance-profile --association-id <ASSOCIATION_ID> --region <REGION>
Alternatively, if the instance needs its role and uses an Elastic IP address, find and remove the Elastic IP association:
aws
ec2 describe-addresses --filters
Name=instance-id,Values=<INSTANCE_ID> --region <REGION>
--query "Addresses[].[PublicIp,AllocationId,AssociationId]"
--output table
aws ec2 disassociate-address --association-id
<EIP_ASSOCIATION_ID> --region <REGION>
After disassociating an Elastic IP, an instance launched with an auto-assigned public IP receives a new public IP address. Check that PublicIpAddress is empty and note the network interface ID:
aws ec2 describe-instances --instance-ids <INSTANCE_ID> --region <REGION> --query "Reservations[].Instances[].[InstanceId,PublicIpAddress,NetworkInterfaces[0].NetworkInterfaceId]" --output table
If the instance still has an auto-assigned public IP address, remove it in place from the network interface:
aws ec2 modify-network-interface-attribute --network-interface-id <NETWORK_INTERFACE_ID> --no-associate-public-ip-address --region <REGION>
Backout Plan
Before making changes, record the instance profile and public IP of the instance:
aws ec2 describe-instances --instance-ids <INSTANCE_ID> --region <REGION> --query "Reservations[].Instances[].[InstanceId,PublicIpAddress,IamInstanceProfile.Arn]" --output table
To roll back:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the Amazon EC2 console and select the instance.
To restore the role, choose Actions, then Security, then Modify IAM role, select the original role and choose Update IAM role.
To restore the Elastic IP, select it under Elastic IPs, choose Actions, then Associate Elastic IP address, and select the instance.
CLI:
aws
ec2 associate-iam-instance-profile --instance-id <INSTANCE_ID>
--iam-instance-profile Name=<INSTANCE_PROFILE_NAME> --region
<REGION>
aws ec2 associate-address --instance-id
<INSTANCE_ID> --allocation-id <ALLOCATION_ID> --region
<REGION>
Note: rolling back exposes the IAM role credentials to Internet-based attacks on the instance again.
Reference
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html
https://aws.amazon.com/blogs/aws/aws-web-application-firewall-waf-for-application-load-balancers/
https://docs.aws.amazon.com/cli/latest/reference/ec2/disassociate-iam-instance-profile.html