← SCP Explorer

MFA enforcement

Requires MFA for sensitive operations, ensuring that critical actions like stopping EC2 instances are only performed by properly authenticated users.

Policy description

What this SCP does

This Service Control Policy (SCP) requires MFA for sensitive operations, ensuring that critical actions like stopping EC2 instances are only performed by properly authenticated users. This adds an important security layer to administrative actions.

By enforcing multi-factor authentication for stopping and terminating EC2 instances, this policy provides an additional security control that prevents unauthorized or accidental shutdown of compute resources, even if a user's credentials are compromised.

Validation strategy

How to test this SCP works

To validate this SCP, try to stop or terminate EC2 instances with and without MFA.

  • Valid test: Launch a test EC2 instance
  • Invalid test: Attempt to stop the instance without using MFA (should be denied)
  • Valid test: Get temporary credentials using MFA and then attempt to stop the instance (should succeed)

This testing approach confirms that sensitive EC2 operations require multi-factor authentication, providing additional protection against unauthorized actions, even in cases where normal authentication credentials might be compromised.

SCP policy & validation scenarios

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Deny", "Action": [ "ec2:StopInstances", "ec2:TerminateInstances" ], "Resource": "*", "Condition": { "BoolIfExists": { "aws:MultiFactorAuthPresent": false } } } ] }
# Launch a test EC2 instance aws ec2 run-instances \ --image-id ami-0c55b159cbfafe1f0 \ --instance-type t2.micro \ --count 1 # Try to stop the instance without MFA (this should be denied) aws ec2 stop-instances --instance-ids i-1234567890abcdef0 # Try to stop the instance with MFA # Note: You need to get an MFA token and use it in an STS get-session-token call aws sts get-session-token \ --serial-number arn:aws:iam::123456789012:mfa/my-mfa-device \ --token-code 123456 # Then use the returned credentials to call # aws ec2 stop-instances --instance-ids i-1234567890abcdef0
import boto3 import json # Initialize clients ec2_client = boto3.client('ec2') sts_client = boto3.client('sts') # Create test resources try: # Launch a test EC2 instance instance_response = ec2_client.run_instances( ImageId='ami-0c55b159cbfafe1f0', # Update with a valid AMI for your region InstanceType='t2.micro', MinCount=1, MaxCount=1 ) instance_id = instance_response['Instances'][0]['InstanceId'] print(f"Created test instance: {instance_id}") # Try to stop the instance without MFA (should be denied if SCP is working) try: ec2_client.stop_instances(InstanceIds=[instance_id]) print("WARNING: Successfully stopped instance without MFA - SCP is NOT restricting as expected") except Exception as e: print(f"Expected error if SCP is working: {e}") print("\nTo properly test with MFA, you would need to:") print("1. Get an MFA token from a registered MFA device") print("2. Use AWS STS to get temporary credentials with MFA") print("3. Use those credentials to make the API call") print("\nExample code (not directly executable):") print(""" # Get temporary credentials with MFA response = sts_client.get_session_token( SerialNumber='arn:aws:iam::123456789012:mfa/my-mfa-device', TokenCode='123456' # The code from your MFA device ) # Create a new client using the temporary credentials mfa_ec2_client = boto3.client( 'ec2', aws_access_key_id=response['Credentials']['AccessKeyId'], aws_secret_access_key=response['Credentials']['SecretAccessKey'], aws_session_token=response['Credentials']['SessionToken'] ) # Try to stop the instance with MFA (should succeed) mfa_ec2_client.stop_instances(InstanceIds=[instance_id]) """) # Clean up try: ec2_client.terminate_instances(InstanceIds=[instance_id]) print("Note: Cleanup might fail if the SCP is working and also restricts terminate operations") except Exception as e: print(f"Error during cleanup (might be expected if SCP is working): {e}") print(f"You may need to manually terminate instance {instance_id}") except Exception as e: print(f"Error during test setup: {e}")