Skip to content

Instantly share code, notes, and snippets.

@petergdoyle
Last active September 22, 2017 11:03
Show Gist options
  • Save petergdoyle/b8241ecf2154fa9c1056383dafae8af2 to your computer and use it in GitHub Desktop.
Save petergdoyle/b8241ecf2154fa9c1056383dafae8af2 to your computer and use it in GitHub Desktop.

Secure Azure VMs

Secure the Node VMs

Any VMs have public ip numbers and registered domain names. Therefore these machines are accessible to the internet and vulternable to attack. Using available Azure VM images has its advantages but a verification of security measures is required to ensure that the VMs are not immediately open to intrusion and do not become compromised over time.

Do Not Use Azure public VM Images

Ideally a vm should be created from distro sources and provisioned and uploaded to Azure accordingly. The following outlines the process to build a CentOS 7.x minimal installation and load it to Azure : Prepare a CentOS-based virtual machine for Azure, 05/09/2016. The current Swarm Nodes were built on top of publically available CentOS vm images. These should likely be replaced once the integration of all the moving parts is complete and the setup and provisioning of this configuration is scripted and automated. The current vms are based on "CentOS-based 7.2" by OpenLogic and available on Azure when creating a compute node.

If an image is built from source distro then only the required services and applications need be installed making the image both smaller and easier to manage and control. Public images may have many additional features installed that require additional administrative consideration as well as footprint.

At the very least the following security measures should be taken for any public facing linux system, but especially if you are using one from the open vm registry available on Azure

If you choose to use public vm images from the Azure Marketplace Then Do at least these Things:

  1. Change the root password - the root password could be well known as it is a public image
  2. Obfuscate the root password and allow only administrative users access to root functionality using sudo to prevent root login
  3. Install, configure and enable DenyHosts to prevent brute force SSH Dictionary attacks
  4. Install, configure and enable firwalld daemon
  5. Update all installed packages and run yum.cron so that security patches and fixes are installed regularily as these are released.
  6. Consider other recommended options below

Require SSH RSA Certificates to Connect

In order to force certificate authenitcation to the vms, steps must be performed on both the client machines as well as the servers. For more information check here

