PTG Hardened Images

Hardened RHEL 9
CIS Level 2

A production-ready, CIS Level 2 compliant RHEL 9 base AMI for security teams, MSPs, and compliance-driven organizations on AWS. All hardening is applied at pipeline build time — every instance launches in a verified, known-good state with a Lynis score of 87.

Versionv1.0
Base OSRHEL 9.7
HardeningCIS Level 2
Lynis Score87 / 100
Build ToolEC2 Image Builder

What is included

🔒

CIS Level 2 Hardening

Full ansible-lockdown RHEL9-CIS role applied at build time. Every control verified before AMI snapshot.

🛡️

SELinux Enforcing

Targeted policy, enforcing mode. Verified at launch. Persists across reboots via /etc/selinux/config.

📋

Auditd + Immutable Rules

Full CIS audit ruleset with -e 2 immutable flag. All privileged commands logged.

🔥

Firewalld Active

Default zone set to drop. SSH explicitly allowed. All other inbound blocked by default.

🚫

Fail2ban SSH Jail

5 failed attempts triggers 1-hour IP ban. Watches /var/log/secure automatically.

☁️

AWS Native

SSM Agent active. Cloud-init compatible. No baked-in SSH keys. IAM-ready at launch.

🔍

AIDE + rkhunter

File integrity monitoring and rootkit detection pre-installed and configured.

⚙️

Auto Security Updates

dnf-automatic enabled. Security patches applied daily without manual intervention.

Supported regions

RegionCodeStatus
US East (N. Virginia)us-east-1Available
US West (Oregon)us-west-2Available
Europe (Ireland)eu-west-1Available
Asia Pacific (Singapore)ap-southeast-1Available

Pricing

ModelRateNotes
Hourly$0.10 / hrBilled per hour of instance running time
Monthly$49.00 / moFixed monthly, unlimited instance launches
Free Trial7 daysFull access — cancel before day 7 at no charge
Getting Started

Quick Start

From AWS Marketplace subscription to a verified running instance in under 10 minutes.

Before you begin

You need an active AWS account, an EC2 key pair in your target region, and an IAM user or role with EC2 launch permissions. For SSM access, attach AmazonSSMManagedInstanceCore to your instance role.

Launch steps

1

Subscribe on AWS Marketplace

Find the PTG Hardened RHEL 9 CIS Level 2 listing on AWS Marketplace. Click Continue to Subscribe. Accept the terms. Click Continue to Configuration.

2

Configure and launch

Select your region, software version v1.0, and fulfillment option Launch through EC2. Click Continue to Launch.

3

Choose instance settings

Instance type: t3.medium minimum (2 vCPU, 4 GB RAM). Select your VPC, a public subnet, and your existing key pair.

Instance minimum

Do not use t3.micro or t3.small. The security stack requires at minimum 2 vCPU and 4 GB RAM to function correctly.

4

Security group

Create a security group with inbound SSH (TCP port 22) restricted to your IP address only.

bash
# CLI option — create SG with your current IP only
aws ec2 authorize-security-group-ingress \
  --group-id sg-xxxxxxxxx \
  --protocol tcp --port 22 \
  --cidr $(curl -s ifconfig.me)/32
5

Connect via SSH

Wait 2–3 minutes for both status checks to pass, then connect.

bash
ssh -i /path/to/your-key.pem ec2-user@PUBLIC_IP
6

Verify security controls

bash
# SELinux enforcing
sudo getenforce

# Auditd running
sudo systemctl status auditd | grep Active

# Firewalld running
sudo systemctl status firewalld | grep Active

# Compliance manifest
cat /opt/PTG/compliance/manifest.txt

# Full Lynis scan (3–5 min)
sudo lynis audit system
Getting Started

Requirements

Everything required before launching a PTG Hardened RHEL 9 instance.

Instance requirements

Minimum instance type
t3.medium
2 vCPU, 4 GB RAM
Recommended
t3.large or m5.large
For production workloads
Root volume
10 GB gp3
Do not reduce below 10 GB
Architecture
x86_64
ARM / Graviton not supported in v1.0

Supported instance types

FamilyTypesUse case
General Purposet3.medium, t3.large, t3.xlarge, m5.large, m5.xlargeMost workloads
Compute Optimizedc5.large, c5.xlarge, c5.2xlargeHigh-CPU workloads
Memory Optimizedr5.large, r5.xlargeMemory-intensive applications

Network requirements

  • Outbound internet access on port 443/80 for dnf-automatic security updates
  • Inbound SSH port 22 from your management IP — restrict to your IP, not 0.0.0.0/0 in production
  • For SSM Session Manager: VPC endpoint for SSM or NAT Gateway with outbound 443

IAM requirements

SSM Agent

The SSM Agent is pre-installed and running. To use Session Manager without SSH, attach AmazonSSMManagedInstanceCore to your EC2 instance role. No additional configuration required on the instance.

Security

CIS Level 2 Hardening

All hardening is applied at build time using the ansible-lockdown RHEL9-CIS role. Controls are baked into the AMI, not applied at runtime, so every instance launches in a known verified state.

SSH Configuration

Applied to /etc/ssh/sshd_config at build time.

SettingValuePurpose
PermitRootLoginnoRoot cannot authenticate over SSH
PasswordAuthenticationnoKey-pair only — no password auth
MaxAuthTries33 failed attempts triggers disconnect
AllowTcpForwardingnoPrevent SSH tunneling
X11ForwardingnoNo graphical forwarding
AllowAgentForwardingnoNo agent forwarding
ClientAliveCountMax2Idle session timeout enforcement
MaxSessions2Limit concurrent sessions per connection
LogLevelVERBOSEFull SSH activity logging to syslog
TCPKeepAlivenoUse ClientAlive instead of TCP keepalive
bash — verify SSH settings
sudo grep -E "^(PermitRootLogin|PasswordAuthentication|MaxAuthTries|X11Forwarding)" /etc/ssh/sshd_config

SELinux

SELinux enforcing mode with targeted policy. Configured in /etc/selinux/config — persists across reboots. Cannot be changed without root access and a reboot.

bash — verify SELinux
# Current enforcement mode
getenforce

# Full status
sestatus

# Check policy from config file matches running mode
sestatus | grep "from config file"

Firewalld

Active with default zone drop. All inbound blocked except SSH (port 22). Add application ports after launch.

bash — firewalld management
# View all active rules
sudo firewall-cmd --list-all

# Add a port for your application
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload

# Check default zone
sudo firewall-cmd --get-default-zone

Auditd

Running with full CIS audit ruleset. Immutable flag -e 2 set — rules cannot change without a reboot. Logs to /var/log/audit/audit.log.

bash — verify auditd
# Service status
sudo systemctl status auditd

# Confirm immutable flag (enabled 2 = immutable)
sudo auditctl -s | grep enabled

# View loaded audit rules
sudo auditctl -l | head -30

# Search recent audit events
sudo ausearch -ts recent | head -40

Kernel Sysctl Hardening

CIS and Lynis recommended values applied via /etc/sysctl.d/99-ptg-lynis.conf.

KeyValuePurpose
kernel.randomize_va_space2Full ASLR enabled
net.ipv4.tcp_syncookies1SYN flood protection
net.ipv4.conf.all.rp_filter1Reverse path filtering
net.ipv4.conf.all.send_redirects0No ICMP redirects sent
net.ipv4.conf.all.accept_redirects0No redirect acceptance
kernel.dmesg_restrict1Restrict dmesg to root only
kernel.kptr_restrict2Hide kernel symbol addresses
fs.protected_fifos2FIFO / named pipe protection
fs.protected_regular2Regular file protection in sticky dirs
net.core.bpf_jit_harden2BPF JIT compiler hardening
kernel.sysrq0Magic SysRq disabled
dev.tty.ldisc_autoload0Prevent auto-loading line disciplines
Security

Security Stack

Pre-installed, pre-configured tools active on every instance from first boot.

Fail2ban — Intrusion Prevention

Monitors /var/log/secure for SSH failures. The SSH jail is active and configured out of the box.

SettingValue
jailsshd
logpath/var/log/secure
maxretry5 attempts
bantime3600 seconds (1 hour)
findtime600 seconds (10 min window)
bash — fail2ban management
# View SSH jail status and banned IPs
sudo fail2ban-client status sshd

# Manually unban an IP
sudo fail2ban-client set sshd unbanip IP_ADDRESS

# View fail2ban log
sudo tail -f /var/log/fail2ban.log

AIDE — File Integrity Monitoring

AIDE monitors the filesystem for unauthorized changes. Initialize your baseline database after you finish configuring your application files, then check against it regularly.

bash — AIDE usage
# Initialize baseline (run after full app setup)
sudo aide --init
sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

# Run integrity check against baseline
sudo aide --check

# Update database after intentional changes
sudo aide --update

rkhunter — Rootkit Detection

bash — rkhunter scan
# Update signatures
sudo rkhunter --update

# Run full scan
sudo rkhunter --check --skip-keypress

# View warnings only
sudo grep -i warning /var/log/rkhunter.log

dnf-automatic — Unattended Security Updates

Security patches applied automatically on a daily timer. No manual intervention required.

bash
# Verify timer is active
sudo systemctl status dnf-automatic-install.timer

# View update history
sudo dnf history list | head -20

Compiler Access Restriction

GCC and Make are set to 0750 permissions — root access only. Non-root users cannot compile code, reducing post-exploitation attack surface.

Legal banners

Legal warning banners are set on /etc/issue and /etc/issue.net and displayed on every login. Required by many compliance frameworks including HIPAA, PCI-DSS, and FedRAMP.

Security

Compliance & Scoring

Every PTG image is scored with Lynis before release. The score reflects controls actively applied in the AMI — not theoretical compliance.

Lynis Hardening Score

87
/ 100
Hardening Index — v1.0 / RHEL 9.7
Tests performed: 248
Warnings: 0
Firewall:
Malware scanner:
Intrusion detection:
Run your own scan

Run sudo lynis audit system at any time. After a reboot (auditd immutable rules fully apply) and after initializing the AIDE baseline, your score may increase further.

Known Lynis suggestions — by design

The following suggestions appear in Lynis output and are intentional architectural decisions, not oversights.

IDDescriptionReason not fixed
FILE-6310/home, /tmp, /var not on separate partitionsCannot repartition inside EC2 Image Builder. Attach separate EBS volumes post-launch if required.
SSH-7408SSH port 22 flaggedPort 22 is required for AWS Marketplace AMI compatibility. CIS requires it be restricted, not moved.
LOGG-2154No remote syslog targetCloudWatch Agent handles centralized logging. Lynis does not detect CloudWatch as a remote syslog target.
NAME-4404FQDN missing from /etc/hostsInstance-specific. Set by cloud-init at launch time — not configurable at AMI build time.

CIS benchmark sections applied

  • Section 1 — Filesystem configuration, kernel module blacklisting, /tmp hardening
  • Section 2 — Services — unnecessary services disabled, inetd removed
  • Section 3 — Network configuration — full IPv4 and IPv6 stack hardening
  • Section 4 — Firewall — firewalld enforced with default deny policy
  • Section 5 — SSH server hardening — full key-pair enforcement, all forwarding disabled
  • Section 6 — Logging and auditing — auditd with complete CIS ruleset, immutable flag
  • Section 7 — User accounts — password policies, locked accounts, PAM, sudoers
Operations

Connecting to Your Instance

Two connection methods are supported. SSH password authentication is permanently disabled — key-pair or SSM only.

Method 1 — SSH with key pair

bash
# Connect as ec2-user
ssh -i /path/to/your-key.pem ec2-user@PUBLIC_IP

# Escalate to root
sudo su -

# Or run a single command as root
sudo COMMAND
Key pair required

Password authentication is permanently disabled. A key pair must be selected at instance launch. A lost key pair cannot be recovered — launch a new instance from the AMI.

Method 2 — AWS Systems Manager Session Manager

SSM Agent is pre-installed and running. Attach AmazonSSMManagedInstanceCore to your instance role to connect without opening any inbound ports.

bash — Session Manager
# Start a session (requires AWS CLI v2 + session-manager-plugin)
aws ssm start-session --target INSTANCE_ID

# Verify SSM agent is running
sudo systemctl status amazon-ssm-agent

Default user reference

PropertyValue
Default userec2-user
sudo accessYes — passwordless via /etc/sudoers.d/90-cloud-init-users
Root SSH loginDisabled (PermitRootLogin no)
Password authDisabled (PasswordAuthentication no)
SSH host keysRegenerated fresh on every first boot — not baked in
Operations

Post-Launch Validation

Run these commands after every launch to confirm all security controls are active. Under 5 minutes manually — or use the PTG validation playbook for automated reporting.

Full verification script

bash — paste and run after login
#!/bin/bash
# PTG RHEL 9 — Post-launch verification

echo "=== SELinux ==="
getenforce

echo "=== Auditd ==="
sudo systemctl is-active auditd
sudo auditctl -s | grep enabled

echo "=== Firewalld ==="
sudo systemctl is-active firewalld
sudo firewall-cmd --state

echo "=== Fail2ban ==="
sudo systemctl is-active fail2ban
sudo fail2ban-client status sshd

echo "=== SSH Hardening ==="
sudo grep -E "^(PermitRootLogin|PasswordAuthentication|MaxAuthTries)" /etc/ssh/sshd_config

echo "=== Compliance Manifest ==="
cat /opt/PTG/compliance/manifest.txt

echo "=== Lynis Score ==="
sudo lynis audit system 2>/dev/null | grep "Hardening index"

Expected outputs

CheckExpected output
getenforceEnforcing
systemctl is-active auditdactive
auditctl -s | grep enabledenabled 2
systemctl is-active firewalldactive
firewall-cmd --staterunning
systemctl is-active fail2banactive
PermitRootLoginno
PasswordAuthenticationno
MaxAuthTries3
Lynis Hardening index87 or higher
Automated playbook

The PTG validation Ansible playbook runs all checks automatically and writes a full report to /opt/PTG/compliance/validation_report.txt. Contact support to request access.

Operations

Compliance Manifest

Every instance built from this AMI contains a compliance manifest generated at build time at /opt/PTG/compliance/manifest.txt.

bash — read manifest
cat /opt/PTG/compliance/manifest.txt

Sample manifest

text
------------------------------------------------
PTG HARDENED IMAGE MANIFEST
Build Date: 2026-04-09
OS: RHEL 9 / AlmaLinux 9
Compliance Level: CIS Level 2
SSH Hardening: Enabled
Firewall: firewalld Active
SELinux: Enforcing
Auditd: Enabled
Fail2ban: Active (SSH jail enabled)
Process Accounting: psacct + sysstat Active
Lynis Sysctl Hardening: Applied (99-ptg-lynis.conf)
Firewire: Blacklisted
Core Dumps: Disabled
File Permissions: Hardened
Legal Banners: /etc/issue + /etc/issue.net
Compiler Access: Restricted to root
PTG Standard: Secure at Every Stage
------------------------------------------------
Reference

Changelog

v1.0 — April 2026 Initial Release

  • CIS Level 2 hardening via ansible-lockdown RHEL9-CIS role
  • SELinux enforcing mode — targeted policy
  • auditd with full CIS ruleset and -e 2 immutable flag
  • firewalld active — default zone drop, SSH explicitly allowed
  • fail2ban with SSH jail — 5 retries, 1-hour ban
  • AIDE file integrity monitoring pre-installed and configured
  • rkhunter rootkit detection pre-installed
  • dnf-automatic enabled for unattended daily security updates
  • Lynis sysctl hardening profile — 99-ptg-lynis.conf
  • Firewire blacklisted, core dumps disabled via limits.conf
  • Compiler access restricted to root — gcc and make chmod 750
  • psacct and sysstat process accounting enabled
  • Legal banners on /etc/issue and /etc/issue.net
  • Compliance manifest at /opt/PTG/compliance/manifest.txt
  • No baked-in SSH authorized keys — regenerated on first boot
  • Available in us-east-1, us-west-2, eu-west-1, ap-southeast-1
  • Lynis hardening score: 87 / 100
Reference

Support

PTG provides email support for all AWS Marketplace subscribers. 48-hour response time Monday through Friday, Eastern Time.

Contact

TypeContactResponse time
General supportsupport@powelltechnologygroup.com48 hours Mon–Fri ET
Urgent issuesSubject line: PTG RHEL9 AMI — UrgentBest effort same business day

What support covers

  • Questions about pre-installed security controls and their configuration
  • Guidance on CIS compliance controls applied in this image
  • Assistance verifying hardening settings after launch
  • Explanation of Lynis findings and which are intentional design decisions
  • Help running or interpreting the PTG validation playbook output

What support does not cover

  • Application-level configuration built on top of the base image
  • AWS account, billing, or EC2 service issues — contact AWS Support
  • Modifications that intentionally reduce the hardening level
Refund policy

Refunds available within 7 days of initial subscription for any reason. Contact support with your AWS account ID and subscription date. No refunds for hourly usage already consumed.