Last updated: 23 October 2026. AWS CLI commands checked against AWS CLI 1.46; Linux settings tested on Ubuntu 24.04 (OpenSSH 9.6, fail2ban 1.0). Adjust user names and paths for Amazon Linux 2023 (default user ec2-user).
Securing a Linux server on AWS has two halves. AWS secures the physical infrastructure; you are responsible for everything you configure on top of it: network access, identities, the operating system, patches and data. This is the shared responsibility model, and most EC2 compromises happen on the customer side: an SSH port open to the world, leaked access keys, or an unpatched web application. This guide covers the controls that matter most, in priority order.
The 10-point checklist
| # | Control | Why |
|---|---|---|
| 1 | No SSH open to 0.0.0.0/0: use Session Manager or EC2 Instance Connect Endpoint | Internet-facing SSH is scanned constantly |
| 2 | IAM roles instead of access keys on the server | Stolen long-lived keys are a top cause of cloud breaches |
| 3 | Require IMDSv2 | Blocks common SSRF-based credential theft |
| 4 | Least-privilege security groups | Only the ports you actually need |
| 5 | Encrypt EBS volumes and snapshots by default | Protects data at rest and in backups |
| 6 | Harden SSH and the OS | Keys only, no root login, minimal services |
| 7 | Automatic security updates | Critical flaws like PHP2Shell are exploited within hours |
| 8 | Turn on CloudTrail, GuardDuty and Inspector | Visibility, threat detection and vulnerability scanning |
| 9 | Centralise logs and alerts | You cannot respond to what you cannot see |
| 10 | Backups you have tested | Recovery from ransomware, mistakes and failed updates |
1. Stop exposing SSH to the internet
The safest SSH port is one that is not open at all. Two AWS options give you shell access without an inbound port 22 from the internet:
- AWS Systems Manager Session Manager: the SSM Agent (pre-installed on Amazon Linux and Ubuntu AMIs) makes an outbound connection to AWS. Attach the managed policy
AmazonSSMManagedInstanceCoreto the instance role, then connect from the console or withaws ssm start-session --target i-xxxxxxxx(requires the Session Manager plugin). Sessions can be logged to CloudWatch or S3. - EC2 Instance Connect Endpoint: lets you SSH to instances in private subnets through an AWS-managed endpoint, controlled by IAM.
If you must keep SSH open, restrict the security group to your office or VPN IP address (/32), never 0.0.0.0/0. Find groups that allow SSH from anywhere:
aws ec2 describe-security-groups \
--filters Name=ip-permission.from-port,Values=22 Name=ip-permission.cidr,Values=0.0.0.0/0 \
--query "SecurityGroups[].GroupId" --output text2. Use IAM roles, not access keys
Never put access keys in ~/.aws/credentials, environment variables or application config on an EC2 instance. Attach an IAM role (instance profile) instead: the AWS SDKs and CLI pick up temporary, automatically rotated credentials from the instance metadata service. Give the role only the permissions the application needs, for example read access to one S3 bucket rather than s3:*. Enable MFA for all human users, and use IAM Identity Center rather than long-lived IAM user keys.
3. Require IMDSv2
The instance metadata service (IMDS) hands out the role’s temporary credentials. Version 1 answers simple GET requests, so a server-side request forgery (SSRF) bug in your web app can leak them. IMDSv2 requires a session token obtained with a PUT request, which blocks most SSRF attacks. Require it on existing instances and make it the default for new ones:
# Find instances that still allow IMDSv1
aws ec2 describe-instances \
--query "Reservations[].Instances[?MetadataOptions.HttpTokens!='required'].InstanceId" --output text
# Require IMDSv2 on one instance
aws ec2 modify-instance-metadata-options --instance-id i-0123456789abcdef0 \
--http-tokens required --http-endpoint enabled
# Make IMDSv2 the default for new instances in this account and region
aws ec2 modify-instance-metadata-defaults --http-tokens required --http-put-response-hop-limit 2A hop limit of 2 lets containers running on the instance reach IMDS; use 1 if you do not run containers. Test older applications first: very old AWS SDK versions only support IMDSv1.
4. Least-privilege security groups
- Allow only the ports the service needs: typically 443 (and 80 for redirects) on a web server, and nothing else from the internet.
- Put databases in private subnets and allow access only from the application’s security group (reference the group ID, not an IP range).
- Put web applications behind an Application Load Balancer, and consider AWS WAF for common web attacks.
- Review rules regularly and remove “temporary” openings.
5. Encrypt storage by default
# Encrypt all new EBS volumes in this region by default
aws ec2 enable-ebs-encryption-by-default
aws ec2 get-ebs-encryption-by-defaultThe setting is per region, so run it in every region you use (for India, usually ap-south-1 Mumbai and ap-south-2 Hyderabad). Existing unencrypted volumes must be migrated by copying an encrypted snapshot. Block public access on S3 buckets and keep snapshots private.
6. Harden SSH and the operating system
Put your SSH settings in a drop-in file so package updates do not overwrite them. Replace ubuntu with your login user (ec2-user on Amazon Linux). Keep your current session open until you have tested a new login.
# /etc/ssh/sshd_config.d/10-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
AllowTcpForwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers ubuntu# Check the syntax and the effective settings, then reload
sudo sshd -t && sudo sshd -T | grep -Ei 'permitrootlogin|passwordauthentication|allowusers'
sudo systemctl reload ssh # Ubuntu/Debian; use "sshd" on Amazon Linux/RHELIf SSH stays reachable, add fail2ban to block repeated failed logins:
sudo apt install -y fail2ban
sudo tee /etc/fail2ban/jail.local >/dev/null <<'EOF'
[sshd]
enabled = true
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
EOF
sudo fail2ban-client -t && sudo systemctl restart fail2ban
sudo fail2ban-client status sshdAlso remove software you do not use, check listening services with sudo ss -tulpn, and keep a host firewall (ufw or firewalld) as a second layer behind the security group.
7. Patch automatically
# Ubuntu/Debian: automatic security updates
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
cat /etc/apt/apt.conf.d/20auto-upgrades # both values should be "1"
# Amazon Linux 2023: check for and apply security updates
sudo dnf check-update --security
sudo dnf upgrade --security -yFor fleets, use Systems Manager Patch Manager with maintenance windows, and restart services after library updates (PHP-FPM, web servers). Recent events show why speed matters: the PHP2Shell flaws were attacked within hours of disclosure.
8. Turn on AWS security services
| Service | What it does |
|---|---|
| AWS CloudTrail | Records API activity in your account. Create a multi-region trail to S3 with log file validation. |
| Amazon GuardDuty | Threat detection from CloudTrail, VPC Flow Logs and DNS logs; optional runtime monitoring on EC2 detects cryptominers and suspicious processes. |
| Amazon Inspector | Continuously scans EC2 instances (via SSM Agent) and container images for known vulnerabilities. |
| AWS Security Hub | Checks your configuration against the CIS AWS Foundations and AWS Foundational Security Best Practices standards and collects findings in one place. |
| AWS Config | Tracks configuration changes and flags non-compliant resources. |
aws guardduty create-detector --enable
aws inspector2 enable --resource-types EC29. Centralise logs and alerts
Ship system and application logs off the instance with the CloudWatch agent (or a SIEM such as Wazuh), so an attacker cannot simply delete them. Enable VPC Flow Logs for network visibility, and create alarms for things that need a human: root account use, IAM policy changes, security group changes, GuardDuty high-severity findings and sustained high CPU (often a sign of cryptomining; see our high CPU troubleshooting guide).
10. Back up, and test the restore
Use AWS Backup or scheduled EBS snapshots with a retention policy. For ransomware resilience, copy backups to a separate account and consider AWS Backup Vault Lock. A backup only counts once you have restored it successfully, so test a restore at least once a quarter.
Frequently asked questions
Is changing the SSH port enough?
No. A non-standard port reduces log noise but scanners find it quickly. Key-only authentication plus restricted access (Session Manager, VPN or an IP allow-list) is what actually protects SSH.
Do I still need a host firewall if I use security groups?
Security groups are your main control. A host firewall is useful defence in depth, for example if a security group is misconfigured or a new service starts listening unexpectedly.
Which benchmark should I follow?
The CIS Benchmarks for your Linux distribution and for AWS Foundations are the most widely used. Hardened CIS images are available in the AWS Marketplace, and Security Hub can check the AWS-level controls automatically.
Want an expert review of your AWS servers? Our Linux server hardening & audit covers EC2, security groups and IAM, and our free Linux server hardening checklist is a good place to start.