Each User Needs to Generate an SSH key-pair on their Client Machine (if one doesn't already exist or existing ones can be destroyed inadvertantly!)

For password-less access to the system(recommended), do not provide a password when prompted and simply hit return.

Peters-MacBook-Pro:~ peter$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/peter/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again
Your identification has been saved in /home/peter/.ssh/id_rsa.
Your public key has been saved in /home/peter/.ssh/id_rsa.pub.
The key fingerprint is:
15:60:97:ac:0f:96:9a:df:0c:32:61:fd:65:fb:77:dc peter@Peters-MacBook-Pro
The key's randomart image is:
+--[ RSA 2048]----+
|        ooo.     |
|       . .o.     |
|       . o.      |
|      o *.  o    |
|     . =S+ o .   |
|      = . o .    |
|       + +   . ..|
|        . o   . E|
|               ..|
+-----------------+

Load the public Part of a Public/Private RSA key to the Server

The public part of the private / public key pair that was just generated needs to be uploaded to the server. This can be added manually by the user or an administrator but there is a utility that makes this easy called ssh-copy-id. Since the key is not copied over yet, you will be prompted for the password for the vm. If all worked well, then you should not be prompted with a subsequent ssh login from that client. If you have issues, it may be related to permissions on the server. Check here to verify permissions.

Peters-MBP:~ peter$ ssh-copy-id root@streamworksnode2.westus.cloudapp.azure.com
/usr/local/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/peter/.ssh/id_rsa.pub"
/usr/local/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed

/usr/local/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
		(if you think this is a mistake, you may want to use -f option)

Peters-MBP:~ peter$ ssh root@streamworksnode2.westus.cloudapp.azure.com
Last login: Thu Nov 24 10:09:41 2016 from c-73-153-102-2.hsd1.co.comcast.net
[root@node02 ~]$

The following commands are run as root

The user that created the vms will have sudo privileges to the host vm.

[petergdoyle@Node0 ~]$ sudo su -
[sudo] password for petergdoyle:
[root@Node0 ~]$

REQUIRED - Install Minimal Additional OS Utilities and Programs - Enable the epel repository and install additional cli tools

[root@Node0 ~] $ yum -y install epel-release && yum -y install git vim htop curl wget tree unzip bash-completion net-tools telnet emacs jq apg denyhosts

IT IS STRONGLY RECOMMENDED THAT YOU CONNECT TO THE VM WITH AT LEAST 1, PREFERRABLY 2 OTHER SHELLS AND SUDO IN AS ROOT TO ALL OF THEM. ANY OF THE FOLLOWING PROCEDURES COULD RESULT IN LOCKING YOU OUT OF THE SYSTEM PERMANENTLY AND THE VM WILL HAVE TO BE DESTROYED WITH THE CLOUD PORTAL AND RECREATED. TEST EACH STEP THOROUGHTLY BEFORE PROCEEDING. IF YOU DO EXPERIENCE UNEXPECTED RESULTS YOU HAVE ACCESS TO THE SYSTEM WITH THE OTHER SHELLS TO FIX THE PROBLEMS - CHANGES TO THE SSH CONFIG AND INTRUSION DETECTION MECHANISMS DO NOT FORCE OFF A CONNECTED USER.

If you do get locked out on one session but have another open, then follow these instructions to allow that use to get back in once Denyhosts has locked them out:

Stop DenyHosts

$ systemctl stop denyhosts.service
  • Remove the IP address from /etc/hosts.deny
  • Edit /var/lib/denyhosts/hosts and remove the lines containing the IP address. Save the file.
  • Edit /var/lib/denyhosts/hosts-restricted and remove the lines containing the IP address. Save the file.
  • Edit /var/lib/denyhosts/hosts-root and remove the lines containing the IP address. Save the file.
  • Edit /var/lib/denyhosts/hosts-valid and remove the lines containing the IP address. Save the file.
  • Edit /var/lib/denyhosts/users-hosts and remove the lines containing the IP address. Save the file.
  • (optional) Consider adding the IP address to /var/lib/denyhosts/allowed-hosts

Start DenyHosts

$ systemctl start denyhosts.service

REQUIRED - Force sudo for root privileged access and actions

Set (Reset) the root password with a strong password

The apg utility can generate strong passwords. A password length of 15 with mixed case characters, special characters and digits is strong. This password should not be saved anywhere preventing direct login with the root users. All root activity then is controlled by a single user or an admin group but prevent direct root login.

One liner - if you choose to NOT keep track of the root password Preferred sinde there is not copy and pasted involved and the password is never seen. This one-liner will generate 6 strong passwords, select one randomly and set it for the root user.

[root@Node0 ~]$ apg -a 1 -m 15 | sed -n $(shuf -i1-6 -n1)p| passwd root --stdin

Step-by-step - if you choose to keep track of the root password - and remember it. Generate strong passwords, run the passwd command for root and copy and paste one in.

[root@Node0 ~]$ apg -a 1 -m 15
1'jE/-8iEeyo{MD
Fv?23.F/nx?W||6
{M'bpW-JzW?G,YD
lbHH8m(CbH`7->]
6FsdzI[FU4e1=Na
{"eIwlfBwnbN,)[
[root@Node0 ~]$ su -
Last login: Mon Oct 17 11:47:32 UTC 2016 on pts/0
[root@Node0 ~] $ passwd
Changing password for user root.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.

Add Primary User to Wheel Group and Run Commands as Root

Rather than run commands directly as root or use sudo commands, it is helpful to use a combination of the two so that you can separate root history from promary user history commands. The primary user on the machine should have sudo nopass rights. The user should therefore be added or created with sudo access. The he can be added to the wheel group to bypass password when running sudo.

root@Node0 ~]$ usermod -aG wheel <username>

Allow Wheel Group NOPASSWD access to run sudo

This is a convenience and possibly weaker security rather than having the user re-enter their password every time they enter a sudo command. Note there is a tab after ALL=(ALL)

root@Node0 ~]$ cp /etc/sudoers /etc/sudoers.bkp
root@Node0 ~]$ echo '%wheel  ALL=(ALL)       NOPASSWD: ALL' >> /etc/sudoers

NOTE: the vm may have to be restarted for group permissions to be applied and allow nopass sudo access.

REQUIRED - Prevent SSH Dictionary Attacks using Denyhosts

  1. install denyhosts (requires epel-release to be installed first)
  2. in order to unlock accounts that are inadvertantly locked out make sure you can allow them back by stopping denyhosts, clearing out the bad entry in /etc/hosts.deny, changing the RESET_ON_SUCCESS in the /etc/denyhosts.conf file and then restarting the service. Gotcha - keep at least two terminals ssh'd into the system, so that in case you get locked out in one, you can continue on the other one (or two as a further safety measure). SSHD / Denyhosts cannot disconnect sessions in progress, even though they will prevent future connections if that connection has been marked for denial.
  3. set RESET_ON_SUCCESS=true if required - suggested way is to comment out RESET_ON_SUCCESS = no then uncomment RESET_ON_SUCCESS = yes. Gotcha - If you have more than one entry the first one is taken
  4. turn on the service
  5. enable the service to start up automatically
  6. check the status of the service
[root@Node0 ~] $ grep RESET_ON_SUCCESS /etc/denyhosts.conf
[root@Node0 ~] $ sed -i "s/#RESET_ON_SUCCESS = yes/RESET_ON_SUCCESS = yes/g" /etc/denyhosts.conf
[root@Node0 ~] $ grep RESET_ON_SUCCESS /etc/denyhosts.conf
[root@Node0 ~] $ systemctl start denyhosts.service && systemctl enable denyhosts.service && systemctl status denyhosts.service
● denyhosts.service - SSH log watcher
   Loaded: loaded (/usr/lib/systemd/system/denyhosts.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2016-10-14 10:54:30 UTC; 2 days ago
 Main PID: 632 (denyhosts.py)
   CGroup: /system.slice/denyhosts.service
           └─632 /usr/bin/python2 /usr/bin/denyhosts.py --foreground --unlock --config=/etc/denyhosts.conf

Oct 14 10:54:30 Node0 systemd[1]: Started SSH log watcher.
Oct 14 10:54:30 Node0 systemd[1]: Starting SSH log watcher...

And within minutes, you can see denyhosts blocking attempts to connect to the vms by reading /var/log/secure and blacklisting ips that are trying to attempt access to the systems by adding them to the /etc/hosts.deny entries.

[root@Node0 ~]$ less /etc/hosts.deny
#
# hosts.deny	This file contains access rules which are used to
#		deny connections to network services that either use
#		the tcp_wrappers library or that have been
#		started through a tcp_wrappers-enabled xinetd.
#
#		The rules in this file can also be set up in
#		/etc/hosts.allow with a 'deny' option instead.
#
#		See 'man 5 hosts_options' and 'man 5 hosts_access'
#		for information on rule syntax.
#		See 'man tcpd' for information on tcp_wrappers
#
# DenyHosts: Thu Oct 13 15:50:40 2016 | sshd: 50.235.31.47
sshd: 50.235.31.47
# DenyHosts: Thu Oct 13 15:50:40 2016 | sshd: 212.83.133.230
sshd: 212.83.133.230
# DenyHosts: Thu Oct 13 19:24:53 2016 | sshd: 82.85.187.101
sshd: 82.85.187.101
...

REQUIRED: Turn on and enable firewalld (install if not installed with yum)

[root@Node0 ~] $ systemctl start firewalld.service && systemctl enable firewalld && systemctl status firewalld.service
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2016-10-14 10:55:32 UTC; 2 days ago
 Main PID: 633 (firewalld)
   CGroup: /system.slice/firewalld.service
           └─633 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid

Oct 16 16:17:03 Node0 systemd[1]: Started firewalld - dynamic firewall daemon.

Check the active FirewalID zone

[root@Node0 ~]$ firewall-cmd --get-default-zone
public

[root@Node0 ~]$ firewall-cmd --get-active-zones
public
  interfaces: eth0

Notice that the interface is eth0, firewallID is configured around the concept of zones and zones bound around interfaces - for moe information on firewallID refer to the link here How do we know what rules are associated with the public zone though? We can print out the default zone's configuration by typing:

[root@Node0 ~] $ firewall-cmd --list-all
public (default, active)
  interfaces: eth0
  sources:
  services: dhcpv6-client ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:

REQUIRED - Update all packages and install yum-cron to keep things up to date

[root@Node0 ~] $ yum -y update && yum -y install yum-cron

See yum-cron details to configure it properly https://community.centminmod.com/threads/automatic-nightly-yum-updates-with-yum-cron.1507/

Additional Measures - Create a Root Certificate and Sign Host Keys

hardening-ssh

Additional Measures - Sign User Keys

hardening-ssh

Additonal Measures - Disable Password-based Authentication

Once the admin user has strengthened the default SSH Security measures outlined previously, and is able to still sign into the system (*see caution about reconfiguring ssh without having at least 1 additional ssh connection, likely 2, so that the admin user doesn not get locked out of the system) then Password-base Authentication can be disable. Follow steps outlined here

Additional Measures - Turn Off IPv6

Internet Protocol version 6 (IPv6) provides a new Internet layer of the TCP/IP protocol suite that replaces Internet Protocol version 4 (IPv4) and provides many benefits. Currently there are no good tools out which are able to check a system over network for IPv6 security issues. Most Linux distro began enabling IPv6 protocol by default. Crackers can send bad traffic via IPv6 as most admins are not monitoring it. Unless network configuration requires it, disable IPv6 or configure Linux IPv6 firewall:

RedHat / Centos Disable IPv6 Networking

More info here

Additional Measures - Disable Root Login for SSH

  1. Log in to the server as root using SSH.
  2. Open the /etc/ssh/sshd_config file in your preferred text editor (nano, vi, etc.).
  3. Change PermitRootLogin yes to PermitRootLogin no
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment