Restricts EC2 instance launches to specific instance types, preventing users from launching larger, more expensive instance types.
What this approach does
This approach uses an SCP to deny all EC2 actions except RunInstances, and an IAM policy to allow only specific instance types. This ensures that only approved instance types can be launched, while all other EC2 actions are broadly controlled at the organization level. This method is reliable and avoids the false negatives and unexpected denials that can occur when using ec2:InstanceType conditions in SCPs.
Why this works: SCPs are best for broad, organization-wide controls, while IAM policies are designed for fine-grained, resource-level restrictions. By combining both, you get predictable, testable enforcement.
How to test this approach
To validate this approach:
We expect operations with allowed instance types (t3.micro, t3.small, t3.medium) to succeed, while attempts to launch any other instance types should be denied with an AccessDenied error.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"ec2:InstanceType": [
"t3.micro",
"t3.small",
"t3.medium"
]
}
}
}
]
}# Assume a user/role with the recommended IAM policy attached
# Try to launch an allowed instance type (should succeed)
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t3.micro \
--count 1
# Try to launch a disallowed instance type (should be denied)
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t2.large \
--count 1
Summary: Use SCPs for broad controls, and IAM policies for fine-grained restrictions like EC2 instance type allowlists.
What this SCP does (not recommended)
This Service Control Policy (SCP) attempts to restrict EC2 instance launches to specific instance types, preventing users from launching larger, more expensive instance types. However, using ec2:InstanceType in SCPs is unreliable and may cause unexpected denials, even for allowed types. This approach is not recommended for production use.
The policy only allows t3.micro, t3.small, and t3.medium instances to be launched, blocking any attempts to create larger, potentially more expensive instances.
How to test this SCP (not recommended)
To validate this SCP, try to launch EC2 instances with both allowed and disallowed instance types.
In practice, even allowed instance types may be denied due to the limitations of using ec2:InstanceType in SCPs. This confirms why this approach is not recommended.
Previous SCP pattern for EC2 instance type restriction
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "ec2:*",
"Resource": "*",
"NotAction": "ec2:RunInstances"
}
]
}# Try to launch an EC2 instance with an allowed instance type (this should succeed)
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t3.micro \
--count 1
# Try to launch an EC2 instance with a disallowed instance type (this should be denied)
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t2.large \
--count 1import boto3
# Initialize EC2 client
ec2_client = boto3.client('ec2')
# Try to launch an EC2 instance with an allowed instance type
allowed_type = 't3.micro'
try:
response = ec2_client.run_instances(
ImageId='ami-0c55b159cbfafe1f0', # Update with a valid AMI ID for your region
InstanceType=allowed_type,
MinCount=1,
MaxCount=1
)
instance_id = response['Instances'][0]['InstanceId']
print(f"Successfully launched instance with allowed type {allowed_type}: {instance_id}")
# Terminate the test instance
ec2_client.terminate_instances(InstanceIds=[instance_id])
print(f"Terminated test instance: {instance_id}")
except Exception as e:
print(f"Error launching allowed instance type: {e}")
# Try to launch an EC2 instance with a disallowed instance type (this should be denied)
disallowed_type = 't2.large'
try:
response = ec2_client.run_instances(
ImageId='ami-0c55b159cbfafe1f0', # Update with a valid AMI ID for your region
InstanceType=disallowed_type,
MinCount=1,
MaxCount=1
)
instance_id = response['Instances'][0]['InstanceId']
print(f"WARNING: Successfully launched instance with disallowed type {disallowed_type}: {instance_id}")
# Terminate the test instance if it was created
ec2_client.terminate_instances(InstanceIds=[instance_id])
print(f"Terminated test instance: {instance_id}")
except Exception as e:
print(f"Expected error for disallowed instance type if SCP is working: {e}")