Lately, I’ve been tasked with ensuring server security compliance with CIS Security Standards for our EC2 instances. This is a major focus for a technology company promoting security compliance in the healthcare industry.
We’ve got a lot of servers running a lot of different things. Obviously, manually updating servers to comply with the standard isn’t really a good use of my time. Automation is the name of the game.
I’m pretty used to writing scripts to automate things. So, I wrote this little script to run on each of the instances in our AWS environment. This is by no means an exhaustive list of security tweaks for all environments and situations. It’s merely the least destructive broad brush I could paint for all of my various servers. I hope you can find this useful too.
#!/usr/bin/env bash # Install the advanced intrustion detection environment and set it up to monitor things apt install aide aide-common libpam-pwquality \ && aideinit \ && cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db \ && update-aide.conf \ && cp /var/lib/aide/aide.conf.autogenerated /etc/aide/aide.conf \ && echo "* 1 * * * root /usr/bin/aide.wrapper --check" > /etc/cron.d/aide-check # disable unneccessary filesystems cat << "EOF" > /etc/modprobe.d/CIS.conf install udf /bin/true install freevxfs /bin/true install jffs2 /bin/true install hfs /bin/true install hfsplus /bin/true install udf /bin/true EOF # disable packet forwarding, log martians, lookout for weird stuff cat << "EOF" > /etc/sysctl.d/999-CIS.conf fs.suid_dumpable=0 kernel.randomize_va_space=2 net.ipv4.ip_forward=0 net.ipv4.conf.all.send_redirects=0 net.ipv4.conf.all.accept_source_route=0 net.ipv4.conf.all.accept_redirects=0 net.ipv4.conf.all.secure_redirects=0 net.ipv4.conf.all.log_martians=1 net.ipv4.conf.all.rp_filter=1 net.ipv6.conf.all.accept_ra=0 net.ipv6.conf.all.forwarding = 0 net.ipv6.conf.all.accept_source_route = 0 net.ipv4.conf.default.send_redirects=0 net.ipv4.conf.default.accept_source_route=0 net.ipv4.conf.default.accept_redirects=0 net.ipv4.conf.default.secure_redirects=0 net.ipv4.conf.default.log_martians=1 net.ipv4.conf.default.rp_filter=1 net.ipv6.conf.default.accept_ra=0 net.ipv6.conf.default.accept_redirects=0 net.ipv6.conf.default.accept_source_route = 0 net.ipv4.icmp_echo_ignore_broadcasts=1 net.ipv4.icmp_ignore_bogus_error_responses=1 net.ipv4.tcp_syncookies=1 net.ipv4.route.flush=1 net.ipv6.route.flush=1 EOF # Secure the ssh daemon cat << "EOF" > /etc/ssh/sshd_config PasswordAuthentication no PermitUserEnvironment no PermitRootLogin no PermitEmptyPasswords no X11Forwarding no LogLevel INFO IgnoreRhosts yes Banner /etc/issue.net ClientAliveInterval 300 ClientAliveCountMax 0 EOF # set defaults for password max/min validity cat << "EOF" > /etc/login.defs PASS_MAX_DAYS 90 PASS_MIN_DAYS 7 PASS_WARN_AGE 7 EOF echo "auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900" > /etc/pam.d/common-auth useradd -D -f 30 # modify users min/max stuff for auth in /etc/shadow while read -r entry; do [ $(echo "${entry}" | awk -F: '{print $2}' | wc -c) -gt 3 ] || continue; _user="$(echo ${entry} | awk -F: '{print $1}')" chage --inactive 30 "${_user}"; chage --maxage 90 "${_user}"; chage --mindays 7 "${_user}"; done < /etc/shadow
Some of the requirements proposed in the standard include things like “Ensure HTTP Server is not enabled” and “Ensure LDAP server is not enabled”. Clearly, turning off our web servers wouldn’t be a prudent move. So, I guess we’re gonna have to fail that standard.
The point is that automating the hardening of servers is a tricky task. Overdoing it will lock you out of systems and put your product offline. On more than one occasion, I locked myself and everyone out of a critical system. Having to detach root drives and remount them in other servers to fix errors isn’t fun.
Too little server security leaves you open to attack from an ephemeral army of hackers waiting to extort bitcoin from you. Being locked out because of my own mistake is tough. Being locked out because of successful hack is much much worse. Like I said – server security is tricky.
The key things to harden here were ssh, password requirements, lockout requirements, removing unneeded filesystems, and ip packet forwarding/redirection. Those efforts seem pretty global.
I’ve setup a GitLab repository to further these efforts. Please feel free to share any concerns or ideas for improvements there.