├── nginx.md ├── linux-kernel-sysctl-hardening.md ├── LICENSE.txt └── README.md /nginx.md: -------------------------------------------------------------------------------- 1 | # Secure nginx 2 | 3 | Global resource: [webdock.io](https://webdock.io/en/docs/how-guides/security-guides/how-to-configure-security-headers-in-nginx-and-apache) 4 | 5 | * [Disable server tokens](https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens) 6 | 7 | ```nginx 8 | server_tokens off; 9 | ``` 10 | 11 | * [Content Security Policy Reference](https://content-security-policy.com/) 12 | 13 | ```nginx 14 | add_header Content-Security-Policy "default-src 'self';" always; 15 | ``` 16 | 17 | * [X-frame-options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options#sameorigin) 18 | 19 | ```nginx 20 | add_header X-Frame-Options SAMEORIGIN always; 21 | ``` 22 | 23 | * [X-Xss-Protection: block](https://docs.nginx.com/nginx-management-suite/acm/how-to/policies/proxy-response-headers/) 24 | 25 | ```nginx 26 | add_header X-Xss-Protection "1; mode=block" always; 27 | ``` 28 | 29 | * [strict origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#strict-origin) 30 | 31 | ```nginx 32 | add_header Referrer-Policy "strict-origin" always; 33 | ``` 34 | 35 | * [Permissions Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy) 36 | 37 | ```nginx 38 | add_header Permissions-Policy "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()"; 39 | ``` 40 | 41 | * [Content sniffing](https://en.wikipedia.org/wiki/Content_sniffing) 42 | 43 | ```nginx 44 | add_header X-Content-Type-Options nosniff always; 45 | ``` 46 | -------------------------------------------------------------------------------- /linux-kernel-sysctl-hardening.md: -------------------------------------------------------------------------------- 1 | # Linux Kernel `sysctl` Hardening 2 | 3 | ## Table of Contents 4 | 5 | - [Overview](#overview) 6 | - [Documentation](#documentation) 7 | - [Disclaimer](#disclaimer) 8 | - [Keys](#keys) 9 | 10 | ## Overview 11 | 12 | This is a combined list of all the `sysctl` hardening recommendations I could find across multiple sites: 13 | 14 | - https://www.cyberciti.biz/faq/linux-kernel-etcsysctl-conf-security-hardening/ 15 | - https://geektnt.com/sysctl-conf-hardening.html 16 | - https://linoxide.com/how-tos/linux-server-protection/ 17 | - https://cloudpro.zone/index.php/2018/01/30/debian-9-3-server-setup-guide-part-5/ 18 | - https://github.com/klaver/sysctl/blob/master/sysctl.conf 19 | 20 | ## Documentation 21 | 22 | Documentation for **most** of these keys can be found at https://github.com/torvalds/linux/blob/master/Documentation. However, the documentation seems to be for the 2.2 kernel. I cannot find any newer documentation. If you know where I can find newer documentation please submit a [new issue](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/new). 23 | 24 | ## Disclaimer 25 | 26 | I do not know what most of these settings do. This list is being provided just as reference material. I take no responsibility for anything. 27 | 28 | ## Keys 29 | 30 | |`key=value`|Note|[Documentation| 31 | |--|--|--| 32 | |`fs.file-max = 65535`||[/sysctl/fs.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/fs.txt)| 33 | |`fs.protected_hardlinks = 1`||[/sysctl/fs.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/fs.txt)| 34 | |`fs.protected_symlinks = 1`||[/sysctl/fs.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/fs.txt)| 35 | |`fs.suid_dumpable = 0`||[/sysctl/fs.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/fs.txt)| 36 | |`kernel.core_uses_pid = 1`||[/sysctl/kernel.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/kernel.txt)| 37 | |`kernel.ctrl-alt-del = 0`||[/sysctl/kernel.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/kernel.txt)| 38 | |`kernel.kptr_restrict = 2`||[/sysctl/kernel.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/kernel.txt)| 39 | |`kernel.maps_protect = 1`||| 40 | |`kernel.msgmax = 65535`||[/sysctl/kernel.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/kernel.txt)| 41 | |`kernel.msgmnb = 65535`||[/sysctl/kernel.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/kernel.txt)| 42 | |`kernel.pid_max = 65535`||[/sysctl/kernel.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/kernel.txt)| 43 | |`kernel.randomize_va_space = 2`||[/sysctl/kernel.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/kernel.txt)| 44 | |`kernel.shmall = 268435456`||[/sysctl/kernel.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/kernel.txt)| 45 | |`kernel.shmmax = 268435456`||[/sysctl/kernel.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/kernel.txt)| 46 | |`kernel.sysrq = 0`||[/sysctl/kernel.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/kernel.txt)| 47 | |`net.core.default_qdisc = fq`||[/sysctl/net.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/net.txt)| 48 | |`net.core.dev_weight = 64`||[/sysctl/net.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/net.txt)| 49 | |`net.core.netdev_max_backlog = 16384`||[/sysctl/net.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/net.txt)| 50 | |`net.core.optmem_max = 65535`||[/sysctl/net.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/net.txt)| 51 | |`net.core.rmem_default = 262144`||[/sysctl/net.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/net.txt)| 52 | |`net.core.rmem_max = 16777216`||[/sysctl/net.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/net.txt)| 53 | |`net.core.somaxconn = 32768`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 54 | |`net.core.wmem_default = 262144`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 55 | |`net.core.wmem_max = 16777216`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 56 | |`net.ipv4.conf.all.accept_redirects = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 57 | |`net.ipv4.conf.all.accept_source_route = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 58 | |`net.ipv4.conf.all.bootp_relay = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 59 | |`net.ipv4.conf.all.forwarding = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 60 | |`net.ipv4.conf.all.log_martians = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 61 | |`net.ipv4.conf.all.proxy_arp = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 62 | |`net.ipv4.conf.all.rp_filter = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 63 | |`net.ipv4.conf.all.secure_redirects = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 64 | |`net.ipv4.conf.all.send_redirects = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 65 | |`net.ipv4.conf.default.accept_redirects = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 66 | |`net.ipv4.conf.default.accept_source_route = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 67 | |`net.ipv4.conf.default.forwarding = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 68 | |`net.ipv4.conf.default.log_martians = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 69 | |`net.ipv4.conf.default.rp_filter = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 70 | |`net.ipv4.conf.default.secure_redirects = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 71 | |`net.ipv4.conf.default.send_redirects = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 72 | |`net.ipv4.conf.eth0.accept_redirects = 0`|change `eth0` to your network interface|[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 73 | |`net.ipv4.conf.eth0.accept_source_route = 0`|change `eth0` to your network interface|[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 74 | |`net.ipv4.conf.eth0.log_martians = 0`|change `eth0` to your network interface|[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 75 | |`net.ipv4.conf.eth0.rp_filter = 1`|change `eth0` to your network interface|[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 76 | |`net.ipv4.conf.lo.accept_redirects = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 77 | |`net.ipv4.conf.lo.accept_source_route = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 78 | |`net.ipv4.conf.lo.log_martians = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 79 | |`net.ipv4.conf.lo.rp_filter = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 80 | |`net.ipv4.icmp_echo_ignore_all = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 81 | |`net.ipv4.icmp_echo_ignore_broadcasts = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 82 | |`net.ipv4.icmp_ignore_bogus_error_responses = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 83 | |`net.ipv4.ip_forward = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 84 | |`net.ipv4.ip_local_port_range = 2000 65000`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 85 | |`net.ipv4.ipfrag_high_thresh = 262144`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 86 | |`net.ipv4.ipfrag_low_thresh = 196608`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 87 | |`net.ipv4.neigh.default.gc_interval = 30`||| 88 | |`net.ipv4.neigh.default.gc_thresh1 = 32`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 89 | |`net.ipv4.neigh.default.gc_thresh2 = 1024`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 90 | |`net.ipv4.neigh.default.gc_thresh3 = 2048`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 91 | |`net.ipv4.neigh.default.proxy_qlen = 96`||| 92 | |`net.ipv4.neigh.default.unres_qlen = 6`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 93 | |`net.ipv4.route.flush = 1`||| 94 | |`net.ipv4.tcp_congestion_control = htcp`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 95 | |`net.ipv4.tcp_ecn = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 96 | |`net.ipv4.tcp_fastopen = 3`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 97 | |`net.ipv4.tcp_fin_timeout = 15`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 98 | |`net.ipv4.tcp_keepalive_intvl = 15`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 99 | |`net.ipv4.tcp_keepalive_probes = 5`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 100 | |`net.ipv4.tcp_keepalive_time = 1800`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 101 | |`net.ipv4.tcp_max_orphans = 16384`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 102 | |`net.ipv4.tcp_max_syn_backlog = 2048`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 103 | |`net.ipv4.tcp_max_tw_buckets = 1440000`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 104 | |`net.ipv4.tcp_moderate_rcvbuf = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 105 | |`net.ipv4.tcp_no_metrics_save = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 106 | |`net.ipv4.tcp_orphan_retries = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 107 | |`net.ipv4.tcp_reordering = 3`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 108 | |`net.ipv4.tcp_retries1 = 3`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 109 | |`net.ipv4.tcp_retries2 = 15`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 110 | |`net.ipv4.tcp_rfc1337 = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 111 | |`net.ipv4.tcp_rmem = 8192 87380 16777216`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 112 | |`net.ipv4.tcp_sack = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 113 | |`net.ipv4.tcp_slow_start_after_idle = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 114 | |`net.ipv4.tcp_syn_retries = 5`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 115 | |`net.ipv4.tcp_synack_retries = 2`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 116 | |`net.ipv4.tcp_syncookies = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 117 | |`net.ipv4.tcp_timestamps = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 118 | |`net.ipv4.tcp_tw_recycle = 0`||| 119 | |`net.ipv4.tcp_tw_reuse = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 120 | |`net.ipv4.tcp_window_scaling = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 121 | |`net.ipv4.tcp_wmem = 8192 65536 16777216`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 122 | |`net.ipv4.udp_rmem_min = 16384`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 123 | |`net.ipv4.udp_wmem_min = 16384`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 124 | |`net.ipv6.conf.all.accept_ra=0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 125 | |`net.ipv6.conf.all.accept_redirects = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 126 | |`net.ipv6.conf.all.accept_source_route = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 127 | |`net.ipv6.conf.all.autoconf = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 128 | |`net.ipv6.conf.all.forwarding = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 129 | |`net.ipv6.conf.default.accept_ra_defrtr = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 130 | |`net.ipv6.conf.default.accept_ra_pinfo = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 131 | |`net.ipv6.conf.default.accept_ra_rtr_pref = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 132 | |`net.ipv6.conf.default.accept_ra=0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 133 | |`net.ipv6.conf.default.accept_redirects = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 134 | |`net.ipv6.conf.default.accept_source_route = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 135 | |`net.ipv6.conf.default.autoconf = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 136 | |`net.ipv6.conf.default.dad_transmits = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 137 | |`net.ipv6.conf.default.forwarding = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 138 | |`net.ipv6.conf.default.max_addresses = 1`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 139 | |`net.ipv6.conf.default.router_solicitations = 0`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 140 | |`net.ipv6.conf.eth0.accept_ra=0`|change `eth0` to your network interface|[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 141 | |`net.ipv6.conf.eth0.autoconf = 0`|change `eth0` to your network interface|[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 142 | |`net.ipv6.ip6frag_high_thresh = 262144`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 143 | |`net.ipv6.ip6frag_low_thresh = 196608`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 144 | |`net.ipv6.route.flush = 1`||| 145 | |`net.unix.max_dgram_qlen = 50`||[/networking/ip-sysctl.txt](https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt)| 146 | |`vm.dirty_background_ratio = 5`||[/sysctl/vm.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/vm.txt)| 147 | |`vm.dirty_ratio = 30`||[/sysctl/vm.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/vm.txt)| 148 | |`vm.min_free_kbytes = 65535`||[/sysctl/vm.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/vm.txt)| 149 | |`vm.mmap_min_addr = 4096`||[/sysctl/vm.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/vm.txt)| 150 | |`vm.overcommit_memory = 0`||[/sysctl/vm.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/vm.txt)| 151 | |`vm.overcommit_ratio = 50`||[/sysctl/vm.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/vm.txt)| 152 | |`vm.swappiness = 30`||[/sysctl/vm.txt](https://github.com/torvalds/linux/blob/master/Documentation/sysctl/vm.txt)| 153 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Attribution-ShareAlike 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-ShareAlike 4.0 International Public 58 | License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-ShareAlike 4.0 International Public License ("Public 63 | License"). To the extent this Public License may be interpreted as a 64 | contract, You are granted the Licensed Rights in consideration of Your 65 | acceptance of these terms and conditions, and the Licensor grants You 66 | such rights in consideration of benefits the Licensor receives from 67 | making the Licensed Material available under these terms and 68 | conditions. 69 | 70 | 71 | Section 1 -- Definitions. 72 | 73 | a. Adapted Material means material subject to Copyright and Similar 74 | Rights that is derived from or based upon the Licensed Material 75 | and in which the Licensed Material is translated, altered, 76 | arranged, transformed, or otherwise modified in a manner requiring 77 | permission under the Copyright and Similar Rights held by the 78 | Licensor. For purposes of this Public License, where the Licensed 79 | Material is a musical work, performance, or sound recording, 80 | Adapted Material is always produced where the Licensed Material is 81 | synched in timed relation with a moving image. 82 | 83 | b. Adapter's License means the license You apply to Your Copyright 84 | and Similar Rights in Your contributions to Adapted Material in 85 | accordance with the terms and conditions of this Public License. 86 | 87 | c. BY-SA Compatible License means a license listed at 88 | creativecommons.org/compatiblelicenses, approved by Creative 89 | Commons as essentially the equivalent of this Public License. 90 | 91 | d. Copyright and Similar Rights means copyright and/or similar rights 92 | closely related to copyright including, without limitation, 93 | performance, broadcast, sound recording, and Sui Generis Database 94 | Rights, without regard to how the rights are labeled or 95 | categorized. For purposes of this Public License, the rights 96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 97 | Rights. 98 | 99 | e. Effective Technological Measures means those measures that, in the 100 | absence of proper authority, may not be circumvented under laws 101 | fulfilling obligations under Article 11 of the WIPO Copyright 102 | Treaty adopted on December 20, 1996, and/or similar international 103 | agreements. 104 | 105 | f. Exceptions and Limitations means fair use, fair dealing, and/or 106 | any other exception or limitation to Copyright and Similar Rights 107 | that applies to Your use of the Licensed Material. 108 | 109 | g. License Elements means the license attributes listed in the name 110 | of a Creative Commons Public License. The License Elements of this 111 | Public License are Attribution and ShareAlike. 112 | 113 | h. Licensed Material means the artistic or literary work, database, 114 | or other material to which the Licensor applied this Public 115 | License. 116 | 117 | i. Licensed Rights means the rights granted to You subject to the 118 | terms and conditions of this Public License, which are limited to 119 | all Copyright and Similar Rights that apply to Your use of the 120 | Licensed Material and that the Licensor has authority to license. 121 | 122 | j. Licensor means the individual(s) or entity(ies) granting rights 123 | under this Public License. 124 | 125 | k. Share means to provide material to the public by any means or 126 | process that requires permission under the Licensed Rights, such 127 | as reproduction, public display, public performance, distribution, 128 | dissemination, communication, or importation, and to make material 129 | available to the public including in ways that members of the 130 | public may access the material from a place and at a time 131 | individually chosen by them. 132 | 133 | l. Sui Generis Database Rights means rights other than copyright 134 | resulting from Directive 96/9/EC of the European Parliament and of 135 | the Council of 11 March 1996 on the legal protection of databases, 136 | as amended and/or succeeded, as well as other essentially 137 | equivalent rights anywhere in the world. 138 | 139 | m. You means the individual or entity exercising the Licensed Rights 140 | under this Public License. Your has a corresponding meaning. 141 | 142 | 143 | Section 2 -- Scope. 144 | 145 | a. License grant. 146 | 147 | 1. Subject to the terms and conditions of this Public License, 148 | the Licensor hereby grants You a worldwide, royalty-free, 149 | non-sublicensable, non-exclusive, irrevocable license to 150 | exercise the Licensed Rights in the Licensed Material to: 151 | 152 | a. reproduce and Share the Licensed Material, in whole or 153 | in part; and 154 | 155 | b. produce, reproduce, and Share Adapted Material. 156 | 157 | 2. Exceptions and Limitations. For the avoidance of doubt, where 158 | Exceptions and Limitations apply to Your use, this Public 159 | License does not apply, and You do not need to comply with 160 | its terms and conditions. 161 | 162 | 3. Term. The term of this Public License is specified in Section 163 | 6(a). 164 | 165 | 4. Media and formats; technical modifications allowed. The 166 | Licensor authorizes You to exercise the Licensed Rights in 167 | all media and formats whether now known or hereafter created, 168 | and to make technical modifications necessary to do so. The 169 | Licensor waives and/or agrees not to assert any right or 170 | authority to forbid You from making technical modifications 171 | necessary to exercise the Licensed Rights, including 172 | technical modifications necessary to circumvent Effective 173 | Technological Measures. For purposes of this Public License, 174 | simply making modifications authorized by this Section 2(a) 175 | (4) never produces Adapted Material. 176 | 177 | 5. Downstream recipients. 178 | 179 | a. Offer from the Licensor -- Licensed Material. Every 180 | recipient of the Licensed Material automatically 181 | receives an offer from the Licensor to exercise the 182 | Licensed Rights under the terms and conditions of this 183 | Public License. 184 | 185 | b. Additional offer from the Licensor -- Adapted Material. 186 | Every recipient of Adapted Material from You 187 | automatically receives an offer from the Licensor to 188 | exercise the Licensed Rights in the Adapted Material 189 | under the conditions of the Adapter's License You apply. 190 | 191 | c. No downstream restrictions. You may not offer or impose 192 | any additional or different terms or conditions on, or 193 | apply any Effective Technological Measures to, the 194 | Licensed Material if doing so restricts exercise of the 195 | Licensed Rights by any recipient of the Licensed 196 | Material. 197 | 198 | 6. No endorsement. Nothing in this Public License constitutes or 199 | may be construed as permission to assert or imply that You 200 | are, or that Your use of the Licensed Material is, connected 201 | with, or sponsored, endorsed, or granted official status by, 202 | the Licensor or others designated to receive attribution as 203 | provided in Section 3(a)(1)(A)(i). 204 | 205 | b. Other rights. 206 | 207 | 1. Moral rights, such as the right of integrity, are not 208 | licensed under this Public License, nor are publicity, 209 | privacy, and/or other similar personality rights; however, to 210 | the extent possible, the Licensor waives and/or agrees not to 211 | assert any such rights held by the Licensor to the limited 212 | extent necessary to allow You to exercise the Licensed 213 | Rights, but not otherwise. 214 | 215 | 2. Patent and trademark rights are not licensed under this 216 | Public License. 217 | 218 | 3. To the extent possible, the Licensor waives any right to 219 | collect royalties from You for the exercise of the Licensed 220 | Rights, whether directly or through a collecting society 221 | under any voluntary or waivable statutory or compulsory 222 | licensing scheme. In all other cases the Licensor expressly 223 | reserves any right to collect such royalties. 224 | 225 | 226 | Section 3 -- License Conditions. 227 | 228 | Your exercise of the Licensed Rights is expressly made subject to the 229 | following conditions. 230 | 231 | a. Attribution. 232 | 233 | 1. If You Share the Licensed Material (including in modified 234 | form), You must: 235 | 236 | a. retain the following if it is supplied by the Licensor 237 | with the Licensed Material: 238 | 239 | i. identification of the creator(s) of the Licensed 240 | Material and any others designated to receive 241 | attribution, in any reasonable manner requested by 242 | the Licensor (including by pseudonym if 243 | designated); 244 | 245 | ii. a copyright notice; 246 | 247 | iii. a notice that refers to this Public License; 248 | 249 | iv. a notice that refers to the disclaimer of 250 | warranties; 251 | 252 | v. a URI or hyperlink to the Licensed Material to the 253 | extent reasonably practicable; 254 | 255 | b. indicate if You modified the Licensed Material and 256 | retain an indication of any previous modifications; and 257 | 258 | c. indicate the Licensed Material is licensed under this 259 | Public License, and include the text of, or the URI or 260 | hyperlink to, this Public License. 261 | 262 | 2. You may satisfy the conditions in Section 3(a)(1) in any 263 | reasonable manner based on the medium, means, and context in 264 | which You Share the Licensed Material. For example, it may be 265 | reasonable to satisfy the conditions by providing a URI or 266 | hyperlink to a resource that includes the required 267 | information. 268 | 269 | 3. If requested by the Licensor, You must remove any of the 270 | information required by Section 3(a)(1)(A) to the extent 271 | reasonably practicable. 272 | 273 | b. ShareAlike. 274 | 275 | In addition to the conditions in Section 3(a), if You Share 276 | Adapted Material You produce, the following conditions also apply. 277 | 278 | 1. The Adapter's License You apply must be a Creative Commons 279 | license with the same License Elements, this version or 280 | later, or a BY-SA Compatible License. 281 | 282 | 2. You must include the text of, or the URI or hyperlink to, the 283 | Adapter's License You apply. You may satisfy this condition 284 | in any reasonable manner based on the medium, means, and 285 | context in which You Share Adapted Material. 286 | 287 | 3. You may not offer or impose any additional or different terms 288 | or conditions on, or apply any Effective Technological 289 | Measures to, Adapted Material that restrict exercise of the 290 | rights granted under the Adapter's License You apply. 291 | 292 | 293 | Section 4 -- Sui Generis Database Rights. 294 | 295 | Where the Licensed Rights include Sui Generis Database Rights that 296 | apply to Your use of the Licensed Material: 297 | 298 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 299 | to extract, reuse, reproduce, and Share all or a substantial 300 | portion of the contents of the database; 301 | 302 | b. if You include all or a substantial portion of the database 303 | contents in a database in which You have Sui Generis Database 304 | Rights, then the database in which You have Sui Generis Database 305 | Rights (but not its individual contents) is Adapted Material, 306 | 307 | including for purposes of Section 3(b); and 308 | c. You must comply with the conditions in Section 3(a) if You Share 309 | all or a substantial portion of the contents of the database. 310 | 311 | For the avoidance of doubt, this Section 4 supplements and does not 312 | replace Your obligations under this Public License where the Licensed 313 | Rights include other Copyright and Similar Rights. 314 | 315 | 316 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 317 | 318 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 319 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 320 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 321 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 322 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 323 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 324 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 325 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 326 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 327 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 328 | 329 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 330 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 331 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 332 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 333 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 334 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 335 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 336 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 337 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 338 | 339 | c. The disclaimer of warranties and limitation of liability provided 340 | above shall be interpreted in a manner that, to the extent 341 | possible, most closely approximates an absolute disclaimer and 342 | waiver of all liability. 343 | 344 | 345 | Section 6 -- Term and Termination. 346 | 347 | a. This Public License applies for the term of the Copyright and 348 | Similar Rights licensed here. However, if You fail to comply with 349 | this Public License, then Your rights under this Public License 350 | terminate automatically. 351 | 352 | b. Where Your right to use the Licensed Material has terminated under 353 | Section 6(a), it reinstates: 354 | 355 | 1. automatically as of the date the violation is cured, provided 356 | it is cured within 30 days of Your discovery of the 357 | violation; or 358 | 359 | 2. upon express reinstatement by the Licensor. 360 | 361 | For the avoidance of doubt, this Section 6(b) does not affect any 362 | right the Licensor may have to seek remedies for Your violations 363 | of this Public License. 364 | 365 | c. For the avoidance of doubt, the Licensor may also offer the 366 | Licensed Material under separate terms or conditions or stop 367 | distributing the Licensed Material at any time; however, doing so 368 | will not terminate this Public License. 369 | 370 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 371 | License. 372 | 373 | 374 | Section 7 -- Other Terms and Conditions. 375 | 376 | a. The Licensor shall not be bound by any additional or different 377 | terms or conditions communicated by You unless expressly agreed. 378 | 379 | b. Any arrangements, understandings, or agreements regarding the 380 | Licensed Material not stated herein are separate from and 381 | independent of the terms and conditions of this Public License. 382 | 383 | 384 | Section 8 -- Interpretation. 385 | 386 | a. For the avoidance of doubt, this Public License does not, and 387 | shall not be interpreted to, reduce, limit, restrict, or impose 388 | conditions on any use of the Licensed Material that could lawfully 389 | be made without permission under this Public License. 390 | 391 | b. To the extent possible, if any provision of this Public License is 392 | deemed unenforceable, it shall be automatically reformed to the 393 | minimum extent necessary to make it enforceable. If the provision 394 | cannot be reformed, it shall be severed from this Public License 395 | without affecting the enforceability of the remaining terms and 396 | conditions. 397 | 398 | c. No term or condition of this Public License will be waived and no 399 | failure to comply consented to unless expressly agreed to by the 400 | Licensor. 401 | 402 | d. Nothing in this Public License constitutes or may be interpreted 403 | as a limitation upon, or waiver of, any privileges and immunities 404 | that apply to the Licensor or You, including from the legal 405 | processes of any jurisdiction or authority. 406 | 407 | 408 | ======================================================================= 409 | 410 | Creative Commons is not a party to its public 411 | licenses. Notwithstanding, Creative Commons may elect to apply one of 412 | its public licenses to material it publishes and in those instances 413 | will be considered the “Licensor.” The text of the Creative Commons 414 | public licenses is dedicated to the public domain under the CC0 Public 415 | Domain Dedication. Except for the limited purpose of indicating that 416 | material is shared under a Creative Commons public license or as 417 | otherwise permitted by the Creative Commons policies published at 418 | creativecommons.org/policies, Creative Commons does not authorize the 419 | use of the trademark "Creative Commons" or any other trademark or logo 420 | of Creative Commons without its prior written consent including, 421 | without limitation, in connection with any unauthorized modifications 422 | to any of its public licenses or any other arrangements, 423 | understandings, or agreements concerning use of licensed material. For 424 | the avoidance of doubt, this paragraph does not form part of the 425 | public licenses. 426 | 427 | Creative Commons may be contacted at creativecommons.org. 428 | 429 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How To Secure A Linux Server 2 | 3 | An evolving how-to guide for securing a Linux server that, hopefully, also teaches you a little about security and why it matters. 4 | 5 | [![CC-BY-SA](https://i.creativecommons.org/l/by-sa/4.0/88x31.png)](#license) 6 | 7 | ## Table of Contents 8 | 9 | - [Introduction](#introduction) 10 | - [Guide Objective](#guide-objective) 11 | - [Why Secure Your Server](#why-secure-your-server) 12 | - [Why Yet Another Guide](#why-yet-another-guide) 13 | - [Other Guides](#other-guides) 14 | - [To Do / To Add](#to-do--to-add) 15 | - [Guide Overview](#guide-overview) 16 | - [About This Guide](#about-this-guide) 17 | - [My Use-Case](#my-use-case) 18 | - [Editing Configuration Files - For The Lazy](#editing-configuration-files---for-the-lazy) 19 | - [Contributing](#contributing) 20 | - [Before You Start](#before-you-start) 21 | - [Identify Your Principles](#identify-your-principles) 22 | - [Picking A Linux Distribution](#picking-a-linux-distribution) 23 | - [Installing Linux](#installing-linux) 24 | - [Pre/Post Installation Requirements](#prepost-installation-requirements) 25 | - [Other Important Notes](#other-important-notes) 26 | - [Using Ansible Playbooks to secure your Linux Server](#using-ansible-playbooks-to-secure-your-linux-server) 27 | - [The SSH Server](#the-ssh-server) 28 | - [Important Note Before You Make SSH Changes](#important-note-before-you-make-ssh-changes) 29 | - [SSH Public/Private Keys](#ssh-publicprivate-keys) 30 | - [Create SSH Group For AllowGroups](#create-ssh-group-for-allowgroups) 31 | - [Secure `/etc/ssh/sshd_config`](#secure-etcsshsshd_config) 32 | - [Remove Short Diffie-Hellman Keys](#remove-short-diffie-hellman-keys) 33 | - [2FA/MFA for SSH](#2famfa-for-ssh) 34 | - [The Basics](#the-basics) 35 | - [Limit Who Can Use sudo](#limit-who-can-use-sudo) 36 | - [Limit Who Can Use su](#limit-who-can-use-su) 37 | - [Run applications in a sandbox with FireJail](#run-applications-in-a-sandbox-with-firejail) 38 | - [NTP Client](#ntp-client) 39 | - [Securing /proc](#securing-proc) 40 | - [Force Accounts To Use Secure Passwords](#force-accounts-to-use-secure-passwords) 41 | - [Automatic Security Updates and Alerts](#automatic-security-updates-and-alerts) 42 | - [More Secure Random Entropy Pool (WIP)](#more-secure-random-entropy-pool-wip) 43 | - [Add Panic/Secondary/Fake password Login Security System](#add-panic-secondary-fake-password-login-security-system) 44 | - [The Network](#the-network) 45 | - [Firewall With UFW (Uncomplicated Firewall)](#firewall-with-ufw-uncomplicated-firewall) 46 | - [iptables Intrusion Detection And Prevention with PSAD](#iptables-intrusion-detection-and-prevention-with-psad) 47 | - [Application Intrusion Detection And Prevention With Fail2Ban](#application-intrusion-detection-and-prevention-with-fail2ban) 48 | - [Application Intrusion Detection And Prevention With CrowdSec](#application-intrusion-detection-and-prevention-with-crowdsec) 49 | - [The Auditing](#the-auditing) 50 | - [File/Folder Integrity Monitoring With AIDE (WIP)](#filefolder-integrity-monitoring-with-aide-wip) 51 | - [Anti-Virus Scanning With ClamAV (WIP)](#anti-virus-scanning-with-clamav-wip) 52 | - [Rootkit Detection With Rkhunter (WIP)](#rootkit-detection-with-rkhunter-wip) 53 | - [Rootkit Detection With chrootkit (WIP)](#rootkit-detection-with-chrootkit-wip) 54 | - [logwatch - system log analyzer and reporter](#logwatch---system-log-analyzer-and-reporter) 55 | - [ss - Seeing Ports Your Server Is Listening On](#ss---seeing-ports-your-server-is-listening-on) 56 | - [Lynis - Linux Security Auditing](#lynis---linux-security-auditing) 57 | - [OSSEC - Host Intrusion Detection](#ossec---host-intrusion-detection) 58 | - [The Danger Zone](#the-danger-zone) 59 | - [The Miscellaneous](#the-miscellaneous) 60 | - [MSMTP (Simple Sendmail) with Google](#msmtp-alternative) 61 | - [Gmail and Exim4 As MTA With Implicit TLS](#gmail-and-exim4-as-mta-with-implicit-tls) 62 | - [Separate iptables Log File](#separate-iptables-log-file) 63 | - [Left Over](#left-over) 64 | - [Contacting Me](#contacting-me) 65 | - [Helpful Links](#helpful-links) 66 | - [Acknowledgments](#acknowledgments) 67 | - [License and Copyright](#license-and-copyright) 68 | 69 | (TOC made with [nGitHubTOC](https://imthenachoman.github.io/nGitHubTOC/)) 70 | 71 | ## Introduction 72 | 73 | ### Guide Objective 74 | 75 | This guides purpose is to teach you how to secure a Linux server. 76 | 77 | There are a lot of things you can do to secure a Linux server and this guide will attempt to cover as many of them as possible. More topics/material will be added as I learn, or as folks [contribute](#contributing). 78 | 79 | Ansible playbooks of this guide are available at [How To Secure A Linux Server With Ansible](https://github.com/moltenbit/How-To-Secure-A-Linux-Server-With-Ansible) by [moltenbit](https://github.com/moltenbit). 80 | 81 | ([Table of Contents](#table-of-contents)) 82 | 83 | ### Why Secure Your Server 84 | 85 | I assume you're using this guide because you, hopefully, already understand why good security is important. That is a heavy topic onto itself and breaking it down is out-of-scope for this guide. If you don't know the answer to that question, I advise you research it first. 86 | 87 | At a high level, the second a device, like a server, is in the public domain -- i.e. visible to the outside world -- it becomes a target for bad-actors. An unsecured device is a playground for bad-actors who want access to your data, or to use your server as another node for their large-scale DDOS attacks. 88 | 89 | What's worse is, without good security, you may never know if your server has been compromised. A bad-actor may have gained unauthorized access to your server and copied your data without changing anything, so you'd never know. Or your server may have been part of a DDOS attack, and you wouldn't know. Look at many of the large scale data breaches in the news -- the companies often did not discover the data leak or intrusion until long after the bad-actors were gone. 90 | 91 | Contrary to popular belief, bad-actors don't always want to change something or [lock you out of your data for money](https://en.wikipedia.org/wiki/Ransomware). Sometimes they just want the data on your server for their data warehouses (there is big money in big data) or to covertly use your server for their nefarious purposes. 92 | 93 | ([Table of Contents](#table-of-contents)) 94 | 95 | ### Why Yet Another Guide 96 | 97 | This guide may appear duplicative/unnecessary because there are countless articles online that tell you [how to secure Linux](https://duckduckgo.com/?q=how+to+secure+linux&t=ffab&atb=v151-7&ia=web), but the information is spread across different articles, that cover different things, and in different ways. Who has time to scour through hundreds of articles? 98 | 99 | As I was going through research for my Debian build, I kept notes. At the end I realized that, along with what I already knew, and what I was learning, I had the makings of a how-to guide. I figured I'd put it online to hopefully help others **learn**, and **save time**. 100 | 101 | I've never found one guide that covers everything -- this guide is my attempt. 102 | 103 | Many of the things covered in this guide may be rather basic/trivial, but most of us do not install Linux every day, and it is easy to forget those basic things. 104 | 105 | ([Table of Contents](#table-of-contents)) 106 | 107 | ### Other Guides 108 | 109 | There are many guides provided by experts, industry leaders, and the distributions themselves. It is not practical, and sometimes against copyright, to include everything from those guides. I recommend you check them out before starting with this guide. 110 | 111 | - The [Center for Internet Security (CIS)](https://www.cisecurity.org/) provides [benchmarks](https://www.cisecurity.org/cis-benchmarks/) that are exhaustive, industry trusted, step-by-step instructions for securing many flavors of Linux. Check their [About Us](https://www.cisecurity.org/about-us/) page for details. My recommendation is to go through this guide (the one you're reading here) first and THEN CIS's guide. That way their recommendations will trump anything in this guide. 112 | - For distribution specific hardening/security guides, check your distributions documentation. 113 | - https://security.utexas.edu/os-hardening-checklist/linux-7 - Red Hat Enterprise Linux 7 Hardening Checklist 114 | - https://cloudpro.zone/index.php/2018/01/18/debian-9-3-server-setup-guide-part-1/ - # Debian 9.3 server setup guide 115 | - https://blog.vigilcode.com/2011/04/ubuntu-server-initial-security-quick-secure-setup-part-i/ - Ubuntu Server Initial Security guide 116 | - https://www.tldp.org/LDP/sag/html/index.html 117 | - https://seifried.org/lasg/ 118 | - https://news.ycombinator.com/item?id=19178964 119 | - https://wiki.archlinux.org/index.php/Security - many folks have also recommended this one 120 | - https://securecompliance.co/linux-server-hardening-checklist/ 121 | 122 | ([Table of Contents](#table-of-contents)) 123 | 124 | ### To Do / To Add 125 | 126 | - [ ] [Custom Jails for Fail2ban](#custom-jails) 127 | - [ ] MAC (Mandatory Access Control) and Linux Security Modules (LSMs) 128 | - https://wiki.archlinux.org/index.php/security#Mandatory_access_control 129 | - Security-Enhanced Linux / SELinux 130 | - https://en.wikipedia.org/wiki/Security-Enhanced_Linux 131 | - https://linuxtechlab.com/beginners-guide-to-selinux/ 132 | - https://linuxtechlab.com/replicate-selinux-policies-among-linux-machines/ 133 | - https://teamignition.us/how-to-stop-being-a-scrub-and-learn-to-use-selinux.html 134 | - AppArmor 135 | - https://wiki.archlinux.org/index.php/AppArmor 136 | - https://security.stackexchange.com/questions/29378/comparison-between-apparmor-and-selinux 137 | - http://www.insanitybit.com/2012/06/01/why-i-like-apparmor-more-than-selinux-5/ 138 | - [ ] disk encryption 139 | - [ ] Rkhunter and chrootkit 140 | - http://www.chkrootkit.org/ 141 | - http://rkhunter.sourceforge.net/ 142 | - https://www.cyberciti.biz/faq/howto-check-linux-rootkist-with-detectors-software/ 143 | - https://www.tecmint.com/install-rootkit-hunter-scan-for-rootkits-backdoors-in-linux/ 144 | - [ ] shipping/backing up logs - https://news.ycombinator.com/item?id=19178681 145 | - [ ] CIS-CAT - https://learn.cisecurity.org/cis-cat-landing-page 146 | - [ ] debsums - https://blog.sleeplessbeastie.eu/2015/03/02/how-to-verify-installed-packages/ 147 | 148 | ([Table of Contents](#table-of-contents)) 149 | 150 | ## Guide Overview 151 | 152 | ### About This Guide 153 | 154 | This guide... 155 | 156 | - ...**is** a work in progress. 157 | - ...**is** focused on **at-home** Linux servers. All of the concepts/recommendations here apply to larger/professional environments but those use-cases call for more advanced and specialized configurations that are out-of-scope for this guide. 158 | - ...**does not** teach you about Linux, how to [install Linux](#installing-linux), or how to use it. Check https://linuxjourney.com/ if you're new to Linux. 159 | - ...**is** meant to be [Linux distribution agnostic](#picking-a-linux-distribution). 160 | - ...**does not** teach you everything you need to know about security nor does it get into all aspects of system/server security. For example, physical security is out of scope for this guide. 161 | - ...**does not** talk about how programs/tools work, nor does it delve into their nook and crannies. Most of the programs/tools this guide references are very powerful and highly configurable. The goal is to cover the bare necessities -- enough to whet your appetite and make you hungry enough to want to go and learn more. 162 | - ...**aims** to make it easy by providing code you can copy-and-paste. You might need to modify the commands before you paste so keep your favorite [text editor](https://notepad-plus-plus.org/) handy. 163 | - ...**is** organized in an order that makes logical sense to me -- i.e. securing SSH before installing a firewall. As such, this guide is intended to be followed in the order it is presented, but it is not necessary to do so. Just be careful if you do things in a different order -- some sections require previous sections to be completed. 164 | 165 | ([Table of Contents](#table-of-contents)) 166 | 167 | ### My Use-Case 168 | 169 | There are many types of servers and different use-cases. While I want this guide to be as generic as possible, there will be some things that may not apply to all/other use-cases. Use your best judgement when going through this guide. 170 | 171 | To help put context to many of the topics covered in this guide, my use-case/configuration is: 172 | 173 | - A desktop class computer... 174 | - With a single NIC... 175 | - Connected to a consumer grade router... 176 | - Getting a dynamic WAN IP provided by the ISP... 177 | - With WAN+LAN on IPV4... 178 | - And LAN using [NAT](https://en.wikipedia.org/wiki/Network_address_translation)... 179 | - That I want to be able to SSH to remotely from unknown computers and unknown locations (i.e. a friend's house). 180 | 181 | ([Table of Contents](#table-of-contents)) 182 | 183 | ### Editing Configuration Files - For The Lazy 184 | 185 | I am very lazy and do not like to edit files by hand if I don't need to. I also assume everyone else is just like me. :) 186 | 187 | So, when and where possible, I have provided `code` snippets to quickly do what is needed, like add or change a line in a configuration file. 188 | 189 | The `code` snippets use basic commands like `echo`, `cat`, `sed`, `awk`, and `grep`. How the `code` snippets work, like what each command/part does, is out of scope for this guide -- the `man` pages are your friend. 190 | 191 | **Note**: The `code` snippets do not validate/verify the change went through -- i.e. the line was actually added or changed. I'll leave the verifying part in your capable hands. The steps in this guide do include taking backups of all files that will be changed. 192 | 193 | Not all changes can be automated with `code` snippets. Those changes need good, old-fashioned, manual editing. For example, you can't just append a line to an [INI](https://en.wikipedia.org/wiki/INI_file) type file. Use your [favorite](https://en.wikipedia.org/wiki/Vi) Linux text editor. 194 | 195 | ([Table of Contents](#table-of-contents)) 196 | 197 | ### Contributing 198 | 199 | I wanted to put this guide on [GitHub](http://www.github.com) to make it easy to collaborate. The more folks that contribute, the better and more complete this guide will become. 200 | 201 | To contribute you can fork and submit a pull request or submit a [new issue](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/new). 202 | 203 | ([Table of Contents](#table-of-contents)) 204 | 205 | ## Before You Start 206 | 207 | ### Identify Your Principles 208 | 209 | Before you start you will want to identify what your Principles are. What is your [threat model](https://en.wikipedia.org/wiki/Threat_model)? Some things to think about: 210 | 211 | - Why do you want to secure your server? 212 | - How much security do you want or not want? 213 | - How much convenience are you willing to compromise for security and vice-versa? 214 | - What are the threats you want to protect against? What are the specifics to your situation? For example: 215 | - Is physical access to your server/network a possible attack vector? 216 | - Will you be opening ports on your router so you can access your server from outside your home? 217 | - Will you be hosting a file share on your server that will be mounted on a desktop class machine? What is the possibility of the desktop machine getting infected and, in turn, infecting the server? 218 | - Do you have a means of recovering if your security implementation locks you out of your own server? For example, you [disabled root login](#disable-root-login) or [password protected GRUB](#password-protect-grub). 219 | 220 | These are just **a few things** to think about. Before you start securing your server you will want to understand what you're trying to protect against and why so you know what you need to do. 221 | 222 | ([Table of Contents](#table-of-contents)) 223 | 224 | ### Picking A Linux Distribution 225 | 226 | This guide is intended to be distribution agnostic so users can use [any distribution](https://distrowatch.com/) they want. With that said, there are a few things to keep in mind: 227 | 228 | You want a distribution that... 229 | 230 | - ...**is stable**. Unless you like debugging issues at 2 AM, you don't want an [unattended upgrade](#automatic-security-updates-and-alerts), or a manual package/system update, to render your server inoperable. But this also means you're okay with not running the latest, greatest, bleeding edge software. 231 | - ...**stays up-to-date with security patches**. You can secure everything on your server, but if the core OS or applications you're running have known vulnerabilities, you'll never be safe. 232 | - ...**you're familiar with.** If you don't know Linux, I would advise you play around with one before you try to secure it. You should be comfortable with it and know your way around, like how to install software, where configuration files are, etc... 233 | - ...**is well-supported.** Even the most seasoned admin needs help every now and then. Having a place to go for help will save your sanity. 234 | 235 | ([Table of Contents](#table-of-contents)) 236 | 237 | ### Installing Linux 238 | 239 | Installing Linux is out-of-scope for this guide because each distribution does it differently and the installation instructions are usually well documented. If you need help, start with your distribution's documentation. Regardless of the distribution, the high-level process usually goes like so: 240 | 241 | 1. download the ISO 242 | 1. burn/copy/transfer it to your install medium (e.g. a CD or USB stick) 243 | 1. boot your server from your install medium 244 | 1. follow the prompts to install 245 | 246 | Where applicable, use the expert install option so you have tighter control of what is running on your server. **Only install what you absolutely need.** I, personally, do not install anything other than SSH. Also, tick the Disk Encryption option. 247 | 248 | ([Table of Contents](#table-of-contents)) 249 | 250 | ### Pre/Post Installation Requirements 251 | 252 | - If you're opening ports on your router so you can access your server from the outside, disable the port forwarding until your system is up and secured. 253 | - Unless you're doing everything physically connected to your server, you'll need remote access so be sure SSH works. 254 | - Keep your system up-to-date (i.e. `sudo apt update && sudo apt upgrade` on Debian based systems). 255 | - Make sure you perform any tasks specific to your setup like: 256 | - Configuring network 257 | - Configuring mount points in `/etc/fstab` 258 | - Creating the initial user accounts 259 | - Installing core software you'll want like `man` 260 | - Etc... 261 | - Your server will need to be able to send e-mails so you can get important security alerts. If you're not setting up a mail server check [Gmail and Exim4 As MTA With Implicit TLS](#gmail-and-exim4-as-mta-with-implicit-tls). 262 | - I would also recommend you **read** through the [CIS Benchmarks](https://www.cisecurity.org/cis-benchmarks/) before you start with this guide just to digest/understand what they have to say. My recommendation is to go through this guide (the one you're reading here) first and THEN CIS's guide. That way their recommendations will trump anything in this guide. 263 | 264 | ([Table of Contents](#table-of-contents)) 265 | 266 | ### Other Important Notes 267 | 268 | - This guide is being written and tested on Debian. Most things below should work on other distributions. If you find something that does not, please [contact me](#contacting-me). The main thing that separates each distribution will be its package management system. Since I use Debian, I will provide the appropriate `apt` commands that should work on all [Debian based distributions](https://www.debian.org/derivatives/). If someone is willing to [provide](#contributing) the respective commands for other distributions, I will add them. 269 | - File paths and settings also may differ slightly -- check with your distribution's documentation if you have issues. 270 | - Read the whole guide before you start. Your use-case and/or principals may call for not doing something or for changing the order. 271 | - Do not **blindly** copy-and-paste without understanding what you're pasting. Some commands will need to be modified for your needs before they'll work -- usernames for example. 272 | 273 | ([Table of Contents](#table-of-contents)) 274 | 275 | ### Using Ansible playbooks to secure your Linux Server 276 | Ansible playbooks of this guide are available at [How To Secure A Linux Server With Ansible](https://github.com/moltenbit/How-To-Secure-A-Linux-Server-With-Ansible). 277 | 278 | Make sure to edit the variables according to your needs and read all tasks beforehand to confirm it does not break your system. After running the playbooks ensure that all settings are configured to your needs! 279 | 280 | 1. Install [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) 281 | 2. git clone [How To Secure A Linux Server With Ansible](https://github.com/moltenbit/How-To-Secure-A-Linux-Server-With-Ansible) 282 | 3. [Create SSH-Public/Private-Keys](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server#ssh-publicprivate-keys) 283 | ``` 284 | ssh-keygen -t ed25519 285 | ``` 286 | 287 | 5. Change all variables in *group_vars/variables.yml* according to your needs. 288 | 6. Enable SSH root access before running the playbooks: 289 | 290 | ``` 291 | nano /etc/ssh/sshd_config 292 | [...] 293 | PermitRootLogin yes 294 | [...] 295 | ``` 296 | 297 | 7. Recommended: configure static IP address on your system. 298 | 8. Add your systems IP address to *hosts.yml*. 299 | 300 |   301 | 302 | Run the requirements playbook using the root password you specified while installing the server: 303 | 304 | ansible-playbook --inventory hosts.yml --ask-pass requirements-playbook.yml 305 | 306 |   307 | 308 | Run the main playbook with the new users password you specified in the *variables.yml* file: 309 | 310 | ansible-playbook --inventory hosts.yml --ask-pass main-playbook.yml 311 | 312 |   313 | 314 | If you need to run the playbooks multiple times remember to use the SSH key and the new SSH port: 315 | 316 | ansible-playbook --inventory hosts.yml -e ansible_ssh_port=SSH_PORT --key-file /PATH/TO/SSH/KEY main-playbook.yml 317 | 318 | 319 | ([Table of Contents](#table-of-contents)) 320 | 321 | ## The SSH Server 322 | 323 | ### Important Note Before You Make SSH Changes 324 | 325 | It is highly advised you keep a 2nd terminal open to your server **before you make and apply SSH configuration changes**. This way if you lock yourself out of your 1st terminal session, you still have one session connected so you can fix it. 326 | 327 | Thank you to [Sonnenbrand](https://github.com/Sonnenbrand) for this [idea](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/56). 328 | 329 | ### SSH Public/Private Keys 330 | 331 | #### Why 332 | 333 | Using SSH public/private keys is more secure than using a password. It also makes it easier and faster, to connect to our server because you don't have to enter a password. 334 | 335 | #### How It Works 336 | 337 | Check the references below for more details but, at a high level, public/private keys work by using a pair of keys to verify identity. 338 | 339 | 1. One key, the **public** key, **can only encrypt data**, not decrypt it 340 | 1. The other key, the **private** key, can decrypt the data 341 | 342 | For SSH, a public and private key is created on the client. You want to keep both keys secure, especially the private key. Even though the public key is meant to be public, it is wise to make sure neither keys fall in the wrong hands. 343 | 344 | When you connect to an SSH server, SSH will look for a public key that matches the client you're connecting from in the file `~/.ssh/authorized_keys` on the server you're connecting to. Notice the file is in the **home folder** of the ID you're trying to connect to. So, after creating the public key, you need to append it to `~/.ssh/authorized_keys`. One approach is to copy it to a USB stick and physically transfer it to the server. Another approach is to use [`ssh-copy-id`](https://www.ssh.com/ssh/copy-id) to transfer and append the public key. 345 | 346 | After the keys have been created and the public key has been appended to `~/.ssh/authorized_keys` on the host, SSH uses the public and private keys to verify identity and then establish a secure connection. How identity is verified is a complicated process but [Digital Ocean](https://www.digitalocean.com/community/tutorials/understanding-the-ssh-encryption-and-connection-process) has a very nice write-up of how it works. At a high level, identity is verified by the server encrypting a challenge message with the public key, then sending it to the client. If the client cannot decrypt the challenge message with the private key, the identity can't be verified and a connection will not be established. 347 | 348 | They are considered more secure because you need the private key to establish an SSH connection. If you set [`PasswordAuthentication no` in `/etc/ssh/sshd_config`](#PasswordAuthentication), then SSH won't let you connect without the private key. 349 | 350 | You can also set a pass-phrase for the keys which would require you to enter the key pass-phrase when connecting using public/private keys. Keep in mind doing this means you can't use the key for automation because you'll have no way to send the passphrase in your scripts. `ssh-agent` is a program that is shipped in many Linux distros (and usually already running) that will allow you to hold your unencrypted private key in memory for a configurable duration. Simply run `ssh-add` and it will prompt you for your passphrase. You will not be prompted for your passphrase again until the configurable duration has passed. 351 | 352 | We will be using Ed25519 keys which, according to [https://linux-audit.com/](https://linux-audit.com/using-ed25519-openssh-keys-instead-of-dsa-rsa-ecdsa/): 353 | 354 | > It is using an elliptic curve signature scheme, which offers better security than ECDSA and DSA. At the same time, it also has good performance. 355 | 356 | #### Goals 357 | 358 | - Ed25519 public/private SSH keys: 359 | - private key on your client 360 | - public key on your server 361 | 362 | #### Notes 363 | 364 | - You'll need to do this step for every computer and account you'll be connecting to your server from/as. 365 | 366 | #### References 367 | 368 | - https://www.ssh.com/ssh/public-key-authentication 369 | - https://help.ubuntu.com/community/SSH/OpenSSH/Keys 370 | - https://linux-audit.com/using-ed25519-openssh-keys-instead-of-dsa-rsa-ecdsa/ 371 | - https://www.digitalocean.com/community/tutorials/understanding-the-ssh-encryption-and-connection-process 372 | - https://wiki.archlinux.org/index.php/SSH_Keys 373 | - https://www.ssh.com/ssh/copy-id 374 | - `man ssh-keygen` 375 | - `man ssh-copy-id` 376 | - `man ssh-add` 377 | 378 | #### Steps 379 | 380 | 1. From the computer you're going to use to connect to your server, **the client**, not the server itself, create an [Ed25519](https://linux-audit.com/using-ed25519-openssh-keys-instead-of-dsa-rsa-ecdsa/) key with `ssh-keygen`: 381 | 382 | ``` bash 383 | ssh-keygen -t ed25519 384 | ``` 385 | 386 | > ``` 387 | > Generating public/private ed25519 key pair. 388 | > Enter file in which to save the key (/home/user/.ssh/id_ed25519): 389 | > Created directory '/home/user/.ssh'. 390 | > Enter passphrase (empty for no passphrase): 391 | > Enter same passphrase again: 392 | > Your identification has been saved in /home/user/.ssh/id_ed25519. 393 | > Your public key has been saved in /home/user/.ssh/id_ed25519.pub. 394 | > The key fingerprint is: 395 | > SHA256:F44D4dr2zoHqgj0i2iVIHQ32uk/Lx4P+raayEAQjlcs user@client 396 | > The key's randomart image is: 397 | > +--[ED25519 256]--+ 398 | > |xxxx x | 399 | > |o.o +. . | 400 | > | o o oo . | 401 | > |. E oo . o . | 402 | > | o o. o S o | 403 | > |... .. o o | 404 | > |.+....+ o | 405 | > |+.=++o.B.. | 406 | > |+..=**=o=. | 407 | > +----[SHA256]-----+ 408 | > ``` 409 | 410 | **Note**: If you set a passphrase, you'll need to enter it every time you connect to your server using this key, unless you're using `ssh-agent`. 411 | 412 | 1. Now you need to **append** the public key `~/.ssh/id_ed25519.pub` from your client to the `~/.ssh/authorized_keys` file on your server. Since we're presumable still at home on the LAN, we're probably safe from [MIM](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) attacks, so we will use `ssh-copy-id` to transfer and append the public key: 413 | 414 | ``` bash 415 | ssh-copy-id user@server 416 | ``` 417 | 418 | > ``` 419 | > /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_ed25519.pub" 420 | > The authenticity of host 'host (192.168.1.96)' can't be established. 421 | > ECDSA key fingerprint is SHA256:QaDQb/X0XyVlogh87sDXE7MR8YIK7ko4wS5hXjRySJE. 422 | > Are you sure you want to continue connecting (yes/no)? yes 423 | > /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed 424 | > /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys 425 | > user@host's password: 426 | > 427 | > Number of key(s) added: 1 428 | > 429 | > Now try logging into the machine, with: "ssh 'user@host'" 430 | > and check to make sure that only the key(s) you wanted were added. 431 | > ``` 432 | 433 | Now would be a good time to [perform any tasks specific to your setup](#prepost-installation-requirements). 434 | 435 | ([Table of Contents](#table-of-contents)) 436 | 437 | ### Create SSH Group For AllowGroups 438 | 439 | #### Why 440 | 441 | To make it easy to control who can SSH to the server. By using a group, we can quickly add/remove accounts to the group to quickly allow or not allow SSH access to the server. 442 | 443 | #### How It Works 444 | 445 | We will use the [AllowGroups option](#AllowGroups) in SSH's configuration file [`/etc/ssh/sshd_config`](#secure-etcsshsshd_config) to tell the SSH server to only allow users to SSH in if they are a member of a certain UNIX group. Anyone not in the group will not be able to SSH in. 446 | 447 | #### Goals 448 | 449 | - a UNIX group that we'll use in [Secure `/etc/ssh/sshd_config`](#secure-etcsshsshd_config) to limit who can SSH to the server 450 | 451 | #### Notes 452 | 453 | - This is a prerequisite step to support the `AllowGroup` setting set in [Secure `/etc/ssh/sshd_config`](#secure-etcsshsshd_config). 454 | 455 | #### References 456 | 457 | - `man groupadd` 458 | - `man usermod` 459 | 460 | #### Steps 461 | 462 | 1. Create a group: 463 | 464 | ``` bash 465 | sudo groupadd sshusers 466 | ``` 467 | 468 | 1. Add account(s) to the group: 469 | 470 | ``` bash 471 | sudo usermod -a -G sshusers user1 472 | sudo usermod -a -G sshusers user2 473 | sudo usermod -a -G sshusers ... 474 | ``` 475 | 476 | You'll need to do this for every account on your server that needs SSH access. 477 | 478 | ([Table of Contents](#table-of-contents)) 479 | 480 | ### Secure `/etc/ssh/sshd_config` 481 | 482 | #### Why 483 | 484 | SSH is a door into your server. This is especially true if you are opening ports on your router so you can SSH to your server from outside your home network. If it is not secured properly, a bad-actor could use it to gain unauthorized access to your system. 485 | 486 | #### How It Works 487 | 488 | `/etc/ssh/sshd_config` is the default configuration file that the SSH server uses. We will use this file to tell what options the SSH server should use. 489 | 490 | #### Goals 491 | 492 | - a secure SSH configuration 493 | 494 | #### Notes 495 | 496 | - Make sure you've completed [Create SSH Group For AllowGroups](#create-ssh-group-for-allowgroups) first. 497 | 498 | #### References 499 | 500 | - Mozilla's OpenSSH guidelines for OpenSSH 6.7+ at https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 501 | - https://linux-audit.com/audit-and-harden-your-ssh-configuration/ 502 | - https://www.ssh.com/ssh/sshd_config/ 503 | - https://www.techbrown.com/harden-ssh-secure-linux-vps-server/ (broken; try http://web.archive.org/web/20200413100933/https://www.techbrown.com/harden-ssh-secure-linux-vps-server/) 504 | - https://serverfault.com/questions/660160/openssh-difference-between-internal-sftp-and-sftp-server/660325 505 | - `man sshd_config` 506 | - Thanks to [than0s](https://github.com/than0s) for [how to find duplicate settings](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/38). 507 | 508 | #### Steps 509 | 510 | 1. Make a backup of OpenSSH server's configuration file `/etc/ssh/sshd_config` and remove comments to make it easier to read: 511 | 512 | ``` bash 513 | sudo cp --archive /etc/ssh/sshd_config /etc/ssh/sshd_config-COPY-$(date +"%Y%m%d%H%M%S") 514 | sudo sed -i -r -e '/^#|^$/ d' /etc/ssh/sshd_config 515 | ``` 516 | 517 | 1. Edit `/etc/ssh/sshd_config` then find and edit or add these settings that should be applied regardless of your configuration/setup: 518 | 519 | **Note**: SSH does not like duplicate contradicting settings. For example, if you have `ChallengeResponseAuthentication no` and then `ChallengeResponseAuthentication yes`, SSH will respect the first one and ignore the second. Your `/etc/ssh/sshd_config` file may already have some of the settings/lines below. To avoid issues you will need to manually go through your `/etc/ssh/sshd_config` file and address any duplicate contradicting settings. 520 | 521 | ``` 522 | ######################################################################################################## 523 | # start settings from https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 as of 2019-01-01 524 | ######################################################################################################## 525 | 526 | # Supported HostKey algorithms by order of preference. 527 | HostKey /etc/ssh/ssh_host_ed25519_key 528 | HostKey /etc/ssh/ssh_host_rsa_key 529 | HostKey /etc/ssh/ssh_host_ecdsa_key 530 | 531 | KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 532 | 533 | Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr 534 | 535 | MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com 536 | 537 | # LogLevel VERBOSE logs user's key fingerprint on login. Needed to have a clear audit track of which key was using to log in. 538 | LogLevel VERBOSE 539 | 540 | # Use kernel sandbox mechanisms where possible in unprivileged processes 541 | # Systrace on OpenBSD, Seccomp on Linux, seatbelt on MacOSX/Darwin, rlimit elsewhere. 542 | # Note: This setting is deprecated in OpenSSH 7.5 (https://www.openssh.com/txt/release-7.5) 543 | # UsePrivilegeSeparation sandbox 544 | 545 | ######################################################################################################## 546 | # end settings from https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 as of 2019-01-01 547 | ######################################################################################################## 548 | 549 | # don't let users set environment variables 550 | PermitUserEnvironment no 551 | 552 | # Log sftp level file access (read/write/etc.) that would not be easily logged otherwise. 553 | Subsystem sftp internal-sftp -f AUTHPRIV -l INFO 554 | 555 | # only use the newer, more secure protocol 556 | Protocol 2 557 | 558 | # disable X11 forwarding as X11 is very insecure 559 | # you really shouldn't be running X on a server anyway 560 | X11Forwarding no 561 | 562 | # disable port forwarding 563 | AllowTcpForwarding no 564 | AllowStreamLocalForwarding no 565 | GatewayPorts no 566 | PermitTunnel no 567 | 568 | # don't allow login if the account has an empty password 569 | PermitEmptyPasswords no 570 | 571 | # ignore .rhosts and .shosts 572 | IgnoreRhosts yes 573 | 574 | # verify hostname matches IP 575 | UseDNS yes 576 | 577 | Compression no 578 | TCPKeepAlive no 579 | AllowAgentForwarding no 580 | PermitRootLogin no 581 | 582 | # don't allow .rhosts or /etc/hosts.equiv 583 | HostbasedAuthentication no 584 | 585 | # https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/115 586 | HashKnownHosts yes 587 | ``` 588 | 589 | 1. Then **find and edit or add** these settings, and set values as per your requirements: 590 | 591 | |Setting|Valid Values|Example|Description|Notes| 592 | |--|--|--|--|--| 593 | |**AllowGroups**|local UNIX group name|`AllowGroups sshusers`|group to allow SSH access to|| 594 | |**ClientAliveCountMax**|number|`ClientAliveCountMax 0`|maximum number of client alive messages sent without response|| 595 | |**ClientAliveInterval**|number of seconds|`ClientAliveInterval 300`|timeout in seconds before a response request|| 596 | |**ListenAddress**|space separated list of local addresses||local addresses `sshd` should listen on|See [Issue #1](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/1) for important details.| 597 | |**LoginGraceTime**|number of seconds|`LoginGraceTime 30`|time in seconds before login times-out|| 598 | |**MaxAuthTries**|number|`MaxAuthTries 2`|maximum allowed attempts to login|| 599 | |**MaxSessions**|number|`MaxSessions 2`|maximum number of open sessions|| 600 | |**MaxStartups**|number|`MaxStartups 2`|maximum number of login sessions|| 601 | |**PasswordAuthentication**|`yes` or `no`|`PasswordAuthentication no`|if login with a password is allowed|| 602 | |**Port**|any open/available port number|`Port 22`|port that `sshd` should listen on|| 603 | 604 | Check `man sshd_config` for more details what these settings mean. 605 | 606 | 1. Make sure there are no duplicate settings that contradict each other. The below command should not have any output. 607 | 608 | ```bash 609 | awk 'NF && $1!~/^(#|HostKey)/{print $1}' /etc/ssh/sshd_config | sort | uniq -c | grep -v ' 1 ' 610 | ``` 611 | 612 | 1. Restart ssh: 613 | 614 | ``` bash 615 | sudo service sshd restart 616 | ``` 617 | 618 | 1. You can check verify the configurations worked with `sshd -T` and verify the output: 619 | 620 | ``` bash 621 | sudo sshd -T 622 | ``` 623 | 624 | > ``` 625 | > port 22 626 | > addressfamily any 627 | > listenaddress [::]:22 628 | > listenaddress 0.0.0.0:22 629 | > usepam yes 630 | > logingracetime 30 631 | > x11displayoffset 10 632 | > maxauthtries 2 633 | > maxsessions 2 634 | > clientaliveinterval 300 635 | > clientalivecountmax 0 636 | > streamlocalbindmask 0177 637 | > permitrootlogin no 638 | > ignorerhosts yes 639 | > ignoreuserknownhosts no 640 | > hostbasedauthentication no 641 | > ... 642 | > subsystem sftp internal-sftp -f AUTHPRIV -l INFO 643 | > maxstartups 2:30:2 644 | > permittunnel no 645 | > ipqos lowdelay throughput 646 | > rekeylimit 0 0 647 | > permitopen any 648 | > ``` 649 | 650 | ([Table of Contents](#table-of-contents)) 651 | 652 | ### Remove Short Diffie-Hellman Keys 653 | 654 | #### Why 655 | 656 | Per [Mozilla's OpenSSH guidelines for OpenSSH 6.7+](https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67), "all Diffie-Hellman moduli in use should be at least 3072-bit-long". 657 | 658 | The Diffie-Hellman algorithm is used by SSH to establish a secure connection. The larger the moduli (key size) the stronger the encryption. 659 | 660 | #### Goals 661 | 662 | - remove all Diffie-Hellman keys that are less than 3072 bits long 663 | 664 | #### References 665 | 666 | - Mozilla's OpenSSH guidelines for OpenSSH 6.7+ at https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 667 | - https://infosec.mozilla.org/guidelines/key_management 668 | - `man moduli` 669 | 670 | #### Steps 671 | 672 | 1. Make a backup of SSH's moduli file `/etc/ssh/moduli`: 673 | 674 | ``` bash 675 | sudo cp --archive /etc/ssh/moduli /etc/ssh/moduli-COPY-$(date +"%Y%m%d%H%M%S") 676 | ``` 677 | 678 | 1. Remove short moduli: 679 | 680 | ``` bash 681 | sudo awk '$5 >= 3071' /etc/ssh/moduli | sudo tee /etc/ssh/moduli.tmp 682 | sudo mv /etc/ssh/moduli.tmp /etc/ssh/moduli 683 | ```` 684 | 685 | ([Table of Contents](#table-of-contents)) 686 | 687 | ### 2FA/MFA for SSH 688 | 689 | #### Why 690 | 691 | Even though SSH is a pretty good security guard for your doors and windows, it is still a visible door that bad-actors can see and try to brute-force in. [Fail2ban](#fail2ban-application-intrusion-detection-and-prevention) will monitor for these brute-force attempts but there is no such thing as being too secure. Requiring two factors adds an extra layer of security. 692 | 693 | Using Two-Factor Authentication (2FA) / Multi-Factor Authentication (MFA) requires anyone entering to have **two** keys to enter which makes it harder for bad actors. The two keys are: 694 | 695 | 1. Their password 696 | 1. A 6 digit token that changes every 30 seconds 697 | 698 | Without both keys, they won't be able to get in. 699 | 700 | #### Why Not 701 | 702 | Many folks might find the experience cumbersome or annoying. And, access to your system is dependent on the accompanying authenticator app that generates the code. 703 | 704 | #### How It Works 705 | 706 | On Linux, PAM is responsible for authentication. There are four tasks to PAM that you can read about at https://en.wikipedia.org/wiki/Linux_PAM. This section talks about the authentication task. 707 | 708 | When you log into a server, be it directly from the console or via SSH, the door you came through will send the request to the authentication task of PAM and PAM will ask for and verify your password. You can customize the rules each doors use. For example, you could have one set of rules when logging in directly from the console and another set of rules for when logging in via SSH. 709 | 710 | This section will alter the authentication rules for when logging in via SSH to require both a password and a 6 digit code. 711 | 712 | We will use Google's libpam-google-authenticator PAM module to create and verify a [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm) key. https://fastmail.blog/2016/07/22/how-totp-authenticator-apps-work/ and https://jemurai.com/2018/10/11/how-it-works-totp-based-mfa/ have very good writeups of how TOTP works. 713 | 714 | What we will do is tell the server's SSH PAM configuration to ask the user for their password and then their numeric token. PAM will then verify the user's password and, if it is correct, then it will route the authentication request to libpam-google-authenticator which will ask for and verify your 6 digit token. If, and only if, everything is good will the authentication succeed and user be allowed to log in. 715 | 716 | #### Goals 717 | 718 | - 2FA/MFA enabled for all SSH connections 719 | 720 | #### Notes 721 | 722 | - Before you do this, you should have an idea of how 2FA/MFA works and you'll need an authenticator app on your phone to continue. 723 | - We'll use [google-authenticator-libpam](https://github.com/google/google-authenticator-libpam). 724 | - With the below configuration, a user will only need to enter their 2FA/MFA code if they are logging on with their password but **not** if they are using [SSH public/private keys](#ssh-publicprivate-keys). Check the documentation on how to change this behavior to suite your requirements. 725 | 726 | #### References 727 | 728 | - https://github.com/google/google-authenticator-libpam 729 | - https://en.wikipedia.org/wiki/Linux_PAM 730 | - https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm 731 | - https://fastmail.blog/2016/07/22/how-totp-authenticator-apps-work/ 732 | - https://jemurai.com/2018/10/11/how-it-works-totp-based-mfa/ 733 | 734 | #### Steps 735 | 736 | 1. Install it libpam-google-authenticator. 737 | 738 | On Debian based systems: 739 | 740 | ``` bash 741 | sudo apt install libpam-google-authenticator 742 | ``` 743 | 744 | 1. **Make sure you're logged in as the ID you want to enable 2FA/MFA for** and **execute** `google-authenticator` to create the necessary token data: 745 | 746 | ``` bash 747 | google-authenticator 748 | ``` 749 | 750 | > ``` 751 | > Do you want authentication tokens to be time-based (y/n) y 752 | > https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/user@host%3Fsecret%3DR4ZWX34FQKZROVX7AGLJ64684Y%26issuer%3Dhost 753 | > 754 | > ... 755 | > 756 | > Your new secret key is: R3NVX3FFQKZROVX7AGLJUGGESY 757 | > Your verification code is 751419 758 | > Your emergency scratch codes are: 759 | > 12345678 760 | > 90123456 761 | > 78901234 762 | > 56789012 763 | > 34567890 764 | > 765 | > Do you want me to update your "/home/user/.google_authenticator" file (y/n) y 766 | > 767 | > Do you want to disallow multiple uses of the same authentication 768 | > token? This restricts you to one login about every 30s, but it increases 769 | > your chances to notice or even prevent man-in-the-middle attacks (y/n) Do you want to disallow multiple uses of the same authentication 770 | > token? This restricts you to one login about every 30s, but it increases 771 | > your chances to notice or even prevent man-in-the-middle attacks (y/n) y 772 | > 773 | > By default, tokens are good for 30 seconds. In order to compensate for 774 | > possible time-skew between the client and the server, we allow an extra 775 | > token before and after the current time. If you experience problems with 776 | > poor time synchronization, you can increase the window from its default 777 | > size of +-1min (window size of 3) to about +-4min (window size of 778 | > 17 acceptable tokens). 779 | > Do you want to do so? (y/n) y 780 | > 781 | > If the computer that you are logging into isn't hardened against brute-force 782 | > login attempts, you can enable rate-limiting for the authentication module. 783 | > By default, this limits attackers to no more than 3 login attempts every 30s. 784 | > Do you want to enable rate-limiting (y/n) y 785 | > ``` 786 | 787 | Notice this is **not run as root**. 788 | 789 | Select default option (y in most cases) for all the questions it asks and remember to save the emergency scratch codes. 790 | 791 | 1. Make a backup of PAM's SSH configuration file `/etc/pam.d/sshd`: 792 | 793 | ``` bash 794 | sudo cp --archive /etc/pam.d/sshd /etc/pam.d/sshd-COPY-$(date +"%Y%m%d%H%M%S") 795 | ``` 796 | 797 | 1. Now we need to enable it as an authentication method for SSH by adding this line to `/etc/pam.d/sshd`: 798 | 799 | ``` 800 | auth required pam_google_authenticator.so nullok 801 | ``` 802 | 803 | **Note**: Check [here](https://github.com/google/google-authenticator-libpam/blob/master/README.md#nullok) for what `nullok` means. 804 | 805 | [For the lazy](#editing-configuration-files---for-the-lazy): 806 | 807 | ``` bash 808 | echo -e "\nauth required pam_google_authenticator.so nullok # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/pam.d/sshd 809 | ``` 810 | 811 | 1. Tell SSH to leverage it by adding or editing this line in `/etc/ssh/sshd_config`: 812 | 813 | ``` 814 | ChallengeResponseAuthentication yes 815 | ``` 816 | 817 | [For the lazy](#editing-configuration-files---for-the-lazy): 818 | 819 | ``` bash 820 | sudo sed -i -r -e "s/^(challengeresponseauthentication .*)$/# \1 # commented by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")/I" /etc/ssh/sshd_config 821 | echo -e "\nChallengeResponseAuthentication yes # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/ssh/sshd_config 822 | ``` 823 | 824 | 1. Restart ssh: 825 | 826 | ``` bash 827 | sudo service sshd restart 828 | ``` 829 | 830 | ([Table of Contents](#table-of-contents)) 831 | 832 | ## The Basics 833 | 834 | ### Limit Who Can Use sudo 835 | 836 | #### Why 837 | 838 | sudo lets accounts run commands as other accounts, including **root**. We want to make sure that only the accounts we want can use sudo. 839 | 840 | #### Goals 841 | 842 | - sudo privileges limited to those who are in a group we specify 843 | 844 | #### Notes 845 | 846 | - Your installation may have already done this, or may already have a special group intended for this purpose so check first. 847 | - Debian creates the sudo group. To view users that are part of this group (thus have sudo privileges): 848 | 849 | ``` 850 | cat /etc/group | grep "sudo" 851 | ``` 852 | - RedHat creates the wheel group 853 | - See [https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/39](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/39) for a note on some distributions making it so `sudo` does not require a password. Thanks to [sbrl](https://github.com/sbrl) for sharing. 854 | 855 | #### Steps 856 | 857 | 1. Create a group: 858 | 859 | ``` bash 860 | sudo groupadd sudousers 861 | ``` 862 | 863 | 1. Add account(s) to the group: 864 | 865 | ``` bash 866 | sudo usermod -a -G sudousers user1 867 | sudo usermod -a -G sudousers user2 868 | sudo usermod -a -G sudousers ... 869 | ``` 870 | 871 | You'll need to do this for every account on your server that needs sudo privileges. 872 | 873 | 1. Make a backup of the sudo's configuration file `/etc/sudoers`: 874 | 875 | ``` bash 876 | sudo cp --archive /etc/sudoers /etc/sudoers-COPY-$(date +"%Y%m%d%H%M%S") 877 | ``` 878 | 879 | 1. Edit sudo's configuration file `/etc/sudoers`: 880 | 881 | ``` bash 882 | sudo visudo 883 | ``` 884 | 885 | 1. Tell sudo to only allow users in the `sudousers` group to use sudo by adding this line if it is not already there: 886 | 887 | ``` 888 | %sudousers ALL=(ALL:ALL) ALL 889 | ``` 890 | 891 | ([Table of Contents](#table-of-contents)) 892 | 893 | ### Limit Who Can Use su 894 | 895 | #### Why 896 | 897 | su also lets accounts run commands as other accounts, including **root**. We want to make sure that only the accounts we want can use su. 898 | 899 | #### Goals 900 | 901 | - su privileges limited to those who are in a group we specify 902 | 903 | #### References 904 | 905 | - Thanks to [olavim](https://github.com/olavim) for sharing [this idea](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/41) 906 | 907 | #### Steps 908 | 909 | 1. Create a group: 910 | 911 | ``` bash 912 | sudo groupadd suusers 913 | ``` 914 | 915 | 1. Add account(s) to the group: 916 | 917 | ``` bash 918 | sudo usermod -a -G suusers user1 919 | sudo usermod -a -G suusers user2 920 | sudo usermod -a -G suusers ... 921 | ``` 922 | 923 | You'll need to do this for every account on your server that needs sudo privileges. 924 | 925 | 1. Make it so only users in this group can execute `/bin/su`: 926 | 927 | ``` bash 928 | sudo dpkg-statoverride --update --add root suusers 4750 /bin/su 929 | ``` 930 | 931 | ([Table of Contents](#table-of-contents)) 932 | 933 | ### Run applications in a sandbox with FireJail 934 | 935 | #### Why 936 | 937 | It's absolutely better, for many applications, to run in a sandbox. 938 | 939 | Browsers (even more the Closed Source ones) and eMail Clients are highly suggested. 940 | 941 | #### Goals 942 | 943 | - confine applications in a jail (few safe directories) and block access to the rest of the system 944 | 945 | #### References 946 | 947 | - Thanks to [FireJail](https://firejail.wordpress.com/) 948 | 949 | #### Steps 950 | 951 | 1. Install the software: 952 | 953 | ``` bash 954 | sudo apt install firejail firejail-profiles 955 | ``` 956 | 957 | Note: for Debian 10 Stable, official Backport is suggested: 958 | 959 | ``` bash 960 | sudo apt install -t buster-backports firejail firejail-profiles 961 | ``` 962 | 963 | 2. Allow an application (installed in `/usr/bin` or `/bin`) to run only in a sandbox (see few examples below here): 964 | 965 | ``` bash 966 | sudo ln -s /usr/bin/firejail /usr/local/bin/google-chrome-stable 967 | sudo ln -s /usr/bin/firejail /usr/local/bin/firefox 968 | sudo ln -s /usr/bin/firejail /usr/local/bin/chromium 969 | sudo ln -s /usr/bin/firejail /usr/local/bin/evolution 970 | sudo ln -s /usr/bin/firejail /usr/local/bin/thunderbird 971 | ``` 972 | 973 | 3. Run the application as usual (via terminal or launcher) and check if it's running in a jail: 974 | 975 | ``` bash 976 | firejail --list 977 | ``` 978 | 979 | 4. Allow a sandboxed app to run again as it was before (example: firefox) 980 | 981 | ``` bash 982 | sudo rm /usr/local/bin/firefox 983 | ``` 984 | 985 | ([Table of Contents](#table-of-contents)) 986 | 987 | ### NTP Client 988 | 989 | #### Why 990 | 991 | Many security protocols leverage the time. If your system time is incorrect, it could have negative impacts to your server. An NTP client can solve that problem by keeping your system time in-sync with [global NTP servers](https://en.wikipedia.org/wiki/Network_Time_Protocol) 992 | 993 | #### How It Works 994 | 995 | NTP stands for Network Time Protocol. In the context of this guide, an NTP client on the server is used to update the server time with the official time pulled from official servers. Check https://www.pool.ntp.org/en/ for all of the public NTP servers. 996 | 997 | #### Goals 998 | 999 | - NTP client installed and keeping server time in-sync 1000 | 1001 | #### References 1002 | 1003 | - https://cloudpro.zone/index.php/2018/01/27/debian-9-3-server-setup-guide-part-4/ 1004 | - https://en.wikipedia.org/wiki/Network_Time_Protocol 1005 | - https://www.pool.ntp.org/en/ 1006 | - https://serverfault.com/questions/957302/securing-hardening-ntp-client-on-linux-servers-config-file/957450#957450 1007 | - https://tf.nist.gov/tf-cgi/servers.cgi 1008 | 1009 | #### Steps 1010 | 1011 | 1. Install ntp. 1012 | 1013 | On Debian based systems: 1014 | 1015 | ``` bash 1016 | sudo apt install ntp 1017 | ``` 1018 | 1019 | 1. Make a backup of the NTP client's configuration file `/etc/ntp.conf`: 1020 | 1021 | ``` bash 1022 | sudo cp --archive /etc/ntpsec/ntp.conf /etc/ntpsec/ntp.conf-COPY-$(date +"%Y%m%d%H%M%S") 1023 | ``` 1024 | 1025 | 1. The default configuration, at least on Debian, is already pretty secure. The only thing we'll want to make sure is we're the `pool` directive and not any `server` directives. The `pool` directive allows the NTP client to stop using a server if it is unresponsive or serving bad time. Do this by commenting out all `server` directives and adding the below to `/etc/ntp.conf`. 1026 | 1027 | ``` 1028 | pool pool.ntp.org iburst 1029 | ``` 1030 | 1031 | [For the lazy](#editing-configuration-files---for-the-lazy): 1032 | 1033 | ``` bash 1034 | sudo sed -i -r -e "s/^((server|pool).*)/# \1 # commented by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")/" /etc/ntp.conf 1035 | echo -e "\npool pool.ntp.org iburst # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/ntp.conf 1036 | ``` 1037 | 1038 | **Example `/etc/ntp.conf`**: 1039 | 1040 | > ``` 1041 | > driftfile /var/lib/ntp/ntp.drift 1042 | > statistics loopstats peerstats clockstats 1043 | > filegen loopstats file loopstats type day enable 1044 | > filegen peerstats file peerstats type day enable 1045 | > filegen clockstats file clockstats type day enable 1046 | > restrict -4 default kod notrap nomodify nopeer noquery limited 1047 | > restrict -6 default kod notrap nomodify nopeer noquery limited 1048 | > restrict 127.0.0.1 1049 | > restrict ::1 1050 | > restrict source notrap nomodify noquery 1051 | > pool pool.ntp.org iburst # added by user on 2019-03-09 @ 10:23:35 1052 | > ``` 1053 | 1054 | 1. Restart ntp: 1055 | 1056 | ``` bash 1057 | sudo service ntp restart 1058 | ``` 1059 | 1060 | 1. Check the status of the ntp service: 1061 | 1062 | ``` bash 1063 | sudo systemctl status ntp 1064 | ``` 1065 | 1066 | > ``` 1067 | > ● ntp.service - LSB: Start NTP daemon 1068 | > Loaded: loaded (/etc/init.d/ntp; generated; vendor preset: enabled) 1069 | > Active: active (running) since Sat 2019-03-09 15:19:46 EST; 4s ago 1070 | > Docs: man:systemd-sysv-generator(8) 1071 | > Process: 1016 ExecStop=/etc/init.d/ntp stop (code=exited, status=0/SUCCESS) 1072 | > Process: 1028 ExecStart=/etc/init.d/ntp start (code=exited, status=0/SUCCESS) 1073 | > Tasks: 2 (limit: 4915) 1074 | > CGroup: /system.slice/ntp.service 1075 | > └─1038 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 108:113 1076 | > 1077 | > Mar 09 15:19:46 host ntpd[1038]: Listen and drop on 0 v6wildcard [::]:123 1078 | > Mar 09 15:19:46 host ntpd[1038]: Listen and drop on 1 v4wildcard 0.0.0.0:123 1079 | > Mar 09 15:19:46 host ntpd[1038]: Listen normally on 2 lo 127.0.0.1:123 1080 | > Mar 09 15:19:46 host ntpd[1038]: Listen normally on 3 enp0s3 10.10.20.96:123 1081 | > Mar 09 15:19:46 host ntpd[1038]: Listen normally on 4 lo [::1]:123 1082 | > Mar 09 15:19:46 host ntpd[1038]: Listen normally on 5 enp0s3 [fe80::a00:27ff:feb6:ed8e%2]:123 1083 | > Mar 09 15:19:46 host ntpd[1038]: Listening on routing socket on fd #22 for interface updates 1084 | > Mar 09 15:19:47 host ntpd[1038]: Soliciting pool server 108.61.56.35 1085 | > Mar 09 15:19:48 host ntpd[1038]: Soliciting pool server 69.89.207.199 1086 | > Mar 09 15:19:49 host ntpd[1038]: Soliciting pool server 45.79.111.114 1087 | > ``` 1088 | 1089 | 1. Check ntp's status: 1090 | 1091 | ``` bash 1092 | sudo ntpq -p 1093 | ``` 1094 | 1095 | > ``` 1096 | > remote refid st t when poll reach delay offset jitter 1097 | > ============================================================================== 1098 | > pool.ntp.org .POOL. 16 p - 64 0 0.000 0.000 0.000 1099 | > *lithium.constan 198.30.92.2 2 u - 64 1 19.900 4.894 3.951 1100 | > ntp2.wiktel.com 212.215.1.157 2 u 2 64 1 48.061 -0.431 0.104 1101 | > ``` 1102 | 1103 | ([Table of Contents](#table-of-contents)) 1104 | 1105 | ### Securing /proc 1106 | 1107 | #### Why 1108 | 1109 | To quote https://linux-audit.com/linux-system-hardening-adding-hidepid-to-proc/: 1110 | 1111 | > When looking in `/proc` you will discover a lot of files and directories. Many of them are just numbers, which represent the information about a particular process ID (PID). By default, Linux systems are deployed to allow all local users to see this all information. This includes process information from other users. This could include sensitive details that you may not want to share with other users. By applying some filesystem configuration tweaks, we can change this behavior and improve the security of the system. 1112 | 1113 | **Note**: This may break on some `systemd` systems. Please see [https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/37](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/37) for more information. Thanks to [nlgranger](https://github.com/nlgranger) for sharing. 1114 | 1115 | #### Goals 1116 | 1117 | - `/proc` mounted with `hidepid=2` so users can only see information about their processes 1118 | 1119 | #### References 1120 | 1121 | - https://linux-audit.com/linux-system-hardening-adding-hidepid-to-proc/ 1122 | - https://likegeeks.com/secure-linux-server-hardening-best-practices/#Hardening-proc-Directory 1123 | - https://www.cyberciti.biz/faq/linux-hide-processes-from-other-users/ 1124 | 1125 | #### Steps 1126 | 1127 | 1. Make a backup of `/etc/fstab`: 1128 | 1129 | ``` bash 1130 | sudo cp --archive /etc/fstab /etc/fstab-COPY-$(date +"%Y%m%d%H%M%S") 1131 | ``` 1132 | 1133 | 1. Add this line to `/etc/fstab` to have `/proc` mounted with `hidepid=2`: 1134 | 1135 | ``` 1136 | proc /proc proc defaults,hidepid=2 0 0 1137 | ``` 1138 | 1139 | [For the lazy](#editing-configuration-files---for-the-lazy): 1140 | 1141 | ``` bash 1142 | echo -e "\nproc /proc proc defaults,hidepid=2 0 0 # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/fstab 1143 | ``` 1144 | 1145 | 1. Reboot the system: 1146 | 1147 | ``` bash 1148 | sudo reboot now 1149 | ``` 1150 | 1151 | **Note**: Alternatively, you can remount `/proc` without rebooting with `sudo mount -o remount,hidepid=2 /proc` 1152 | 1153 | ([Table of Contents](#table-of-contents)) 1154 | 1155 | ### Force Accounts To Use Secure Passwords 1156 | 1157 | #### Why 1158 | 1159 | By default, accounts can use any password they want, including bad ones. [pwquality](https://linux.die.net/man/5/pwquality.conf)/[pam_pwquality](https://linux.die.net/man/8/pam_pwquality) addresses this security gap by providing "a way to configure the default password quality requirements for the system passwords" and checking "its strength against a system dictionary and a set of rules for identifying poor choices." 1160 | 1161 | #### How It Works 1162 | 1163 | On Linux, PAM is responsible for authentication. There are four tasks to PAM that you can read about at https://en.wikipedia.org/wiki/Linux_PAM. This section talks about the password task. 1164 | 1165 | When there is a need to set or change an account password, the password task of PAM handles the request. In this section we will tell PAM's password task to pass the requested new password to libpam-pwquality to make sure it meets our requirements. If the requirements are met it is used/set; if it does not meet the requirements it errors and lets the user know. 1166 | 1167 | #### Goals 1168 | 1169 | - enforced strong passwords 1170 | 1171 | #### Steps 1172 | 1173 | 1. Install libpam-pwquality. 1174 | 1175 | On Debian based systems: 1176 | 1177 | ``` bash 1178 | sudo apt install libpam-pwquality 1179 | ``` 1180 | 1181 | 1. Make a backup of PAM's password configuration file `/etc/pam.d/common-password`: 1182 | 1183 | ``` bash 1184 | sudo cp --archive /etc/pam.d/common-password /etc/pam.d/common-password-COPY-$(date +"%Y%m%d%H%M%S") 1185 | ``` 1186 | 1187 | 1. Tell PAM to use libpam-pwquality to enforce strong passwords by editing the file `/etc/pam.d/common-password` and change the line that starts like this: 1188 | 1189 | ``` 1190 | password requisite pam_pwquality.so 1191 | ``` 1192 | 1193 | to this: 1194 | 1195 | ``` 1196 | password requisite pam_pwquality.so retry=3 minlen=10 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 maxrepeat=3 gecoschec 1197 | ``` 1198 | 1199 | The above options are: 1200 | 1201 | - `retry=3` = prompt user 3 times before returning with error. 1202 | - `minlen=10` = the minimum length of the password, factoring in any credits (or debits) from these: 1203 | - `dcredit=-1` = must have at least **one digit** 1204 | - `ucredit=-1` = must have at least **one upper case letter** 1205 | - `lcredit=-1` = must have at least **one lower case letter** 1206 | - `ocredit=-1` = must have at least **one non-alphanumeric character** 1207 | - `difok=3` = at least 3 characters from the new password cannot have been in the old password 1208 | - `maxrepeat=3` = allow a maximum of 3 repeated characters 1209 | - `gecoschec` = do not allow passwords with the account's name 1210 | 1211 | 1212 | [For the lazy](#editing-configuration-files---for-the-lazy): 1213 | 1214 | ``` bash 1215 | sudo sed -i -r -e "s/^(password\s+requisite\s+pam_pwquality.so)(.*)$/# \1\2 # commented by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")\n\1 retry=3 minlen=10 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 maxrepeat=3 gecoschec # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")/" /etc/pam.d/common-password 1216 | ``` 1217 | 1218 | ([Table of Contents](#table-of-contents)) 1219 | 1220 | ### Automatic Security Updates and Alerts 1221 | 1222 | #### Why 1223 | 1224 | It is important to keep a server updated with the latest **critical security patches and updates**. Otherwise you're at risk of known security vulnerabilities that bad-actors could use to gain unauthorized access to your server. 1225 | 1226 | Unless you plan on checking your server every day, you'll want a way to automatically update the system and/or get emails about available updates. 1227 | 1228 | You don't want to do all updates because with every update there is a risk of something breaking. It is important to do the critical updates but everything else can wait until you have time to do it manually. 1229 | 1230 | #### Why Not 1231 | 1232 | Automatic and unattended updates may break your system and you may not be near your server to fix it. This would be especially problematic if it broke your SSH access. 1233 | 1234 | #### Notes 1235 | 1236 | - Each distribution manages packages and updates differently. So far I only have steps for Debian based systems. 1237 | - Your server will need a way to send e-mails for this to work 1238 | 1239 | #### Goals 1240 | 1241 | - Automatic, unattended, updates of critical security patches 1242 | - Automatic emails of remaining pending updates 1243 | 1244 | #### Debian Based Systems 1245 | 1246 | ##### How It Works 1247 | 1248 | On Debian based systems you can use: 1249 | 1250 | - unattended-upgrades to automatically do system updates you want (i.e. critical security updates) 1251 | - apt-listchanges to get details about package changes before they are installed/upgraded 1252 | - apticron to get emails for pending package updates 1253 | 1254 | We will use unattended-upgrades to apply **critical security patches**. We can also apply stable updates since they've already been thoroughly tested by the Debian community. 1255 | 1256 | ##### References 1257 | 1258 | - https://wiki.debian.org/UnattendedUpgrades 1259 | - https://debian-handbook.info/browse/stable/sect.regular-upgrades.html 1260 | - https://blog.sleeplessbeastie.eu/2015/01/02/how-to-perform-unattended-upgrades/ 1261 | - https://www.vultr.com/docs/how-to-set-up-unattended-upgrades-on-debian-9-stretch 1262 | - https://github.com/mvo5/unattended-upgrades 1263 | - https://wiki.debian.org/UnattendedUpgrades#apt-listchanges 1264 | - https://www.cyberciti.biz/faq/apt-get-apticron-send-email-upgrades-available/ 1265 | - https://www.unixmen.com/how-to-get-email-notifications-for-new-updates-on-debianubuntu/ 1266 | - `/etc/apt/apt.conf.d/50unattended-upgrades` 1267 | 1268 | ##### Steps 1269 | 1270 | 1. Install unattended-upgrades, apt-listchanges, and apticron: 1271 | 1272 | ``` bash 1273 | sudo apt install unattended-upgrades apt-listchanges apticron 1274 | ``` 1275 | 1276 | 1. Now we need to configure unattended-upgrades to automatically apply the updates. This is typically done by editing the files `/etc/apt/apt.conf.d/20auto-upgrades` and `/etc/apt/apt.conf.d/50unattended-upgrades` that were created by the packages. However, because these file may get overwritten with a future update, we'll create a new file instead. Create the file `/etc/apt/apt.conf.d/51myunattended-upgrades` and add this: 1277 | 1278 | ``` 1279 | // Enable the update/upgrade script (0=disable) 1280 | APT::Periodic::Enable "1"; 1281 | 1282 | // Do "apt-get update" automatically every n-days (0=disable) 1283 | APT::Periodic::Update-Package-Lists "1"; 1284 | 1285 | // Do "apt-get upgrade --download-only" every n-days (0=disable) 1286 | APT::Periodic::Download-Upgradeable-Packages "1"; 1287 | 1288 | // Do "apt-get autoclean" every n-days (0=disable) 1289 | APT::Periodic::AutocleanInterval "7"; 1290 | 1291 | // Send report mail to root 1292 | // 0: no report (or null string) 1293 | // 1: progress report (actually any string) 1294 | // 2: + command outputs (remove -qq, remove 2>/dev/null, add -d) 1295 | // 3: + trace on APT::Periodic::Verbose "2"; 1296 | APT::Periodic::Unattended-Upgrade "1"; 1297 | 1298 | // Automatically upgrade packages from these 1299 | Unattended-Upgrade::Origins-Pattern { 1300 | "o=Debian,a=stable"; 1301 | "o=Debian,a=stable-updates"; 1302 | "origin=Debian,codename=${distro_codename},label=Debian-Security"; 1303 | }; 1304 | 1305 | // You can specify your own packages to NOT automatically upgrade here 1306 | Unattended-Upgrade::Package-Blacklist { 1307 | }; 1308 | 1309 | // Run dpkg --force-confold --configure -a if a unclean dpkg state is detected to true to ensure that updates get installed even when the system got interrupted during a previous run 1310 | Unattended-Upgrade::AutoFixInterruptedDpkg "true"; 1311 | 1312 | //Perform the upgrade when the machine is running because we wont be shutting our server down often 1313 | Unattended-Upgrade::InstallOnShutdown "false"; 1314 | 1315 | // Send an email to this address with information about the packages upgraded. 1316 | Unattended-Upgrade::Mail "root"; 1317 | 1318 | // Always send an e-mail 1319 | Unattended-Upgrade::MailOnlyOnError "false"; 1320 | 1321 | // Remove all unused dependencies after the upgrade has finished 1322 | Unattended-Upgrade::Remove-Unused-Dependencies "true"; 1323 | 1324 | // Remove any new unused dependencies after the upgrade has finished 1325 | Unattended-Upgrade::Remove-New-Unused-Dependencies "true"; 1326 | 1327 | // Automatically reboot WITHOUT CONFIRMATION if the file /var/run/reboot-required is found after the upgrade. 1328 | Unattended-Upgrade::Automatic-Reboot "true"; 1329 | 1330 | // Automatically reboot even if users are logged in. 1331 | Unattended-Upgrade::Automatic-Reboot-WithUsers "true"; 1332 | ``` 1333 | 1334 | **Notes**: 1335 | - Check `/usr/lib/apt/apt.systemd.daily` for details on the `APT::Periodic` options 1336 | - Check https://github.com/mvo5/unattended-upgrades for details on the `Unattended-Upgrade` options 1337 | 1338 | 1. Run a dry-run of unattended-upgrades to make sure your configuration file is okay: 1339 | 1340 | ``` bash 1341 | sudo unattended-upgrade -d --dry-run 1342 | ``` 1343 | 1344 | If everything is okay, you can let it run whenever it's scheduled to or force a run with `unattended-upgrade -d`. 1345 | 1346 | 1. Configure apt-listchanges to your liking: 1347 | 1348 | ``` bash 1349 | sudo dpkg-reconfigure apt-listchanges 1350 | ``` 1351 | 1352 | 1. For apticron, the default settings are good enough but you can check them in `/etc/apticron/apticron.conf` if you want to change them. For example, my configuration looks like this: 1353 | 1354 | > ``` 1355 | > EMAIL="root" 1356 | > NOTIFY_NO_UPDATES="1" 1357 | > ``` 1358 | 1359 | ([Table of Contents](#table-of-contents)) 1360 | 1361 | ### More Secure Random Entropy Pool (WIP) 1362 | 1363 | #### Why 1364 | 1365 | WIP 1366 | 1367 | #### How It Works 1368 | 1369 | WIP 1370 | 1371 | #### Goals 1372 | 1373 | WIP 1374 | 1375 | #### References 1376 | 1377 | - Thanks to [branneman](https://github.com/branneman) for this idea as submitted in [issue #33](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/33). 1378 | - https://hackaday.com/2017/11/02/what-is-entropy-and-how-do-i-get-more-of-it/ 1379 | - https://www.2uo.de/myths-about-urandom 1380 | - https://www.gnu.org/software/hurd/user/tlecarrour/rng-tools.html 1381 | - https://wiki.archlinux.org/index.php/Rng-tools 1382 | - https://www.howtoforge.com/helping-the-random-number-generator-to-gain-enough-entropy-with-rng-tools-debian-lenny 1383 | - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sect-security_guide-encryption-using_the_random_number_generator 1384 | 1385 | #### Steps 1386 | 1387 | 1. Install rng-tools. 1388 | 1389 | On Debian based systems: 1390 | 1391 | ``` bash 1392 | sudo apt-get install rng-tools 1393 | ``` 1394 | 1395 | 1. Now we need to set the hardware device used to generate random numbers by adding this to `/etc/default/rng-tools`: 1396 | 1397 | ``` 1398 | HRNGDEVICE=/dev/urandom 1399 | ``` 1400 | 1401 | [For the lazy](#editing-configuration-files---for-the-lazy): 1402 | 1403 | ``` bash 1404 | echo "HRNGDEVICE=/dev/urandom" | sudo tee -a /etc/default/rng-tools 1405 | ``` 1406 | 1407 | 1. Restart the service: 1408 | 1409 | ``` bash 1410 | sudo systemctl stop rng-tools.service 1411 | sudo systemctl start rng-tools.service 1412 | ``` 1413 | 1414 | 1. Test randomness: 1415 | - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sect-security_guide-encryption-using_the_random_number_generator 1416 | - https://wiki.archlinux.org/index.php/Rng-tools 1417 | 1418 | ([Table of Contents](#table-of-contents)) 1419 | 1420 | ### Add Panic/Secondary/Fake password Login Security System 1421 | 1422 | #### Why 1423 | 1424 | A nice tool to add extra password security, against physical attack (In-Person) Ramson/Rob/assault methods. 1425 | 1426 | #### How It Works 1427 | 1428 | The pamduress will add to the X user a secondary password (Panic password), when this password match will start run a script (this script do what you what the user do, when he logins with THESE panic password. 1429 | 1430 | Practical & real Example: 1431 | "Some Robber invade a home, and steal the server (containing IMPORTANT business backups, and ownlife memories and blablabla). Not exist any disk/boot encryption. Robber have start the server on their 'safe zone' and start an bruteforce attack. He have cracked the local password by SSH with from sudoer user 'admin' success, yeah a dummy password, not THE Strong one/primary. He starts SSH session/or physical session with that cracked dummy/panic password with 'admin' sudoer. He starts feeling the server seems too much busy in less than 2 minutes until to freeze.. 'wtf!?! lets reboot and continue steal info..'.. sorry friend. all data and system was destroyed.". 1432 | Conclusion, the robber cracked the dummy/panic/secondary password, and with this password its associated a script will do delete all files, config, system, boot and after than start charge the RAM and CPU to force robber reboot system. 1433 | 1434 | #### Goals 1435 | 1436 | Prevent access to malicious person to access server information when get an a password in force way (assault, gun, ransom, ...). Of course this is helpfull in other situations. 1437 | 1438 | #### References 1439 | 1440 | - Thanks to [nuvious](https://github.com/nuvious/pam-duress) for this tool 1441 | - Thanks to [hellresistor](https://gist.github.com/hellresistor/a4c542415a2d437e21afc235260d2366) for this Lazy-Tool-Script 1442 | 1443 | #### Steps 1444 | 1445 | 1. Run this (hellresistor Lazy-Tool-Script). 1446 | 1447 | ```` bash 1448 | #!/bin/bash 1449 | myownscript(){ 1450 | ####################################################### 1451 | ## ***** EDIT THIS SCRIPT TO YOUR PROPOSES *****# 1452 | 1453 | cat > "$ScriptFile" <<-EOF 1454 | #!/bin/bash 1455 | sudo rm -rf /home 1456 | #### FINISHED OWN SCRIPT #### 1457 | EOF 1458 | ####################################################### 1459 | } 1460 | echo "Lets Config a PANIC PASSWORD ;)" && sleep 1 1461 | read -r -p "Want you REALLY configure A PANIC PASSWORD?? Write [ OK ] : " PAMDUR 1462 | if [[ "$PAMDUR" = "OK" ]]; then 1463 | echo "Lets Config a PANIC USER, PASSWORD and SCRIPT ;)" && sleep 1 1464 | while [ -z "$PANICUSR" ] 1465 | do 1466 | read -r -p "WRITE a Panic User to your pam-duress user [ root ]: " PANICUSR 1467 | PANICUSR=${PANICUSR:=root} 1468 | done 1469 | if [ -z "$ScriptLoc" ]; then 1470 | read -r -p "SET Script Directory with FULL PATH [ /root/.duress ]: " ScriptLoc 1471 | ScriptLoc=${ScriptLoc:=/root/.duress} 1472 | ScriptFile="$ScriptLoc/PanicScript.sh" 1473 | fi 1474 | else 1475 | echo "NOT Use PAM DURESS aKa Panic Password!!! Bye" 1476 | exit 1 1477 | fi 1478 | 1479 | sudo apt install -y git build-essential libpam0g-dev libssl-dev 1480 | 1481 | cd "$HOME" || exit 1 1482 | git clone https://github.com/nuvious/pam-duress.git 1483 | cd pam-duress || exit 1 1484 | make 1485 | sudo make install 1486 | make clean 1487 | #make uninstall 1488 | 1489 | mkdir -p $ScriptLoc 1490 | sudo mkdir -p /etc/duress.d 1491 | myownscript 1492 | duress_sign $ScriptFile 1493 | chmod -R 500 $ScriptLoc 1494 | chmod 400 $ScriptLoc/*.sha256 1495 | chown -R $PANICUSR $ScriptLoc 1496 | 1497 | sudo cp --preserve /etc/pam.d/common-auth /etc/pam.d/common-auth.bck 1498 | 1499 | echo " 1500 | auth [success=2 default=ignore] pam_unix.so nullok_secure 1501 | auth [success=1 default=ignore] pam_duress.so 1502 | auth requisite pam_deny.so 1503 | auth required pam_permit.so 1504 | " | sudo tee /etc/pam.d/common-auth 1505 | 1506 | read -r -p "Press Key to Finish PAM DURESS Script!" 1507 | exit 0 1508 | ```` 1509 | 1510 | ([Table of Contents](#table-of-contents)) 1511 | 1512 | ## The Network 1513 | 1514 | ### Firewall With UFW (Uncomplicated Firewall) 1515 | 1516 | #### Why 1517 | 1518 | Call me paranoid, and you don't have to agree, but I want to deny all traffic in and out of my server except what I explicitly allow. Why would my server be sending traffic out that I don't know about? And why would external traffic be trying to access my server if I don't know who or what it is? When it comes to good security, my opinion is to reject/deny by default, and allow by exception. 1519 | 1520 | Of course, if you disagree, that is totally fine and can configure UFW to suit your needs. 1521 | 1522 | Either way, ensuring that only traffic we explicitly allow is the job of a firewall. 1523 | 1524 | #### How It Works 1525 | 1526 | The Linux kernel provides capabilities to monitor and control network traffic. These capabilities are exposed to the end-user through firewall utilities. On Linux, the most common firewall is [iptables](https://en.wikipedia.org/wiki/Iptables). However, iptables is rather complicated and confusing (IMHO). This is where UFW comes in. Think of UFW as a front-end to iptables. It simplifies the process of managing the iptables rules that tell the Linux kernel what to do with network traffic. 1527 | 1528 | **UFW** works by letting you configure rules that: 1529 | 1530 | - **allow** or **deny** 1531 | - **input** or **output** traffic 1532 | - **to** or **from** ports 1533 | 1534 | You can create rules by explicitly specifying the ports or with application configurations that specify the ports. 1535 | 1536 | #### Goals 1537 | 1538 | - all network traffic, input and output, blocked except those we explicitly allow 1539 | 1540 | #### Notes 1541 | 1542 | - As you install other programs, you'll need to enable the necessary ports/applications. 1543 | 1544 | #### References 1545 | 1546 | - https://launchpad.net/ufw 1547 | 1548 | #### Steps 1549 | 1550 | 1. Install ufw. 1551 | 1552 | On Debian based systems: 1553 | 1554 | ``` bash 1555 | sudo apt install ufw 1556 | ``` 1557 | 1558 | 1. Deny all outgoing traffic: 1559 | 1560 | ``` bash 1561 | sudo ufw default deny outgoing comment 'deny all outgoing traffic' 1562 | ``` 1563 | 1564 | > ``` 1565 | > Default outgoing policy changed to 'deny' 1566 | > (be sure to update your rules accordingly) 1567 | > ``` 1568 | 1569 | If you are not as paranoid as me, and don't want to deny all outgoing traffic, you can allow it instead: 1570 | 1571 | ``` bash 1572 | sudo ufw default allow outgoing comment 'allow all outgoing traffic' 1573 | ``` 1574 | 1575 | 1. Deny all incoming traffic: 1576 | 1577 | ``` bash 1578 | sudo ufw default deny incoming comment 'deny all incoming traffic' 1579 | ``` 1580 | 1581 | 1. Obviously we want SSH connections in: 1582 | 1583 | ``` bash 1584 | sudo ufw limit in ssh comment 'allow SSH connections in' 1585 | ``` 1586 | 1587 | > ``` 1588 | > Rules updated 1589 | > Rules updated (v6) 1590 | > ``` 1591 | 1592 | 1. Allow additional traffic as per your needs. Some common use-cases: 1593 | 1594 | ``` bash 1595 | # allow traffic out to port 53 -- DNS 1596 | sudo ufw allow out 53 comment 'allow DNS calls out' 1597 | 1598 | # allow traffic out to port 123 -- NTP 1599 | sudo ufw allow out 123 comment 'allow NTP out' 1600 | 1601 | # allow traffic out for HTTP, HTTPS, or FTP 1602 | # apt might needs these depending on which sources you're using 1603 | sudo ufw allow out http comment 'allow HTTP traffic out' 1604 | sudo ufw allow out https comment 'allow HTTPS traffic out' 1605 | sudo ufw allow out ftp comment 'allow FTP traffic out' 1606 | 1607 | # allow whois 1608 | sudo ufw allow out whois comment 'allow whois' 1609 | 1610 | # allow mails for status notifications -- choose port according to your provider 1611 | sudo ufw allow out 25 comment 'allow SMTP out' 1612 | sudo ufw allow out 587 comment 'allow SMTP out' 1613 | 1614 | # allow traffic out to port 68 -- the DHCP client 1615 | # you only need this if you're using DHCP 1616 | sudo ufw allow out 67 comment 'allow the DHCP client to update' 1617 | sudo ufw allow out 68 comment 'allow the DHCP client to update' 1618 | ``` 1619 | 1620 | **Note**: You'll need to allow HTTP/HTTPS for installing packages and many other things. 1621 | 1622 | 1. Start ufw: 1623 | 1624 | ``` bash 1625 | sudo ufw enable 1626 | ``` 1627 | 1628 | > ``` 1629 | > Command may disrupt existing ssh connections. Proceed with operation (y|n)? y 1630 | > Firewall is active and enabled on system startup 1631 | > ``` 1632 | 1633 | 1. If you want to see a status: 1634 | 1635 | ``` bash 1636 | sudo ufw status 1637 | ``` 1638 | 1639 | > ``` 1640 | > Status: active 1641 | > 1642 | > To Action From 1643 | > -- ------ ---- 1644 | > 22/tcp LIMIT Anywhere # allow SSH connections in 1645 | > 22/tcp (v6) LIMIT Anywhere (v6) # allow SSH connections in 1646 | > 1647 | > 53 ALLOW OUT Anywhere # allow DNS calls out 1648 | > 123 ALLOW OUT Anywhere # allow NTP out 1649 | > 80/tcp ALLOW OUT Anywhere # allow HTTP traffic out 1650 | > 443/tcp ALLOW OUT Anywhere # allow HTTPS traffic out 1651 | > 21/tcp ALLOW OUT Anywhere # allow FTP traffic out 1652 | > Mail submission ALLOW OUT Anywhere # allow mail out 1653 | > 43/tcp ALLOW OUT Anywhere # allow whois 1654 | > 53 (v6) ALLOW OUT Anywhere (v6) # allow DNS calls out 1655 | > 123 (v6) ALLOW OUT Anywhere (v6) # allow NTP out 1656 | > 80/tcp (v6) ALLOW OUT Anywhere (v6) # allow HTTP traffic out 1657 | > 443/tcp (v6) ALLOW OUT Anywhere (v6) # allow HTTPS traffic out 1658 | > 21/tcp (v6) ALLOW OUT Anywhere (v6) # allow FTP traffic out 1659 | > Mail submission (v6) ALLOW OUT Anywhere (v6) # allow mail out 1660 | > 43/tcp (v6) ALLOW OUT Anywhere (v6) # allow whois 1661 | > ``` 1662 | 1663 | or 1664 | 1665 | ``` bash 1666 | sudo ufw status verbose 1667 | ``` 1668 | 1669 | > ``` 1670 | > Status: active 1671 | > Logging: on (low) 1672 | > Default: deny (incoming), deny (outgoing), disabled (routed) 1673 | > New profiles: skip 1674 | > 1675 | > To Action From 1676 | > -- ------ ---- 1677 | > 22/tcp LIMIT IN Anywhere # allow SSH connections in 1678 | > 22/tcp (v6) LIMIT IN Anywhere (v6) # allow SSH connections in 1679 | > 1680 | > 53 ALLOW OUT Anywhere # allow DNS calls out 1681 | > 123 ALLOW OUT Anywhere # allow NTP out 1682 | > 80/tcp ALLOW OUT Anywhere # allow HTTP traffic out 1683 | > 443/tcp ALLOW OUT Anywhere # allow HTTPS traffic out 1684 | > 21/tcp ALLOW OUT Anywhere # allow FTP traffic out 1685 | > 587/tcp (Mail submission) ALLOW OUT Anywhere # allow mail out 1686 | > 43/tcp ALLOW OUT Anywhere # allow whois 1687 | > 53 (v6) ALLOW OUT Anywhere (v6) # allow DNS calls out 1688 | > 123 (v6) ALLOW OUT Anywhere (v6) # allow NTP out 1689 | > 80/tcp (v6) ALLOW OUT Anywhere (v6) # allow HTTP traffic out 1690 | > 443/tcp (v6) ALLOW OUT Anywhere (v6) # allow HTTPS traffic out 1691 | > 21/tcp (v6) ALLOW OUT Anywhere (v6) # allow FTP traffic out 1692 | > 587/tcp (Mail submission (v6)) ALLOW OUT Anywhere (v6) # allow mail out 1693 | > 43/tcp (v6) ALLOW OUT Anywhere (v6) # allow whois 1694 | > ``` 1695 | 1696 | 7. If you need to delete a rule 1697 | 1698 | ``` bash 1699 | sudo ufw status numbered 1700 | [...] 1701 | sudo ufw delete 3 #line number of the rule you want to delete 1702 | ``` 1703 | 1704 | #### Default Applications 1705 | 1706 | ufw ships with some default applications. You can see them with: 1707 | 1708 | ``` bash 1709 | sudo ufw app list 1710 | ``` 1711 | 1712 | > ``` 1713 | > Available applications: 1714 | > AIM 1715 | > Bonjour 1716 | > CIFS 1717 | > DNS 1718 | > Deluge 1719 | > IMAP 1720 | > IMAPS 1721 | > IPP 1722 | > KTorrent 1723 | > Kerberos Admin 1724 | > Kerberos Full 1725 | > Kerberos KDC 1726 | > Kerberos Password 1727 | > LDAP 1728 | > LDAPS 1729 | > LPD 1730 | > MSN 1731 | > MSN SSL 1732 | > Mail submission 1733 | > NFS 1734 | > OpenSSH 1735 | > POP3 1736 | > POP3S 1737 | > PeopleNearby 1738 | > SMTP 1739 | > SSH 1740 | > Socks 1741 | > Telnet 1742 | > Transmission 1743 | > Transparent Proxy 1744 | > VNC 1745 | > WWW 1746 | > WWW Cache 1747 | > WWW Full 1748 | > WWW Secure 1749 | > XMPP 1750 | > Yahoo 1751 | > qBittorrent 1752 | > svnserve 1753 | > ``` 1754 | 1755 | To get details about the app, like which ports it includes, type: 1756 | 1757 | ``` bash 1758 | sudo ufw app info [app name] 1759 | ``` 1760 | 1761 | > ``` bash 1762 | > sudo ufw app info DNS 1763 | > ``` 1764 | > 1765 | > ``` 1766 | > Profile: DNS 1767 | > Title: Internet Domain Name Server 1768 | > Description: Internet Domain Name Server 1769 | > 1770 | > Port: 1771 | > 53 1772 | > ``` 1773 | 1774 | #### Custom Application 1775 | 1776 | If you don't want to create rules by explicitly providing the port number(s), you can create your own application configurations. To do this, create a file in `/etc/ufw/applications.d`. 1777 | 1778 | For example, here is what you would use for [Plex](https://support.plex.tv/articles/201543147-what-network-ports-do-i-need-to-allow-through-my-firewall/): 1779 | 1780 | ``` bash 1781 | cat /etc/ufw/applications.d/plexmediaserver 1782 | ``` 1783 | 1784 | > ``` 1785 | > [PlexMediaServer] 1786 | > title=Plex Media Server 1787 | > description=This opens up PlexMediaServer for http (32400), upnp, and autodiscovery. 1788 | > ports=32469/tcp|32413/udp|1900/udp|32400/tcp|32412/udp|32410/udp|32414/udp|32400/udp 1789 | > ``` 1790 | 1791 | Then you can enable it like any other app: 1792 | 1793 | ```bash 1794 | sudo ufw allow plexmediaserver 1795 | ``` 1796 | 1797 | ([Table of Contents](#table-of-contents)) 1798 | 1799 | ### iptables Intrusion Detection And Prevention with PSAD 1800 | 1801 | #### Why 1802 | 1803 | Even if you have a firewall to guard your doors, it is possible to try brute-forcing your way in any of the guarded doors. We want to monitor all network activity to detect potential intrusion attempts, such has repeated attempts to get in, and block them. 1804 | 1805 | #### How It Works 1806 | 1807 | I can't explain it any better than user [FINESEC](https://serverfault.com/users/143961/finesec) from https://serverfault.com/ did at: https://serverfault.com/a/447604/289829. 1808 | 1809 | > Fail2BAN scans log files of various applications such as apache, ssh or ftp and automatically bans IPs that show the malicious signs such as automated login attempts. PSAD on the other hand scans iptables and ip6tables log messages (typically /var/log/messages) to detect and optionally block scans and other types of suspect traffic such as DDoS or OS fingerprinting attempts. It's ok to use both programs at the same time because they operate on different level. 1810 | 1811 | And, since we're already using [UFW](#ufw-uncomplicated-firewall) so we'll follow the awesome instructions by [netson](https://gist.github.com/netson) at https://gist.github.com/netson/c45b2dc4e835761fbccc to make PSAD work with UFW. 1812 | 1813 | #### References 1814 | 1815 | - http://www.cipherdyne.org/psad/ 1816 | - http://www.cipherdyne.org/psad/docs/config.html 1817 | - https://www.thefanclub.co.za/how-to/how-install-psad-intrusion-detection-ubuntu-1204-lts-server 1818 | - https://serverfault.com/a/447604/289829 1819 | - https://serverfault.com/a/770424/289829 1820 | - https://gist.github.com/netson/c45b2dc4e835761fbccc 1821 | - Thanks to [moltenbit](https://github.com/moltenbit) for catching the issue ([#61](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/61)) with `psadwatchd`. 1822 | 1823 | #### Steps 1824 | 1825 | 1. Install psad. 1826 | 1827 | On Debian based systems: 1828 | 1829 | ``` bash 1830 | sudo apt install psad 1831 | ``` 1832 | 1833 | 1. Make a backup of psad's configuration file `/etc/psad/psad.conf`: 1834 | 1835 | ``` bash 1836 | sudo cp --archive /etc/psad/psad.conf /etc/psad/psad.conf-COPY-$(date +"%Y%m%d%H%M%S") 1837 | ``` 1838 | 1839 | 1. Review and update configuration options in `/etc/psad/psad.conf`. Pay special attention to these: 1840 | 1841 | |Setting|Set To 1842 | |--|--| 1843 | |[`EMAIL_ADDRESSES`](http://www.cipherdyne.org/psad/docs/config.html#EMAIL_ADDRESSES)|your email address(s)| 1844 | |`HOSTNAME`|your server's hostname| 1845 | |`EXPECT_TCP_OPTIONS`|`EXPECT_TCP_OPTIONS Y;`| 1846 | |`ENABLE_PSADWATCHD`|`ENABLE_PSADWATCHD Y;`| 1847 | |[`ENABLE_AUTO_IDS`](http://www.cipherdyne.org/psad/docs/config.html#ENABLE_AUTO_IDS)|`ENABLE_AUTO_IDS Y;`| 1848 | |`ENABLE_AUTO_IDS_EMAILS`|`ENABLE_AUTO_IDS_EMAILS Y;`| 1849 | 1850 | Check the configuration file psad's documentation at http://www.cipherdyne.org/psad/docs/config.html for more details. 1851 | 1852 | 1. Now we need to make some changes to ufw so it works with psad by telling ufw to log all traffic so psad can analyze it. Do this by editing **two files** and adding these lines **at the end but before the COMMIT line**. 1853 | 1854 | Make backups: 1855 | 1856 | ``` bash 1857 | sudo cp --archive /etc/ufw/before.rules /etc/ufw/before.rules-COPY-$(date +"%Y%m%d%H%M%S") 1858 | sudo cp --archive /etc/ufw/before6.rules /etc/ufw/before6.rules-COPY-$(date +"%Y%m%d%H%M%S") 1859 | ``` 1860 | 1861 | Edit the files: 1862 | 1863 | - `/etc/ufw/before.rules` 1864 | - `/etc/ufw/before6.rules` 1865 | 1866 | And add add this **at the end but before the COMMIT line**: 1867 | 1868 | ``` 1869 | # log all traffic so psad can analyze 1870 | -A INPUT -j LOG --log-tcp-options --log-prefix "[IPTABLES] " 1871 | -A FORWARD -j LOG --log-tcp-options --log-prefix "[IPTABLES] " 1872 | ``` 1873 | 1874 | **Note**: We're adding a log prefix to all the iptables logs. We'll need this for [seperating iptables logs to their own file](#ns-separate-iptables-log-file). 1875 | 1876 | For example: 1877 | 1878 | > ``` 1879 | > ... 1880 | > 1881 | > # log all traffic so psad can analyze 1882 | > -A INPUT -j LOG --log-tcp-options --log-prefix "[IPTABLES] " 1883 | > -A FORWARD -j LOG --log-tcp-options --log-prefix "[IPTABLES] " 1884 | > 1885 | > # don't delete the 'COMMIT' line or these rules won't be processed 1886 | > COMMIT 1887 | > ``` 1888 | 1889 | 1. Now we need to reload/restart ufw and psad for the changes to take effect: 1890 | 1891 | ``` bash 1892 | sudo ufw reload 1893 | 1894 | sudo psad -R 1895 | sudo psad --sig-update 1896 | sudo psad -H 1897 | ``` 1898 | 1899 | 1. Analyze iptables rules for errors: 1900 | 1901 | ``` bash 1902 | sudo psad --fw-analyze 1903 | ``` 1904 | 1905 | > ``` 1906 | > [+] Parsing INPUT chain rules. 1907 | > [+] Parsing INPUT chain rules. 1908 | > [+] Firewall config looks good. 1909 | > [+] Completed check of firewall ruleset. 1910 | > [+] Results in /var/log/psad/fw_check 1911 | > [+] Exiting. 1912 | > ``` 1913 | 1914 | **Note**: If there were any issues you will get an e-mail with the error. 1915 | 1916 | 1. Check the status of psad: 1917 | 1918 | ``` bash 1919 | sudo psad --Status 1920 | ``` 1921 | 1922 | > ``` 1923 | > [-] psad: pid file /var/run/psad/psadwatchd.pid does not exist for psadwatchd on vm 1924 | > [+] psad_fw_read (pid: 3444) %CPU: 0.0 %MEM: 2.2 1925 | > Running since: Sat Feb 16 01:03:09 2019 1926 | > 1927 | > [+] psad (pid: 3435) %CPU: 0.2 %MEM: 2.7 1928 | > Running since: Sat Feb 16 01:03:09 2019 1929 | > Command line arguments: [none specified] 1930 | > Alert email address(es): root@localhost 1931 | > 1932 | > [+] Version: psad v2.4.3 1933 | > 1934 | > [+] Top 50 signature matches: 1935 | > [NONE] 1936 | > 1937 | > [+] Top 25 attackers: 1938 | > [NONE] 1939 | > 1940 | > [+] Top 20 scanned ports: 1941 | > [NONE] 1942 | > 1943 | > [+] iptables log prefix counters: 1944 | > [NONE] 1945 | > 1946 | > Total protocol packet counters: 1947 | > 1948 | > [+] IP Status Detail: 1949 | > [NONE] 1950 | > 1951 | > Total scan sources: 0 1952 | > Total scan destinations: 0 1953 | > 1954 | > [+] These results are available in: /var/log/psad/status.out 1955 | > ``` 1956 | 1957 | ([Table of Contents](#table-of-contents)) 1958 | 1959 | ### Application Intrusion Detection And Prevention With Fail2Ban 1960 | 1961 | #### Why 1962 | 1963 | UFW tells your server what doors to board up so nobody can see them, and what doors to allow authorized users through. PSAD monitors network activity to detect and prevent potential intrusions -- repeated attempts to get in. 1964 | 1965 | But what about the applications/services your server is running, like SSH and Apache, where your firewall is configured to allow access in. Even though access may be allowed that doesn't mean all access attempts are valid and harmless. What if someone tries to brute-force their way in to a web-app you're running on your server? This is where Fail2ban comes in. 1966 | 1967 | #### How It Works 1968 | 1969 | Fail2ban monitors the logs of your applications (like SSH and Apache) to detect and prevent potential intrusions. It will monitor network traffic/logs and prevent intrusions by blocking suspicious activity (e.g. multiple successive failed connections in a short time-span). 1970 | 1971 | #### Goals 1972 | 1973 | - network monitoring for suspicious activity with automatic banning of offending IPs 1974 | 1975 | #### Notes 1976 | 1977 | - As of right now, the only thing running on this server is SSH so we'll want Fail2ban to monitor SSH and ban as necessary. 1978 | - As you install other programs, you'll need to create/configure the appropriate jails and enable them. 1979 | 1980 | #### References 1981 | 1982 | - https://www.fail2ban.org/ 1983 | - https://blog.vigilcode.com/2011/05/ufw-with-fail2ban-quick-secure-setup-part-ii/ 1984 | - https://dodwell.us/security/ufw-fail2ban-portscan.html 1985 | - https://www.howtoforge.com/community/threads/fail2ban-and-ufw-on-debian.77261/ 1986 | 1987 | #### Steps 1988 | 1989 | 1. Install fail2ban. 1990 | 1991 | On Debian based systems: 1992 | 1993 | ``` bash 1994 | sudo apt install fail2ban 1995 | ``` 1996 | 1997 | 1. We don't want to edit `/etc/fail2ban/fail2ban.conf` or `/etc/fail2ban/jail.conf` because a future update may overwrite those so we'll create a local copy instead. Create the file `/etc/fail2ban/jail.local` and add this to it after replacing `[LAN SEGMENT]` and `[your email]` with the appropriate values: 1998 | 1999 | ``` 2000 | [DEFAULT] 2001 | # the IP address range we want to ignore 2002 | ignoreip = 127.0.0.1/8 [LAN SEGMENT] 2003 | 2004 | # who to send e-mail to 2005 | destemail = [your e-mail] 2006 | 2007 | # who is the email from 2008 | sender = [your e-mail] 2009 | 2010 | # since we're using exim4 to send emails 2011 | mta = mail 2012 | 2013 | # get email alerts 2014 | action = %(action_mwl)s 2015 | ``` 2016 | 2017 | **Note**: Your server will need to be able to send e-mails so Fail2ban can let you know of suspicious activity and when it banned an IP. 2018 | 2019 | 1. We need to create a jail for SSH that tells fail2ban to look at SSH logs and use ufw to ban/unban IPs as needed. Create a jail for SSH by creating the file `/etc/fail2ban/jail.d/ssh.local` and adding this to it: 2020 | 2021 | ``` 2022 | [sshd] 2023 | enabled = true 2024 | banaction = ufw 2025 | port = ssh 2026 | filter = sshd 2027 | logpath = %(sshd_log)s 2028 | maxretry = 5 2029 | ``` 2030 | 2031 | [For the lazy](#editing-configuration-files---for-the-lazy): 2032 | 2033 | ``` bash 2034 | cat << EOF | sudo tee /etc/fail2ban/jail.d/ssh.local 2035 | [sshd] 2036 | enabled = true 2037 | banaction = ufw 2038 | port = ssh 2039 | filter = sshd 2040 | logpath = %(sshd_log)s 2041 | maxretry = 5 2042 | EOF 2043 | ``` 2044 | 2045 | 1. In the above we tell fail2ban to use the ufw as the `banaction`. Fail2ban ships with an action configuration file for ufw. You can see it in `/etc/fail2ban/action.d/ufw.conf` 2046 | 2047 | 1. Enable fail2ban: 2048 | 2049 | ``` bash 2050 | sudo fail2ban-client start 2051 | sudo fail2ban-client reload 2052 | sudo fail2ban-client add sshd # This may fail on some systems if the sshd jail was added by default 2053 | ``` 2054 | 2055 | 1. To check the status: 2056 | 2057 | ``` bash 2058 | sudo fail2ban-client status 2059 | ``` 2060 | 2061 | > ``` 2062 | > Status 2063 | > |- Number of jail: 1 2064 | > `- Jail list: sshd 2065 | > ``` 2066 | 2067 | ``` bash 2068 | sudo fail2ban-client status sshd 2069 | ``` 2070 | 2071 | > ``` 2072 | > Status for the jail: sshd 2073 | > |- Filter 2074 | > | |- Currently failed: 0 2075 | > | |- Total failed: 0 2076 | > | `- File list: /var/log/auth.log 2077 | > `- Actions 2078 | > |- Currently banned: 0 2079 | > |- Total banned: 0 2080 | > `- Banned IP list: 2081 | > ``` 2082 | 2083 | #### Custom Jails 2084 | 2085 | I have not needed to create a custom jail yet. Once I do, and I figure out how, I will update this guide. Or, if you know how please help [contribute](#contributing). 2086 | 2087 | #### Unban an IP 2088 | 2089 | To unban an IP use this command: 2090 | 2091 | ``` bash 2092 | fail2ban-client set [jail] unbanip [IP] 2093 | ``` 2094 | 2095 | `[jail]` is the name of the jail that has the banned IP and `[IP]` is the IP address you want to unban. For example, to unaban `192.168.1.100` from SSH you would do: 2096 | 2097 | ``` bash 2098 | fail2ban-client set sshd unbanip 192.168.1.100 2099 | ``` 2100 | 2101 | ([Table of Contents](#table-of-contents)) 2102 | 2103 | ### Application Intrusion Detection And Prevention With CrowdSec 2104 | 2105 | #### Why 2106 | 2107 | UFW tells your server what doors to board up so nobody can see them, and what doors to allow authorized users through. PSAD monitors network activity to detect and prevent potential intrusions -- repeated attempts to get in. 2108 | 2109 | CrowdSec is similar to Fail2Ban in that it monitors the logs of your applications (like SSH and Apache) to detect and prevent potential intrusions. However, CrowdSec is coupled with a community that shares threat intelligence back to CrowdSec to then distribute a Community Blocklist to all users. 2110 | 2111 | #### How It Works 2112 | 2113 | CrowdSec monitors the logs of your applications (like SSH and Apache) to detect and prevent potential intrusions. It will monitor network traffic/logs and prevent intrusions by blocking suspicious activity (e.g. multiple successive failed connections in a short time-span). Once a malicious IP is detected, it will be added to your local decision list and threat information is shared with CrowdSec to update the Community Blocklist on malicious IP addresses. Once an IP address hits a certain threshold of malicious activity, it will be automatically propogated to all other CrowdSec users to proactively block. 2114 | 2115 | #### Goals 2116 | 2117 | - network monitoring for suspicious activity with automatic banning of offending IPs 2118 | 2119 | #### Notes 2120 | 2121 | - As of right now, the only thing running on this server is SSH so we'll want CrowdSec to monitor SSH and ban as necessary. 2122 | - As you install other programs, you'll need to install additional collections and configure the appropriate acquisitions. 2123 | 2124 | #### References 2125 | 2126 | - https://www.crowdsec.net/ 2127 | - [Read how CrowdSec curates the Community Blocklist](https://www.crowdsec.net/our-data) 2128 | - [Read what threat intelligence is shared with CrowdSec](https://docs.crowdsec.net/docs/next/central_api/intro#signal-meta-data) 2129 | - https://docs.crowdsec.net/ 2130 | 2131 | #### Steps 2132 | 2133 | 1. Install CrowdSec Security Engine. (IDS) 2134 | 2135 | On any linux distro (including Debian based systems) 2136 | 2137 | Install the CrowdSec repository: 2138 | ``` bash 2139 | curl -s https://install.crowdsec.net | sudo sh 2140 | ``` 2141 | 2142 | Install the CrowdSec Security Engine: 2143 | ``` bash 2144 | sudo apt install crowdsec 2145 | ``` 2146 | 2147 | > [!TIP] 2148 | > if `curl | sh` is not your thing, you can find additional install methods [here](https://docs.crowdsec.net/u/getting_started/installation/linux). 2149 | 2150 | By default whilst CrowdSec is installing the Security Engine it will auto-discover your installed applications and install the appropriate parsers and scenarios for them. Since we know most Linux servers are running ssh out of the box CrowdSec will automatically configured this for you. 2151 | 2152 | 2. Install a Remediation Component. (IPS) 2153 | 2154 | CrowdSec by itself is a detection engine, since in most modern infrastructures you may have an upstream firewall or WAF, CrowdSec will not block the IP addresses by itself. You can install a Remediation Component to block the IP addresses detected by CrowdSec. 2155 | ```bash 2156 | sudo apt install crowdsec-firewall-bouncer-iptables 2157 | ``` 2158 | 2159 | > [!TIP] 2160 | > If your installation of UFW is not using `iptables` as the backend, you can alternatively install `crowdsec-firewall-bouncer-nftables`. There is no difference in the installed binaries, only the configuration file is different. 2161 | 2162 | By default whilst the Remediation Component is installing it will auto-configure the necessary settings to work with the Security Engine if deployed on the same host (and if the security engine is not within a container environment). 2163 | 2164 | 3. Check detection and remediation is working as intended: 2165 | 2166 | CrowdSec package comes with a CLI tool to check the status of the Security Engine and the Remediation Component. 2167 | 2168 | ```bash 2169 | sudo cscli metrics 2170 | ``` 2171 | 2172 | ```bash 2173 | Acquisition Metrics: 2174 | ╭────────────────────────┬────────────┬──────────────┬────────────────┬────────────────────────┬───────────────────╮ 2175 | │ Source │ Lines read │ Lines parsed │ Lines unparsed │ Lines poured to bucket │ Lines whitelisted │ 2176 | ├────────────────────────┼────────────┼──────────────┼────────────────┼────────────────────────┼───────────────────┤ 2177 | │ file:/var/log/auth.log │ 5 │ 4 │ 1 │ 10 │ - │ 2178 | │ file:/var/log/syslog │ 30 │ - │ 30 │ - │ - │ 2179 | ╰────────────────────────┴────────────┴──────────────┴────────────────┴────────────────────────┴───────────────────╯ 2180 | 2181 | Local API Decisions: 2182 | ╭────────────────────────────────────────────┬────────┬────────┬───────╮ 2183 | │ Reason │ Origin │ Action │ Count │ 2184 | ├────────────────────────────────────────────┼────────┼────────┼───────┤ 2185 | │ crowdsecurity/http-backdoors-attempts │ CAPI │ ban │ 73 │ 2186 | │ crowdsecurity/http-bad-user-agent │ CAPI │ ban │ 4836 │ 2187 | │ crowdsecurity/http-path-traversal-probing │ CAPI │ ban │ 87 │ 2188 | │ crowdsecurity/http-probing │ CAPI │ ban │ 2010 │ 2189 | │ crowdsecurity/thinkphp-cve-2018-20062 │ CAPI │ ban │ 88 │ 2190 | │ crowdsecurity/CVE-2019-18935 │ CAPI │ ban │ 7 │ 2191 | │ crowdsecurity/CVE-2023-49103 │ CAPI │ ban │ 5 │ 2192 | │ crowdsecurity/http-admin-interface-probing │ CAPI │ ban │ 91 │ 2193 | │ ltsich/http-w00tw00t │ CAPI │ ban │ 3 │ 2194 | │ crowdsecurity/apache_log4j2_cve-2021-44228 │ CAPI │ ban │ 18 │ 2195 | │ crowdsecurity/nginx-req-limit-exceeded │ CAPI │ ban │ 280 │ 2196 | │ crowdsecurity/ssh-slow-bf │ CAPI │ ban │ 3412 │ 2197 | │ crowdsecurity/spring4shell_cve-2022-22965 │ CAPI │ ban │ 1 │ 2198 | │ crowdsecurity/ssh-cve-2024-6387 │ CAPI │ ban │ 24 │ 2199 | │ crowdsecurity/CVE-2023-22515 │ CAPI │ ban │ 2 │ 2200 | │ crowdsecurity/http-cve-2021-41773 │ CAPI │ ban │ 172 │ 2201 | │ crowdsecurity/netgear_rce │ CAPI │ ban │ 14 │ 2202 | │ crowdsecurity/ssh-bf │ CAPI │ ban │ 2000 │ 2203 | │ crowdsecurity/CVE-2022-35914 │ CAPI │ ban │ 1 │ 2204 | │ crowdsecurity/http-cve-2021-42013 │ CAPI │ ban │ 2 │ 2205 | │ crowdsecurity/jira_cve-2021-26086 │ CAPI │ ban │ 9 │ 2206 | │ crowdsecurity/http-sensitive-files │ CAPI │ ban │ 166 │ 2207 | │ crowdsecurity/http-wordpress-scan │ CAPI │ ban │ 272 │ 2208 | │ crowdsecurity/CVE-2022-26134 │ CAPI │ ban │ 5 │ 2209 | │ crowdsecurity/http-generic-bf │ CAPI │ ban │ 7 │ 2210 | │ crowdsecurity/http-open-proxy │ CAPI │ ban │ 948 │ 2211 | │ crowdsecurity/http-crawl-non_statics │ CAPI │ ban │ 339 │ 2212 | │ crowdsecurity/http-cve-probing │ CAPI │ ban │ 5 │ 2213 | │ crowdsecurity/CVE-2017-9841 │ CAPI │ ban │ 117 │ 2214 | │ crowdsecurity/CVE-2022-37042 │ CAPI │ ban │ 1 │ 2215 | │ crowdsecurity/fortinet-cve-2018-13379 │ CAPI │ ban │ 5 │ 2216 | ╰────────────────────────────────────────────┴────────┴────────┴───────╯ 2217 | 2218 | Local API Metrics: 2219 | ╭──────────────────────┬────────┬──────╮ 2220 | │ Route │ Method │ Hits │ 2221 | ├──────────────────────┼────────┼──────┤ 2222 | │ /v1/alerts │ GET │ 2 │ 2223 | │ /v1/decisions/stream │ GET │ 5 │ 2224 | │ /v1/usage-metrics │ POST │ 2 │ 2225 | │ /v1/watchers/login │ POST │ 4 │ 2226 | ╰──────────────────────┴────────┴──────╯ 2227 | 2228 | Local API Bouncers Metrics: 2229 | ╭────────────────────────────────┬──────────────────────┬────────┬──────╮ 2230 | │ Bouncer │ Route │ Method │ Hits │ 2231 | ├────────────────────────────────┼──────────────────────┼────────┼──────┤ 2232 | │ cs-firewall-bouncer-1729025592 │ /v1/decisions/stream │ GET │ 5 │ 2233 | ╰────────────────────────────────┴──────────────────────┴────────┴──────╯ 2234 | 2235 | Local API Machines Metrics: 2236 | ╭──────────────────────────────────────────────────┬────────────┬────────┬──────╮ 2237 | │ Machine │ Route │ Method │ Hits │ 2238 | ├──────────────────────────────────────────────────┼────────────┼────────┼──────┤ 2239 | │ │ /v1/alerts │ GET │ 2 │ 2240 | ╰──────────────────────────────────────────────────┴────────────┴────────┴──────╯ 2241 | 2242 | Parser Metrics: 2243 | ╭─────────────────────────────────┬──────┬────────┬──────────╮ 2244 | │ Parsers │ Hits │ Parsed │ Unparsed │ 2245 | ├─────────────────────────────────┼──────┼────────┼──────────┤ 2246 | │ child-crowdsecurity/sshd-logs │ 41 │ 4 │ 37 │ 2247 | │ child-crowdsecurity/syslog-logs │ 35 │ 35 │ - │ 2248 | │ crowdsecurity/dateparse-enrich │ 4 │ 4 │ - │ 2249 | │ crowdsecurity/sshd-logs │ 5 │ 4 │ 1 │ 2250 | │ crowdsecurity/syslog-logs │ 35 │ 35 │ - │ 2251 | ╰─────────────────────────────────┴──────┴────────┴──────────╯ 2252 | 2253 | Scenario Metrics: 2254 | ╭─────────────────────────────────────┬───────────────┬───────────┬──────────────┬────────┬─────────╮ 2255 | │ Scenario │ Current Count │ Overflows │ Instantiated │ Poured │ Expired │ 2256 | ├─────────────────────────────────────┼───────────────┼───────────┼──────────────┼────────┼─────────┤ 2257 | │ crowdsecurity/ssh-bf │ 1 │ - │ 1 │ 4 │ - │ 2258 | │ crowdsecurity/ssh-bf_user-enum │ 1 │ - │ 1 │ 1 │ - │ 2259 | │ crowdsecurity/ssh-slow-bf │ 1 │ - │ 1 │ 4 │ - │ 2260 | │ crowdsecurity/ssh-slow-bf_user-enum │ 1 │ - │ 1 │ 1 │ - │ 2261 | ╰─────────────────────────────────────┴───────────────┴───────────┴──────────────┴────────┴─────────╯ 2262 | ``` 2263 | 2264 | The above output can be daunting, but it's a good way to check that the Security Engine is reading logs and the Remediation Component is blocking IP addresses. So a quick breakdown of each section: 2265 | 2266 | - **Acquisition Metrics**: This section shows the logs that the Security Engine is reading and parsing. If you see logs in the `Lines unparsed` column, it means the Security Engine is not able to parse the logs. This could be due to a misconfiguration or the logs are not in the expected format. 2267 | - **Local API Decisions**: This section shows the decisions that the Security Engine has within the datbase. If you see logs in the `Count` column, it means the Security Engine has detected malicious activity and has blocked the IP address. 2268 | - Orgin: This is where the decision came from. In this case, it's from the Central API (CAPI). 2269 | - **Local API Metrics**: This section shows the number of hits to the Local API. This is the API that the Security Engine uses to communicate with the Remediation Component. 2270 | - **Local API Bouncers Metrics**: This section shows the number of hits to the Local API by the Remediation Component. 2271 | - **Local API Machines Metrics**: This section shows the number of hits to the Local API by the Security Engine (if you run multiple Security Engine in a centralized setup you can see multiple ID's here). 2272 | - **Parser Metrics**: This section shows the parsers that are being used by the Security Engine. If you see logs in the `Unparsed` column, it means the Security Engine is not able to parse the logs. This could be due to a misconfiguration or the logs are not in the expected format. 2273 | - **Scenario Metrics**: This section shows the scenarios that are being used by the Security Engine. If you see logs in the `Current Count` column, it means the Security Engine has detected malicious activity and is tracking the IP address. 2274 | 2275 | #### Unban an IP 2276 | 2277 | To unban an IP use this command: 2278 | 2279 | ``` bash 2280 | cscli decisions delete --ip [IP] 2281 | ``` 2282 | 2283 | `[IP]` is the IP address you want to unban. For example, to unban `192.168.1.100` from SSH you would do: 2284 | 2285 | ``` bash 2286 | cscli decisions delete --ip 192.168.1.100 2287 | ``` 2288 | 2289 | ## The Auditing 2290 | 2291 | ### File/Folder Integrity Monitoring With AIDE (WIP) 2292 | 2293 | #### Why 2294 | 2295 | WIP 2296 | 2297 | #### How It Works 2298 | 2299 | WIP 2300 | 2301 | #### Goals 2302 | 2303 | WIP 2304 | 2305 | #### References 2306 | 2307 | - https://aide.github.io/ 2308 | - https://www.hiroom2.com/2017/06/09/debian-8-file-integrity-check-with-aide/ 2309 | - https://blog.rapid7.com/2017/06/30/how-to-install-and-configure-aide-on-ubuntu-linux/ 2310 | - https://www.stephenrlang.com/2016/03/using-aide-for-file-integrity-monitoring-fim-on-ubuntu/ 2311 | - https://www.howtoforge.com/how-to-configure-the-aide-advanced-intrusion-detection-environment-file-integrity-scanner-for-your-website 2312 | - https://www.tecmint.com/check-integrity-of-file-and-directory-using-aide-in-linux/ 2313 | - https://www.cyberciti.biz/faq/debian-ubuntu-linux-software-integrity-checking-with-aide/ 2314 | - https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/83 2315 | 2316 | #### Steps 2317 | 2318 | 1. Install AIDE. 2319 | 2320 | On Debian based systems: 2321 | 2322 | ``` bash 2323 | sudo apt install aide aide-common 2324 | ``` 2325 | 2326 | 1. Make a backup of AIDE's defaults file: 2327 | 2328 | ``` bash 2329 | sudo cp -p /etc/default/aide /etc/default/aide-COPY-$(date +"%Y%m%d%H%M%S") 2330 | ``` 2331 | 2332 | 1. Go through `/etc/default/aide` and set AIDE's defaults per your requirements. If you want AIDE to run daily and e-mail you, be sure to set `CRON_DAILY_RUN` to `yes`. 2333 | 2334 | 1. Make a backup of AIDE's configuration files: 2335 | 2336 | ``` bash 2337 | sudo cp -pr /etc/aide /etc/aide-COPY-$(date +"%Y%m%d%H%M%S") 2338 | ``` 2339 | 2340 | 1. On Debian based systems: 2341 | 2342 | - AIDE's configuration files are in `/etc/aide/aide.conf.d/`. 2343 | - You'll want to go through AIDE's documentation and the configuration files in to set them per your requirements. 2344 | - If you want new settings, to monitor a new folder for example, you'll want to add them to `/etc/aide/aide.conf` or `/etc/aide/aide.conf.d/`. 2345 | - Take a backup of the stock configuration files: `sudo cp -pr /etc/aide /etc/aide-COPY-$(date +"%Y%m%d%H%M%S")`. 2346 | 2347 | 1. Create a new database, and install it. 2348 | 2349 | On Debian based systems: 2350 | 2351 | ``` bash 2352 | sudo aideinit 2353 | ``` 2354 | 2355 | > ``` 2356 | > Running aide --init... 2357 | > Start timestamp: 2019-04-01 21:23:37 -0400 (AIDE 0.16) 2358 | > AIDE initialized database at /var/lib/aide/aide.db.new 2359 | > Verbose level: 6 2360 | > 2361 | > Number of entries: 25973 2362 | > 2363 | > --------------------------------------------------- 2364 | > The attributes of the (uncompressed) database(s): 2365 | > --------------------------------------------------- 2366 | > 2367 | > /var/lib/aide/aide.db.new 2368 | > RMD160 : moyQ1YskQQbidX+Lusv3g2wf1gQ= 2369 | > TIGER : 7WoOgCrXzSpDrlO6I3PyXPj1gRiaMSeo 2370 | > SHA256 : gVx8Fp7r3800WF2aeXl+/KHCzfGsNi7O 2371 | > g16VTPpIfYQ= 2372 | > SHA512 : GYfa0DJwWgMLl4Goo5VFVOhu4BphXCo3 2373 | > rZnk49PYztwu50XjaAvsVuTjJY5uIYrG 2374 | > tV+jt3ELvwFzGefq4ZBNMg== 2375 | > CRC32 : /cusZw== 2376 | > HAVAL : E/i5ceF3YTjwenBfyxHEsy9Kzu35VTf7 2377 | > CPGQSW4tl14= 2378 | > GOST : n5Ityzxey9/1jIs7LMc08SULF1sLBFUc 2379 | > aMv7Oby604A= 2380 | > 2381 | > 2382 | > End timestamp: 2019-04-01 21:24:45 -0400 (run time: 1m 8s) 2383 | > ``` 2384 | 2385 | 1. Test everything works with no changes. 2386 | 2387 | On Debian based systems: 2388 | 2389 | ``` bash 2390 | sudo aide.wrapper --check 2391 | ``` 2392 | 2393 | > ``` 2394 | > Start timestamp: 2019-04-01 21:24:45 -0400 (AIDE 0.16) 2395 | > AIDE found NO differences between database and filesystem. Looks okay!! 2396 | > Verbose level: 6 2397 | > 2398 | > Number of entries: 25973 2399 | > 2400 | > --------------------------------------------------- 2401 | > The attributes of the (uncompressed) database(s): 2402 | > --------------------------------------------------- 2403 | > 2404 | > /var/lib/aide/aide.db 2405 | > RMD160 : moyQ1YskQQbidX+Lusv3g2wf1gQ= 2406 | > TIGER : 7WoOgCrXzSpDrlO6I3PyXPj1gRiaMSeo 2407 | > SHA256 : gVx8Fp7r3800WF2aeXl+/KHCzfGsNi7O 2408 | > g16VTPpIfYQ= 2409 | > SHA512 : GYfa0DJwWgMLl4Goo5VFVOhu4BphXCo3 2410 | > rZnk49PYztwu50XjaAvsVuTjJY5uIYrG 2411 | > tV+jt3ELvwFzGefq4ZBNMg== 2412 | > CRC32 : /cusZw== 2413 | > HAVAL : E/i5ceF3YTjwenBfyxHEsy9Kzu35VTf7 2414 | > CPGQSW4tl14= 2415 | > GOST : n5Ityzxey9/1jIs7LMc08SULF1sLBFUc 2416 | > aMv7Oby604A= 2417 | > 2418 | > 2419 | > End timestamp: 2019-04-01 21:26:03 -0400 (run time: 1m 18s) 2420 | > ``` 2421 | 2422 | 1. Test everything works after making some changes. 2423 | 2424 | On Debian based systems: 2425 | 2426 | ``` bash 2427 | sudo touch /etc/test.sh 2428 | sudo touch /root/test.sh 2429 | 2430 | sudo aide.wrapper --check 2431 | 2432 | sudo rm /etc/test.sh 2433 | sudo rm /root/test.sh 2434 | 2435 | sudo aideinit -y -f 2436 | ``` 2437 | 2438 | > ``` 2439 | > Start timestamp: 2019-04-01 21:37:37 -0400 (AIDE 0.16) 2440 | > AIDE found differences between database and filesystem!! 2441 | > Verbose level: 6 2442 | > 2443 | > Summary: 2444 | > Total number of entries: 25972 2445 | > Added entries: 2 2446 | > Removed entries: 0 2447 | > Changed entries: 1 2448 | > 2449 | > --------------------------------------------------- 2450 | > Added entries: 2451 | > --------------------------------------------------- 2452 | > 2453 | > f++++++++++++++++: /etc/test.sh 2454 | > f++++++++++++++++: /root/test.sh 2455 | > 2456 | > --------------------------------------------------- 2457 | > Changed entries: 2458 | > --------------------------------------------------- 2459 | > 2460 | > d =.... mc.. .. .: /root 2461 | > 2462 | > --------------------------------------------------- 2463 | > Detailed information about changes: 2464 | > --------------------------------------------------- 2465 | > 2466 | > Directory: /root 2467 | > Mtime : 2019-04-01 21:35:07 -0400 | 2019-04-01 21:37:36 -0400 2468 | > Ctime : 2019-04-01 21:35:07 -0400 | 2019-04-01 21:37:36 -0400 2469 | > 2470 | > 2471 | > --------------------------------------------------- 2472 | > The attributes of the (uncompressed) database(s): 2473 | > --------------------------------------------------- 2474 | > 2475 | > /var/lib/aide/aide.db 2476 | > RMD160 : qF9WmKaf2PptjKnhcr9z4ueCPTY= 2477 | > TIGER : zMo7MvvYJcq1hzvTQLPMW7ALeFiyEqv+ 2478 | > SHA256 : LSLLVjjV6r8vlSxlbAbbEsPcQUB48SgP 2479 | > pdVqEn6ZNbQ= 2480 | > SHA512 : Qc4U7+ZAWCcitapGhJ1IrXCLGCf1IKZl 2481 | > 02KYL1gaZ0Fm4dc7xLqjiquWDMSEbwzW 2482 | > oz49NCquqGz5jpMIUy7UxA== 2483 | > CRC32 : z8ChEA== 2484 | > HAVAL : YapzS+/cdDwLj3kHJEq8fufLp3DPKZDg 2485 | > U12KCSkrO7Y= 2486 | > GOST : 74sLV4HkTig+GJhokvxZQm7CJD/NR0mG 2487 | > 6jV7zdt5AXQ= 2488 | > 2489 | > 2490 | > End timestamp: 2019-04-01 21:38:50 -0400 (run time: 1m 13s) 2491 | > ``` 2492 | 2493 | 1. That's it. If you set `CRON_DAILY_RUN` to `yes` in `/etc/default/aide` then cron will execute `/etc/cron.daily/aide` every day and e-mail you the output. 2494 | 2495 | #### Updating The Database 2496 | 2497 | Every time you make changes to files/folders that AIDE monitors, you will need to update the database to capture those changes. To do that on Debian based systems: 2498 | 2499 | ``` bash 2500 | sudo aideinit -y -f 2501 | ``` 2502 | 2503 | ([Table of Contents](#table-of-contents)) 2504 | 2505 | ### Anti-Virus Scanning With ClamAV (WIP) 2506 | 2507 | #### Why 2508 | 2509 | WIP 2510 | 2511 | #### How It Works 2512 | 2513 | - ClamAV is a virus scanner 2514 | - ClamAV-Freshclam is a service that keeps the virus definitions updated 2515 | - ClamAV-Daemon keeps the `clamd` process running to make scanning faster 2516 | 2517 | #### Goals 2518 | 2519 | WIP 2520 | 2521 | #### Notes 2522 | 2523 | - These instructions **do not** tell you how to enable the ClamAV daemon service to ensure `clamd` is running all the time. `clamd` is only if you're running a mail server and does not provide real-time monitoring of files. Instead, you'd want to scan files manually or on a schedule. 2524 | 2525 | #### References 2526 | 2527 | - https://www.clamav.net/documents/installation-on-debian-and-ubuntu-linux-distributions 2528 | - https://wiki.debian.org/ClamAV 2529 | - https://www.osradar.com/install-clamav-debian-9-ubuntu-18/ 2530 | - https://www.lisenet.com/2014/automate-clamav-to-perform-daily-system-scan-and-send-email-notifications-on-linux/ 2531 | - https://www.howtoforge.com/tutorial/configure-clamav-to-scan-and-notify-virus-and-malware/ 2532 | - https://serverfault.com/questions/741299/is-there-a-way-to-keep-clamav-updated-on-debian-8 2533 | - https://askubuntu.com/questions/250290/how-do-i-scan-for-viruses-with-clamav 2534 | - https://ngothang.com/how-to-install-clamav-and-configure-daily-scanning-on-centos/ 2535 | 2536 | #### Steps 2537 | 2538 | 1. Install ClamAV. 2539 | 2540 | On Debian based systems: 2541 | 2542 | ``` bash 2543 | sudo apt install clamav clamav-freshclam clamav-daemon 2544 | ``` 2545 | 2546 | 1. Make a backup of `clamav-freshclam`'s configuration file `/etc/clamav/freshclam.conf`: 2547 | 2548 | ``` bash 2549 | sudo cp --archive /etc/clamav/freshclam.conf /etc/clamav/freshclam.conf-COPY-$(date +"%Y%m%d%H%M%S") 2550 | ``` 2551 | 2552 | 1. `clamav-freshclam`'s default settings are probably good enough but if you want to change them, you can either edit the file `/etc/clamav/freshclam.conf` or use `dpkg-reconfigure`: 2553 | 2554 | ``` bash 2555 | sudo dpkg-reconfigure clamav-freshclam 2556 | ``` 2557 | 2558 | **Note**: The default settings will update the definitions 24 times in a day. To change the interval, check the `Checks` setting in `/etc/clamav/freshclam.conf` or use `dpkg-reconfigure`. 2559 | 2560 | 1. Start the `clamav-freshclam` service: 2561 | 2562 | ``` bash 2563 | sudo service clamav-freshclam start 2564 | ``` 2565 | 2566 | 1. You can make sure `clamav-freshclam` running: 2567 | 2568 | ``` bash 2569 | sudo service clamav-freshclam status 2570 | ``` 2571 | 2572 | > ``` 2573 | > ● clamav-freshclam.service - ClamAV virus database updater 2574 | > Loaded: loaded (/lib/systemd/system/clamav-freshclam.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2019-03-16 22:57:07 EDT; 2min 13s ago 2575 | > Docs: man:freshclam(1) 2576 | > man:freshclam.conf(5) 2577 | > https://www.clamav.net/documents 2578 | > Main PID: 1288 (freshclam) 2579 | > CGroup: /system.slice/clamav-freshclam.service 2580 | > └─1288 /usr/bin/freshclam -d --foreground=true 2581 | > 2582 | > Mar 16 22:57:08 host freshclam[1288]: Sat Mar 16 22:57:08 2019 -> ^Local version: 0.100.2 Recommended version: 0.101.1 2583 | > Mar 16 22:57:08 host freshclam[1288]: Sat Mar 16 22:57:08 2019 -> DON'T PANIC! Read https://www.clamav.net/documents/upgrading-clamav 2584 | > Mar 16 22:57:15 host freshclam[1288]: Sat Mar 16 22:57:15 2019 -> Downloading main.cvd [100%] 2585 | > Mar 16 22:57:38 host freshclam[1288]: Sat Mar 16 22:57:38 2019 -> main.cvd updated (version: 58, sigs: 4566249, f-level: 60, builder: sigmgr) 2586 | > Mar 16 22:57:40 host freshclam[1288]: Sat Mar 16 22:57:40 2019 -> Downloading daily.cvd [100%] 2587 | > Mar 16 22:58:13 host freshclam[1288]: Sat Mar 16 22:58:13 2019 -> daily.cvd updated (version: 25390, sigs: 1520006, f-level: 63, builder: raynman) 2588 | > Mar 16 22:58:14 host freshclam[1288]: Sat Mar 16 22:58:14 2019 -> Downloading bytecode.cvd [100%] 2589 | > Mar 16 22:58:16 host freshclam[1288]: Sat Mar 16 22:58:16 2019 -> bytecode.cvd updated (version: 328, sigs: 94, f-level: 63, builder: neo) 2590 | > Mar 16 22:58:24 host freshclam[1288]: Sat Mar 16 22:58:24 2019 -> Database updated (6086349 signatures) from db.local.clamav.net (IP: 104.16.219.84) 2591 | > Mar 16 22:58:24 host freshclam[1288]: Sat Mar 16 22:58:24 2019 -> ^Clamd was NOT notified: Can't connect to clamd through /var/run/clamav/clamd.ctl: No such file or directory 2592 | > ``` 2593 | 2594 | **Note**: Don't worry about that `Local version` line. Check https://serverfault.com/questions/741299/is-there-a-way-to-keep-clamav-updated-on-debian-8 for more details. 2595 | 2596 | 1. Make a backup of `clamav-daemon`'s configuration file `/etc/clamav/clamd.conf`: 2597 | 2598 | ``` bash 2599 | sudo cp --archive /etc/clamav/clamd.conf /etc/clamav/clamd.conf-COPY-$(date +"%Y%m%d%H%M%S") 2600 | ``` 2601 | 2602 | 1. You can change `clamav-daemon`'s settings by editing the file `/etc/clamav/clamd.conf` or useing `dpkg-reconfigure`: 2603 | 2604 | ``` bash 2605 | sudo dpkg-reconfigure clamav-daemon 2606 | ``` 2607 | 2608 | #### Scanning Files/Folders 2609 | 2610 | - To scan files/folders use the `clamscan` program. 2611 | - `clamscan` runs as the user it is executed as so it needs read permissions to the files/folders it is scanning. 2612 | - Using `clamscan` as `root` is dangerous because if a file is in fact a virus there is risk that it could use the root privileges. 2613 | - To scan a file: `clamscan /path/to/file`. 2614 | - To scan a directory: `clamscan -r /path/to/folder`. 2615 | - You can use the `-i` switch to only print infected files. 2616 | - Check `clamscan`'s `man` pages for other switches/options. 2617 | 2618 | ([Table of Contents](#table-of-contents)) 2619 | 2620 | ### Rootkit Detection With Rkhunter (WIP) 2621 | 2622 | #### Why 2623 | 2624 | WIP 2625 | 2626 | #### How It Works 2627 | 2628 | WIP 2629 | 2630 | #### Goals 2631 | 2632 | WIP 2633 | 2634 | #### References 2635 | 2636 | - http://rkhunter.sourceforge.net/ 2637 | - https://www.cyberciti.biz/faq/howto-check-linux-rootkist-with-detectors-software/ 2638 | - https://www.tecmint.com/install-rootkit-hunter-scan-for-rootkits-backdoors-in-linux/ 2639 | 2640 | #### Steps 2641 | 2642 | 1. Install Rkhunter. 2643 | 2644 | On Debian based systems: 2645 | 2646 | ``` bash 2647 | sudo apt install rkhunter 2648 | ``` 2649 | 2650 | 1. Make a backup of rkhunter' defaults file: 2651 | 2652 | ``` bash 2653 | sudo cp -p /etc/default/rkhunter /etc/default/rkhunter-COPY-$(date +"%Y%m%d%H%M%S") 2654 | ``` 2655 | 2656 | 1. rkhunter's configuration file is `/etc/rkhunter.conf`. Instead of making changes to it, create and use the file `/etc/rkhunter.conf.local` instead: 2657 | 2658 | ``` bash 2659 | sudo cp -p /etc/rkhunter.conf /etc/rkhunter.conf.local 2660 | ``` 2661 | 2662 | 1. Go through the configuration file `/etc/rkhunter.conf.local` and set to your requirements. My recommendations: 2663 | 2664 | |Setting|Note| 2665 | |--|--| 2666 | |`UPDATE_MIRRORS=1`|| 2667 | |`MIRRORS_MODE=0`|| 2668 | |`MAIL-ON-WARNING=root`|| 2669 | |`COPY_LOG_ON_ERROR=1`|to save a copy of the log if there is an error| 2670 | |`PKGMGR=...`|set to the appropriate value per the documentation| 2671 | |`PHALANX2_DIRTEST=1`|read the documentation for why| 2672 | |`WEB_CMD=""`|this is to address an issue with the Debian package that disables the ability for rkhunter to self-update.| 2673 | |`USE_LOCKING=1`|to prevent issues with rkhunter running multiple times| 2674 | |`SHOW_SUMMARY_WARNINGS_NUMBER=1`|to see the actual number of warnings found| 2675 | 2676 | 1. You want rkhunter to run every day and e-mail you the result. You can write your own script or check https://www.tecmint.com/install-rootkit-hunter-scan-for-rootkits-backdoors-in-linux/ for a sample cron script you can use. 2677 | 2678 | On Debian based system, rkhunter comes with cron scripts. To enable them check `/etc/default/rkhunter` or use `dpkg-reconfigure` and say `Yes` to all of the questions: 2679 | 2680 | ``` bash 2681 | sudo dpkg-reconfigure rkhunter 2682 | ``` 2683 | 2684 | 1. After you've finished with all of the changes, make sure all the settings are valid: 2685 | 2686 | ``` bash 2687 | sudo rkhunter -C 2688 | ``` 2689 | 2690 | 1. Update rkhunter and its database: 2691 | 2692 | ``` bash 2693 | sudo rkhunter --versioncheck 2694 | sudo rkhunter --update 2695 | sudo rkhunter --propupd 2696 | ``` 2697 | 2698 | 1. If you want to do a manual scan and see the output: 2699 | 2700 | ``` bash 2701 | sudo rkhunter --check 2702 | ``` 2703 | 2704 | ([Table of Contents](#table-of-contents)) 2705 | 2706 | ### Rootkit Detection With chrootkit (WIP) 2707 | 2708 | #### Why 2709 | 2710 | WIP 2711 | 2712 | #### How It Works 2713 | 2714 | WIP 2715 | 2716 | #### Goals 2717 | 2718 | WIP 2719 | 2720 | #### References 2721 | 2722 | - http://www.chkrootkit.org/ 2723 | - https://www.cyberciti.biz/faq/howto-check-linux-rootkist-with-detectors-software/ 2724 | - https://askubuntu.com/questions/258658/eth0-packet-sniffer-sbin-dhclient 2725 | 2726 | #### Steps 2727 | 2728 | 1. Install chkrootkit. 2729 | 2730 | On Debian based systems: 2731 | 2732 | ``` bash 2733 | sudo apt install chkrootkit 2734 | ``` 2735 | 2736 | 1. Do a manual scan: 2737 | 2738 | ``` bash 2739 | sudo chkrootkit 2740 | ``` 2741 | 2742 | > ``` 2743 | > ROOTDIR is `/' 2744 | > Checking `amd'... not found 2745 | > Checking `basename'... not infected 2746 | > Checking `biff'... not found 2747 | > Checking `chfn'... not infected 2748 | > Checking `chsh'... not infected 2749 | > ... 2750 | > Checking `scalper'... not infected 2751 | > Checking `slapper'... not infected 2752 | > Checking `z2'... chklastlog: nothing deleted 2753 | > Checking `chkutmp'... chkutmp: nothing deleted 2754 | > Checking `OSX_RSPLUG'... not infected 2755 | > ``` 2756 | 2757 | 1. Make a backup of chkrootkit's configuration file `/etc/chkrootkit.conf`: 2758 | 2759 | ``` bash 2760 | sudo cp --archive /etc/chkrootkit.conf /etc/chkrootkit.conf-COPY-$(date +"%Y%m%d%H%M%S") 2761 | ``` 2762 | 2763 | 1. You want chkrootkit to run every day and e-mail you the result. 2764 | 2765 | On Debian based system, chkrootkit comes with cron scripts. To enable them check `/etc/chkrootkit.conf` or use `dpkg-reconfigure` and say `Yes` to the first question: 2766 | 2767 | ``` bash 2768 | sudo dpkg-reconfigure chkrootkit 2769 | ``` 2770 | 2771 | ([Table of Contents](#table-of-contents)) 2772 | 2773 | ### logwatch - system log analyzer and reporter 2774 | 2775 | #### Why 2776 | 2777 | Your server will be generating a lot of logs that may contain important information. Unless you plan on checking your server everyday, you'll want a way to get e-mail summary of your server's logs. To accomplish this we'll use [logwatch](https://sourceforge.net/projects/logwatch/). 2778 | 2779 | #### How It Works 2780 | 2781 | logwatch scans system log files and summarizes them. You can run it directly from the command line or schedule it to run on a recurring schedule. logwatch uses service files to know how to read/summarize a log file. You can see all of the stock service files in `/usr/share/logwatch/scripts/services`. 2782 | 2783 | logwatch's configuration file `/usr/share/logwatch/default.conf/logwatch.conf` specifies default options. You can override them via command line arguments. 2784 | 2785 | #### Goals 2786 | 2787 | - Logwatch configured to send a daily e-mail summary of all of the server's status and logs 2788 | 2789 | #### Notes 2790 | 2791 | - Your server will need to be able to send e-mails for this to work 2792 | - The below steps will result in logwatch running every day. If you want to change the schedule, modify the cronjob to your liking. You'll also want to change the `range` option to cover your recurrence window. See https://www.badpenguin.org/configure-logwatch-for-weekly-email-and-html-output-format for an example. 2793 | - If logwatch fails to deliver mail due to the e-mail having long lines please check https://blog.dhampir.no/content/exim4-line-length-in-debian-stretch-mail-delivery-failed-returning-message-to-sender as documented in [issue #29](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/29). If you followed [Gmail and Exim4 As MTA With Implicit TLS](#gmail-and-exim4-as-mta-with-implicit-tls) then we already took care of this in step #7. 2794 | 2795 | #### References 2796 | 2797 | - Thanks to [amacheema](https://github.com/amacheema) for fixing some issues with the steps and letting me know of a long line bug with exim4 as documented in [issue #29](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/29). 2798 | - https://sourceforge.net/projects/logwatch/ 2799 | - https://www.digitalocean.com/community/tutorials/how-to-install-and-use-logwatch-log-analyzer-and-reporter-on-a-vps 2800 | 2801 | #### Steps 2802 | 2803 | 1. Install logwatch. 2804 | 2805 | On Debian based systems: 2806 | 2807 | ``` bash 2808 | sudo apt install logwatch 2809 | ``` 2810 | 2811 | 1. To see a sample of what logwatch collects you can run it directly: 2812 | 2813 | ``` bash 2814 | sudo /usr/sbin/logwatch --output stdout --format text --range yesterday --service all 2815 | ``` 2816 | 2817 | > ``` 2818 | > 2819 | > ################### Logwatch 7.4.3 (12/07/16) #################### 2820 | > Processing Initiated: Mon Mar 4 00:05:50 2019 2821 | > Date Range Processed: yesterday 2822 | > ( 2019-Mar-03 ) 2823 | > Period is day. 2824 | > Detail Level of Output: 5 2825 | > Type of Output/Format: stdout / text 2826 | > Logfiles for Host: host 2827 | > ################################################################## 2828 | > 2829 | > --------------------- Cron Begin ------------------------ 2830 | > ... 2831 | > ... 2832 | > ---------------------- Disk Space End ------------------------- 2833 | > 2834 | > 2835 | > ###################### Logwatch End ######################### 2836 | > ``` 2837 | 2838 | 1. Go through logwatch's self-documented configuration file `/usr/share/logwatch/default.conf/logwatch.conf` before continuing. There is no need to change anything here but pay special attention to the `Output`, `Format`, `MailTo`, `Range`, and `Service` as those are the ones we'll be using. For our purposes, instead of specifying our options in the configuration file, we will pass them as command line arguments in the daily cron job that executes logwatch. That way, if the configuration file is ever modified (e.g. during an update), our options will still be there. 2839 | 2840 | 1. Make a backup of logwatch's daily cron file `/etc/cron.daily/00logwatch` and unset the execute bit: 2841 | 2842 | ``` bash 2843 | sudo cp --archive /etc/cron.daily/00logwatch /etc/cron.daily/00logwatch-COPY-$(date +"%Y%m%d%H%M%S") 2844 | sudo chmod -x /etc/cron.daily/00logwatch-COPY* 2845 | ``` 2846 | 2847 | 1. By default, logwatch outputs to `stdout`. Since the goal is to get a daily e-mail, we need to change the output type that logwatch uses to send e-mail instead. We could do this through the configuration file above, but that would apply to every time it is run -- even when we run it manually and want to see the output to the screen. Instead, we'll change the cron job that executes logwatch to send e-mail. This way, when run manually, we'll still get output to `stdout` and when run by cron, it'll send an e-mail. We'll also make sure it checks for all services, and change the output format to html so it's easier to read regardless of what the configuration file says. In the file `/etc/cron.daily/00logwatch` find the execute line and change it to: 2848 | 2849 | ``` 2850 | /usr/sbin/logwatch --output mail --format html --mailto root --range yesterday --service all 2851 | ``` 2852 | 2853 | > ``` 2854 | > #!/bin/bash 2855 | > 2856 | > #Check if removed-but-not-purged 2857 | > test -x /usr/share/logwatch/scripts/logwatch.pl || exit 0 2858 | > 2859 | > #execute 2860 | > /usr/sbin/logwatch --output mail --format html --mailto root --range yesterday --service all 2861 | > 2862 | > #Note: It's possible to force the recipient in above command 2863 | > #Just pass --mailto address@a.com instead of --output mail 2864 | > ``` 2865 | 2866 | [For the lazy](#editing-configuration-files---for-the-lazy): 2867 | 2868 | ``` bash 2869 | sudo sed -i -r -e "s,^($(sudo which logwatch).*?),# \1 # commented by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")\n$(sudo which logwatch) --output mail --format html --mailto root --range yesterday --service all # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")," /etc/cron.daily/00logwatch 2870 | ``` 2871 | 2872 | 1. You can test the cron job by executing it: 2873 | 2874 | ``` bash 2875 | sudo /etc/cron.daily/00logwatch 2876 | ``` 2877 | 2878 | **Note**: If logwatch fails to deliver mail due to the e-mail having long lines please check https://blog.dhampir.no/content/exim4-line-length-in-debian-stretch-mail-delivery-failed-returning-message-to-sender as documented in [issue #29](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/29). If you followed [Gmail and Exim4 As MTA With Implicit TLS](#gmail-and-exim4-as-mta-with-implicit-tls) then we already took care of this in step #7. 2879 | 2880 | ([Table of Contents](#table-of-contents)) 2881 | 2882 | ### ss - Seeing Ports Your Server Is Listening On 2883 | 2884 | #### Why 2885 | 2886 | Ports are how applications, services, and processes communicate with each other -- either locally within your server or with other devices on the network. When you have an application or service (like SSH or Apache) running on your server, they listen for requests on specific ports. 2887 | 2888 | Obviously we don't want your server listening on ports we don't know about. We'll use `ss` to see all the ports that services are listening on. This will help us track down and stop rogue, potentially dangerous, services. 2889 | 2890 | #### Goals 2891 | 2892 | - find out non-localhost what ports are open and listening for connections 2893 | 2894 | #### References 2895 | 2896 | - https://www.reddit.com/r/linux/comments/arx7st/howtosecurealinuxserver_an_evolving_howto_guide/egrib6o/ 2897 | - https://www.reddit.com/r/linux/comments/arx7st/howtosecurealinuxserver_an_evolving_howto_guide/egs1rev/ 2898 | - https://www.tecmint.com/find-open-ports-in-linux/ 2899 | - `man ss` 2900 | 2901 | #### Steps 2902 | 2903 | 1. To see the all the ports listening for traffic: 2904 | 2905 | ``` bash 2906 | sudo ss -lntup 2907 | ``` 2908 | 2909 | > ``` 2910 | > Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port 2911 | > udp UNCONN 0 0 *:68 *:* users:(("dhclient",pid=389,fd=6)) 2912 | > tcp LISTEN 0 128 *:22 *:* users:(("sshd",pid=4390,fd=3)) 2913 | > tcp LISTEN 0 128 :::22 :::* users:(("sshd",pid=4390,fd=4)) 2914 | > ``` 2915 | 2916 | **Switch Explanations**: 2917 | - `l` = display listening sockets 2918 | - `n` = do not try to resolve service names 2919 | - `t` = display TCP sockets 2920 | - `u` = display UDP sockets 2921 | - `p` = show process information 2922 | 2923 | 1. If you see anything suspicious, like a port you're not aware of or a process you don't know, investigate and remediate as necessary. 2924 | 2925 | ([Table of Contents](#table-of-contents)) 2926 | 2927 | ### Lynis - Linux Security Auditing 2928 | 2929 | #### Why 2930 | 2931 | From [https://cisofy.com/lynis/](https://cisofy.com/lynis/): 2932 | 2933 | > Lynis is a battle-tested security tool for systems running Linux, macOS, or Unix-based operating system. It performs an extensive health scan of your systems to support system hardening and compliance testing. 2934 | 2935 | #### Goals 2936 | 2937 | - Lynis installed 2938 | 2939 | #### Notes 2940 | 2941 | - CISOFY offers packages for many distributions. Check https://packages.cisofy.com/ for distribution specific installation instructions. 2942 | 2943 | #### References 2944 | 2945 | - https://cisofy.com/documentation/lynis/get-started/ 2946 | - https://packages.cisofy.com/community/#debian-ubuntu 2947 | - https://thelinuxcode.com/audit-lynis-ubuntu-server/ 2948 | - https://www.vultr.com/docs/install-lynis-on-debian-8 2949 | 2950 | #### Steps 2951 | 2952 | 1. Install lynis. https://cisofy.com/lynis/#installation has detailed instructions on how to install it for your distribution. 2953 | 2954 | On Debian based systems, using CISOFY's community software repository: 2955 | 2956 | ``` bash 2957 | sudo apt install apt-transport-https ca-certificates host 2958 | sudo wget -O - https://packages.cisofy.com/keys/cisofy-software-public.key | sudo apt-key add - 2959 | sudo echo "deb https://packages.cisofy.com/community/lynis/deb/ stable main" | sudo tee /etc/apt/sources.list.d/cisofy-lynis.list 2960 | sudo apt update 2961 | sudo apt install lynis host 2962 | ``` 2963 | 2964 | 1. Update it: 2965 | 2966 | ``` bash 2967 | sudo lynis update info 2968 | ``` 2969 | 2970 | 1. Run a security audit: 2971 | 2972 | ``` bash 2973 | sudo lynis audit system 2974 | ``` 2975 | 2976 | This will scan your server, report its audit findings, and at the end it will give you suggestions. Spend some time going through the output and address gaps as necessary. 2977 | 2978 | ([Table of Contents](#table-of-contents)) 2979 | 2980 | ### OSSEC - Host Intrusion Detection 2981 | 2982 | #### Why 2983 | From [https://github.com/ossec/ossec-hids](https://github.com/ossec/ossec-hids) 2984 | > OSSEC is a full platform to monitor and control your systems. It mixes together all the aspects of HIDS (host-based intrusion detection), log monitoring and SIM/SIEM together in a simple, powerful and open source solution. 2985 | 2986 | #### Goals 2987 | 2988 | - OSSEC-HIDS installed 2989 | 2990 | #### References 2991 | 2992 | - https://www.ossec.net/docs/ 2993 | 2994 | #### Steps 2995 | 2996 | 1. Install OSSEC-HIDS from sources 2997 | ```bash 2998 | sudo apt install -y libz-dev libssl-dev libpcre2-dev build-essential libsystemd-dev 2999 | wget https://github.com/ossec/ossec-hids/archive/3.7.0.tar.gz 3000 | tar xzf 3.7.0.tar.gz 3001 | cd ossec-hids-3.7.0/ 3002 | sudo ./install.sh 3003 | ``` 3004 | 3005 | 1. Useful commands: 3006 | 3007 | **Agent information** 3008 | 3009 | ```bash 3010 | sudo /var/ossec/bin/agent_control -i 3011 | ``` 3012 | `AGENT_ID` by default is `000`, to be sure the command `sudo /var/ossec/bin/agent_control -l` can be used. 3013 | 3014 | **Run integrity/rootkit checking** 3015 | 3016 | OSSEC by default run rootkit check each 2 hours. 3017 | 3018 | ```bash 3019 | sudo /var/ossec/bin/agent_control -u -r 3020 | ``` 3021 | 3022 | **Alerts** 3023 | 3024 | - All: 3025 | ```bash 3026 | tail -f /var/ossec/logs/alerts/alerts.log 3027 | ``` 3028 | - Integrity check: 3029 | ```bash 3030 | sudo cat /var/ossec/logs/alerts/alerts.log | grep -A4 -i integrity 3031 | ``` 3032 | - Rootkit check: 3033 | ```bash 3034 | sudo cat /var/ossec/logs/alerts/alerts.log | grep -A4 "rootcheck," 3035 | ``` 3036 | 3037 | ([Table of Contents](#table-of-contents)) 3038 | 3039 | ## The Danger Zone 3040 | 3041 | ### Proceed At Your Own Risk 3042 | 3043 | This sections cover things that are high risk because there is a possibility they can make your system unusable, or are considered unnecessary by many because the risks outweigh any rewards. 3044 | 3045 | **!! PROCEED AT YOUR OWN RISK !!** 3046 | 3047 |
!! PROCEED AT YOUR OWN RISK !! 3048 | 3049 | ([Table of Contents](#table-of-contents)) 3050 | 3051 | ### Table of Contents 3052 | 3053 | - [Linux Kernel sysctl Hardening](#linux-kernel-sysctl-hardening) 3054 | - [Password Protect GRUB](#password-protect-grub) 3055 | - [Disable Root Login](#disable-root-login) 3056 | - [Change Default umask](#change-default-umask) 3057 | - [Orphaned Software](#orphaned-software) 3058 | 3059 | ([Table of Contents](#table-of-contents)) 3060 | 3061 | ### Linux Kernel sysctl Hardening 3062 | 3063 |
!! PROCEED AT YOUR OWN RISK !! 3064 | 3065 | #### Why 3066 | 3067 | The kernel is the brains of a Linux system. Securing it just makes sense. 3068 | 3069 | #### Why Not 3070 | 3071 | Changing kernel settings with sysctl is risky and could break your server. If you don't know what you are doing, don't have the time to debug issues, or just don't want to take the risks, I would advise from not following these steps. 3072 | 3073 | #### Disclaimer 3074 | 3075 | I am not as knowledgeable about hardening/securing a Linux kernel as I'd like. As much as I hate to admit it, I do not know what all of these settings do. My understanding is that most of them are general kernel hardening and performance, and the others are to protect against spoofing and DOS attacks. 3076 | 3077 | In fact, since I am not 100% sure exactly what each setting does, I took recommended settings from numerous sites (all linked in the references below) and combined them to figure out what should be set. I figure if multiple reputable sites mention the same setting, it's probably safe. 3078 | 3079 | If you have a better understanding of what these settings do, or have any other feedback/advice on them, please [let me know](#contacting-me). 3080 | 3081 | I won't provide [For the lazy](#editing-configuration-files---for-the-lazy) code in this section. 3082 | 3083 | #### Notes 3084 | 3085 | - Documentation on all the sysctl settings/keys is severely lacking. The [documentation I can find](https://github.com/torvalds/linux/tree/master/Documentation) seems to reference the 2.2 version kernel. I could not find anything newer. If you know where I can, please [let me know](#contacting-me). 3086 | - The reference sites listed below have more comments on what each setting does. 3087 | 3088 | #### References 3089 | 3090 | - https://github.com/torvalds/linux/tree/master/Documentation 3091 | - https://www.cyberciti.biz/faq/linux-kernel-etcsysctl-conf-security-hardening/ 3092 | - https://geektnt.com/sysctl-conf-hardening.html 3093 | - https://linoxide.com/how-tos/linux-server-protection/ 3094 | - https://github.com/klaver/sysctl/blob/master/sysctl.conf 3095 | - https://cloudpro.zone/index.php/2018/01/30/debian-9-3-server-setup-guide-part-5/ 3096 | 3097 | #### Steps 3098 | 3099 | 1. The sysctl settings can be found in the [linux-kernel-sysctl-hardening.md](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/blob/master/linux-kernel-sysctl-hardening.md) file in this repo. 3100 | 3101 | 1. Before you make a kernel sysctl change permanent, you can test it with the sysctl command: 3102 | 3103 | ``` bash 3104 | sudo sysctl -w [key=value] 3105 | ``` 3106 | 3107 | Example: 3108 | 3109 | ``` bash 3110 | sudo sysctl -w kernel.ctrl-alt-del=0 3111 | ``` 3112 | 3113 | **Note**: There are no spaces in `key=value`, including before and after the space. 3114 | 3115 | 1. Once you have tested a setting, and made sure it works without breaking your server, you can make it permanent by adding the values to `/etc/sysctl.conf`. For example: 3116 | 3117 | ``` bash 3118 | $ sudo cat /etc/sysctl.conf 3119 | kernel.ctrl-alt-del = 0 3120 | fs.file-max = 65535 3121 | ... 3122 | kernel.sysrq = 0 3123 | ``` 3124 | 3125 | 1. After updating the file you can reload the settings or reboot. To reload: 3126 | 3127 | ``` bash 3128 | sudo sysctl -p 3129 | ``` 3130 | 3131 | **Note**: If sysctl has trouble writing any settings then `sysctl -w` or `sysctl -p` will write an error to stderr. You can use this to quickly find invalid settings in your `/etc/sysctl.conf` file: 3132 | 3133 | ``` bash 3134 | sudo sysctl -p >/dev/null 3135 | ``` 3136 | 3137 |

3138 | 3139 | ([Table of Contents](#table-of-contents)) 3140 | 3141 | ### Password Protect GRUB 3142 | 3143 |
!! PROCEED AT YOUR OWN RISK !! 3144 | 3145 | #### Why 3146 | 3147 | If a bad actor has physical access to your server, they could use GRUB to gain unauthorized access to your system. 3148 | 3149 | #### Why Not 3150 | 3151 | If you forget the password, you'll have to go through [some work](https://www.cyberciti.biz/tips/howto-recovering-grub-boot-loader-password.html) to recover the password. 3152 | 3153 | #### Goals 3154 | 3155 | - auto boot the default Debian install and require a password for anything else 3156 | 3157 | #### Notes 3158 | 3159 | - This will only protect GRUB and anything behind it like your operating systems. Check your motherboard's documentation for password protecting your BIOS to prevent a bad actor from circumventing GRUB. 3160 | 3161 | #### References 3162 | 3163 | - https://selivan.github.io/2017/12/21/grub2-password-for-all-but-default-menu-entries.html 3164 | - https://help.ubuntu.com/community/Grub2/Passwords 3165 | - https://computingforgeeks.com/how-to-protect-grub-with-password-on-debian-ubuntu-and-kali-linux/ 3166 | - `man grub` 3167 | - `man grub-mkpasswd-pbkdf2` 3168 | 3169 | #### Steps 3170 | 3171 | 1. Create a [Password-Based Key Derivation Function 2 (PBKDF2)](https://en.wikipedia.org/wiki/PBKDF2) hash of your password: 3172 | 3173 | ``` bash 3174 | grub-mkpasswd-pbkdf2 -c 100000 3175 | ``` 3176 | 3177 | The below output is from using `password` as the password: 3178 | 3179 | > ``` 3180 | > Enter password: 3181 | > Reenter password: 3182 | > PBKDF2 hash of your password is grub.pbkdf2.sha512.100000.2812C233DFC899EFC3D5991D8CA74068C99D6D786A54F603E9A1EFE7BAEDDB6AA89672F92589FAF98DB9364143E7A1156C9936328971A02A483A84C3D028C4FF.C255442F9C98E1F3C500C373FE195DCF16C56EEBDC55ABDD332DD36A92865FA8FC4C90433757D743776AB186BD3AE5580F63EF445472CC1D151FA03906D08A6D 3183 | > ``` 3184 | 3185 | 1. Copy everything **after** `PBKDF2 hash of your password is `, **starting from and including** `grub.pbkdf2.sha512...` to the end. You'll need this in the next step. 3186 | 3187 | 1. The `update-grub` program uses scripts to generate configuration files it will use for GRUB's settings. Create the file `/etc/grub.d/01_password` and add the below code after replacing `[hash]` with the hash you copied from the first step. This tells `update-grub` to use this username and password for GRUB. 3188 | 3189 | ``` bash 3190 | #!/bin/sh 3191 | set -e 3192 | 3193 | cat << EOF 3194 | set superusers="grub" 3195 | password_pbkdf2 grub [hash] 3196 | EOF 3197 | ``` 3198 | 3199 | For example: 3200 | 3201 | > ``` bash 3202 | > #!/bin/sh 3203 | > set -e 3204 | > 3205 | > cat << EOF 3206 | > set superusers="grub" 3207 | > password_pbkdf2 grub grub.pbkdf2.sha512.100000.2812C233DFC899EFC3D5991D8CA74068C99D6D786A54F603E9A1EFE7BAEDDB6AA89672F92589FAF98DB9364143E7A1156C9936328971A02A483A84C3D028C4FF.C255442F9C98E1F3C500C373FE195DCF16C56EEBDC55ABDD332DD36A92865FA8FC4C90433757D743776AB186BD3AE5580F63EF445472CC1D151FA03906D08A6D 3208 | > EOF 3209 | > ``` 3210 | 3211 | 1. Set the file's execute bit so `update-grub` includes it when it updates GRUB's configuration: 3212 | 3213 | ``` bash 3214 | sudo chmod a+x /etc/grub.d/01_password 3215 | ``` 3216 | 3217 | 1. Make a backup of GRUB's configuration file `/etc/grub.d/10_linux` that we'll be modifying and unset the execute bit so `update-grub` doesn't try to run it: 3218 | 3219 | ``` bash 3220 | sudo cp --archive /etc/grub.d/10_linux /etc/grub.d/10_linux-COPY-$(date +"%Y%m%d%H%M%S") 3221 | sudo chmod a-x /etc/grub.d/10_linux.* 3222 | ``` 3223 | 3224 | 1. To make the default Debian install unrestricted (**without** the password) while keeping everything else restricted (**with** the password) modify `/etc/grub.d/10_linux` and add `--unrestricted` to the `CLASS` variable. 3225 | 3226 | [For the lazy](#editing-configuration-files---for-the-lazy): 3227 | 3228 | ``` bash 3229 | sudo sed -i -r -e "/^CLASS=/ a CLASS=\"\${CLASS} --unrestricted\" # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" /etc/grub.d/10_linux 3230 | ``` 3231 | 3232 | 1. Update GRUB with `update-grub`: 3233 | 3234 | ``` bash 3235 | sudo update-grub 3236 | ``` 3237 | 3238 |

3239 | 3240 | ([Table of Contents](#table-of-contents)) 3241 | 3242 | ### Disable Root Login 3243 | 3244 |
!! PROCEED AT YOUR OWN RISK !! 3245 | 3246 | #### Why 3247 | 3248 | If you have sudo [configured properly](#limit-who-can-use-sudo), then the **root** account will mostly never need to log in directly -- either at the terminal or remotely. 3249 | 3250 | #### Why Not 3251 | 3252 | **Be warned, this can cause issues with some configurations!** 3253 | 3254 | If your installation uses [`sulogin`](https://linux.die.net/man/8/sulogin) (like Debian) to drop to a **root** console during boot failures, then locking the **root** account will prevent `sulogin` from opening the **root** shell and you will get this error: 3255 | 3256 | Cannot open access to console, the root account is locked. 3257 | 3258 | See sulogin(8) man page for more details. 3259 | 3260 | Press Enter to continue. 3261 | 3262 | To work around this, you can use the `--force` option for `sulogin`. Some distributions already include this, or some other, workaround. 3263 | 3264 | An alternative to locking the **root** acount is set a long/complicated **root** password and store it in a secured, non-digital format. That way you have it when/if you need it. 3265 | 3266 | #### Goals 3267 | 3268 | - locked **root** account that nobody can use to log in as **root** 3269 | 3270 | #### Notes 3271 | 3272 | - Some distributions disable **root** login by default (e.g. Ubuntu) so you may not need to do this step. Check with your distribution's documentation. 3273 | 3274 | #### References 3275 | 3276 | - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=806852 3277 | - https://github.com/systemd/systemd/issues/7115 3278 | - https://github.com/karelzak/util-linux/commit/7ff1162e67164cb4ece19dd809c26272461aa254 3279 | - https://github.com/systemd/systemd/issues/11596 3280 | - https://www.reddit.com/r/selfhosted/comments/aoxd4l/new_guide_created_by_me_how_to_secure_a_linux/eg4rkfi/ 3281 | - `man systemd` 3282 | 3283 | #### Steps 3284 | 3285 | 1. Lock the **root** account: 3286 | 3287 | ``` bash 3288 | sudo passwd -l root 3289 | ``` 3290 | 3291 |

3292 | 3293 | ([Table of Contents](#table-of-contents)) 3294 | 3295 | ### Change Default umask 3296 | 3297 |
!! PROCEED AT YOUR OWN RISK !! 3298 | 3299 | #### Why 3300 | 3301 | umask controls the **default** permissions of files/folders when they are created. Insecure file/folder permissions give other accounts potentially unauthorized access to your data. This may include the ability to make configuration changes. 3302 | 3303 | - For **non-root** accounts, there is no need for other accounts to get any access to the account's files/folders **by default**. 3304 | - For the **root** account, there is no need for the file/folder primary group or other accounts to have any access to **root**'s files/folders **by default**. 3305 | 3306 | When and if other accounts need access to a file/folder, you want to explicitly grant it using a combination of file/folder permissions and primary group. 3307 | 3308 | #### Why Not 3309 | 3310 | Changing the default umask can create unexpected problems. For example, if you set umask to `0077` for **root**, then **non-root** accounts **will not** have access to application configuration files/folders in `/etc/` which could break applications that do not run with **root** privileges. 3311 | 3312 | #### How It Works 3313 | 3314 | In order to explain how umask works I'd have to explain how Linux file/folder permissions work. As that is a rather complicated question, I will defer you to the references below for further reading. 3315 | 3316 | #### Goals 3317 | 3318 | - set default umask for **non-root** accounts to **0027** 3319 | - set default umask for the **root** account to **0077** 3320 | 3321 | #### Notes 3322 | 3323 | - umask is a Bash built-in which means a user can change their own umask setting. 3324 | 3325 | #### References 3326 | 3327 | - https://www.linuxnix.com/umask-define-linuxunix/ 3328 | - https://serverfault.com/questions/818783/which-umask-is-more-secure-in-linux-022-or-027 3329 | - https://www.cyberciti.biz/tips/understanding-linux-unix-umask-value-usage.html 3330 | - `man umask` 3331 | 3332 | #### Steps 3333 | 3334 | 1. Make a backup of files we'll be editing: 3335 | 3336 | ``` bash 3337 | sudo cp --archive /etc/profile /etc/profile-COPY-$(date +"%Y%m%d%H%M%S") 3338 | sudo cp --archive /etc/bash.bashrc /etc/bash.bashrc-COPY-$(date +"%Y%m%d%H%M%S") 3339 | sudo cp --archive /etc/login.defs /etc/login.defs-COPY-$(date +"%Y%m%d%H%M%S") 3340 | sudo cp --archive /root/.bashrc /root/.bashrc-COPY-$(date +"%Y%m%d%H%M%S") 3341 | ``` 3342 | 3343 | 1. Set default umask for **non-root** accounts to **0027** by adding this line to `/etc/profile` and `/etc/bash.bashrc`: 3344 | 3345 | ``` 3346 | umask 0027 3347 | ``` 3348 | 3349 | [For the lazy](#editing-configuration-files---for-the-lazy): 3350 | 3351 | ``` bash 3352 | echo -e "\numask 0027 # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/profile /etc/bash.bashrc 3353 | ``` 3354 | 3355 | 1. We also need to add this line to `/etc/login.defs`: 3356 | 3357 | ``` 3358 | UMASK 0027 3359 | ``` 3360 | 3361 | [For the lazy](#editing-configuration-files---for-the-lazy): 3362 | 3363 | ``` bash 3364 | echo -e "\nUMASK 0027 # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/login.defs 3365 | ``` 3366 | 3367 | 1. Set default umask for the **root** account to **0077** by adding this line to `/root/.bashrc`: 3368 | 3369 | ``` 3370 | umask 0077 3371 | ``` 3372 | 3373 | [For the lazy](#editing-configuration-files---for-the-lazy): 3374 | 3375 | ``` bash 3376 | echo -e "\numask 0077 # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /root/.bashrc 3377 | ``` 3378 | 3379 |

3380 | 3381 | ([Table of Contents](#table-of-contents)) 3382 | 3383 | ### Orphaned Software 3384 | 3385 |
!! PROCEED AT YOUR OWN RISK !! 3386 | 3387 | #### Why 3388 | 3389 | As you use your system, and you install and uninstall software, you'll eventually end up with orphaned, or unused software/packages/libraries. You don't need to remove them, but if you don't need them, why keep them? When security is a priority, anything not explicitly needed is a potential security threat. You want to keep your server as trimmed and lean as possible. 3390 | 3391 | #### Notes 3392 | 3393 | - Each distribution manages software/packages/libraries differently so how you find and remove orphaned packages will be different. So far I only have steps for Debian based systems. 3394 | 3395 | #### Debian Based Systems 3396 | 3397 | On Debian based systems, you can use [deborphan](http://freshmeat.sourceforge.net/projects/deborphan/) to find orphaned packages. 3398 | 3399 | ##### Why Not 3400 | 3401 | Keep in mind, deborphan finds packages that have **no package dependencies**. That does not mean they are not used. You could very well have a package you use every day that has no dependencies that you wouldn't want to remove. And, if deborphan gets anything wrong, then removing critical packages may break your system. 3402 | 3403 | ##### Steps 3404 | 3405 | 1. Install deborphan. 3406 | 3407 | ``` bash 3408 | sudo apt install deborphan 3409 | ``` 3410 | 3411 | 1. Run deborphan as **root** to see a list of orphaned packages: 3412 | 3413 | ``` bash 3414 | sudo deborphan 3415 | ``` 3416 | 3417 | > ``` 3418 | > libxapian30 3419 | > libpipeline1 3420 | > ``` 3421 | 3422 | 1. [Assuming you want to remove all of the packages deborphan finds](#orphaned-software-why-not), you can pass it's output to `apt` to remove them: 3423 | 3424 | ``` bash 3425 | sudo apt --autoremove purge $(deborphan) 3426 | ``` 3427 | 3428 |
3429 | 3430 |

3431 | 3432 | ([Table of Contents](#table-of-contents)) 3433 | 3434 | ## The Miscellaneous 3435 | 3436 | ### The Simple way with MSMTP 3437 | (#msmtp-alternative) 3438 | #### Why 3439 | 3440 | Well I will SIMPLIFY this method, to only output email using Google Mail account (and others). True Simple! :) 3441 | 3442 | ``` bash 3443 | #!/bin/bash 3444 | ###### PLEASE .... EDIT IT... 3445 | USEREMAIL="usernameemail" 3446 | DOMPROV="gmail.com" 3447 | PWDEMAIL="passwordStrong" ## ATTENTION DONT USE Special Chars.. like as SPACE # and some others not all. Feel free to test ;) 3448 | MAILPROV="smtp.google.com:583" 3449 | MYMAIL="$USRMAIL@$DOMPROV" 3450 | USERLOC="root" 3451 | ####### 3452 | apt install -y msmtp 3453 | ln -s /usr/bin/msmtp /usr/sbin/sendmail 3454 | #wget http://www.cacert.org/revoke.crl -O /etc/ssl/certs/revoke.crl 3455 | #chmod 644 /etc/ssl/certs/revoke.crl 3456 | touch /root/.msmtprc 3457 | cat < .msmtprc 3458 | defaults 3459 | account gmail 3460 | host $MAILPROV 3461 | port $MAILPORT 3462 | #proxy_host 127.0.0.1 3463 | #proxy_port 9001 3464 | from $MYEMAIL 3465 | timeout off 3466 | protocol smtp 3467 | #auto_from [(on|off)] 3468 | #from envelope_from 3469 | #maildomain [domain] 3470 | auth on 3471 | user $USRMAIL 3472 | passwordeval "gpg -q --for-your-eyes-only --no-tty -d /root/msmtp-mail.gpg" 3473 | #passwordeval "gpg --quiet --for-your-eyes-only --no-tty --decrypt /root/msmtp-mail.gpg" 3474 | tls on 3475 | tls_starttls on 3476 | tls_trust_file /etc/ssl/certs/ca-certificates.crt 3477 | #tls_crl_file /etc/ssl/certs/revoke.crl 3478 | #tls_fingerprint [fingerprint] 3479 | #tls_key_file [file] 3480 | #tls_cert_file [file] 3481 | tls_certcheck on 3482 | tls_force_sslv3 on 3483 | tls_min_dh_prime_bits 512 3484 | #tls_priorities [priorities] 3485 | #dsn_notify (off|condition) 3486 | #dsn_return (off|amount) 3487 | #domain argument 3488 | #keepbcc off 3489 | logfile /var/log/mail.log 3490 | syslog on 3491 | account default : gmail 3492 | EOF 3493 | chmod 0400 /root/.msmtprc 3494 | 3495 | ## In testing .. auto command 3496 | # echo -e "1\n4096\n\ny\n$MYUSRMAIL\n$MYEMAIL\nmy key\nO\n$PWDMAIL\n$PWDMAIL\n" | gpg --full-generate-key 3497 | ## 3498 | gpg --full-generate-key 3499 | gpg --output revoke.asc --gen-revoke $MYEMAIL 3500 | echo -e "$PWDEMAIL\n" | gpg -e -o /root/msmtp-mail.gpg --recipient $MYEMAIL 3501 | echo "export GPG_TTY=\$(tty)" >> .baschrc 3502 | chmod 400 msmtp-mail.gpg 3503 | 3504 | echo "Hello there" | msmtp --debug $MYEMAIL 3505 | echo"###################### 3506 | ## MSMTP Configured ## 3507 | ######################" 3508 | ``` 3509 | 3510 | DONE!! ;) 3511 | ([Table of Contents](#table-of-contents)) 3512 | 3513 | ### Gmail and Exim4 As MTA With Implicit TLS 3514 | 3515 | #### Why 3516 | 3517 | Unless you're planning on setting up your own mail server, you'll need a way to send e-mails from your server. This will be important for system alerts/messages. 3518 | 3519 | You can use any Gmail account. I recommend you create one specific for this server. That way if your server **is** compromised, the bad-actor won't have any passwords for your primary account. Granted, if you have 2FA/MFA enabled, and you use an app password, there isn't much a bad-actor can do with just the app password, but why take the risk? 3520 | 3521 | There are many guides on-line that cover how to configure Gmail as MTA using STARTTLS including a [previous version of this guide](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/tree/cc5edcae1cf846dd250e76b121e721d836481d2f#configure-gmail-as-mta). With STARTTLS, an initial **unencrypted** connection is made and then upgraded to an encrypted TLS or SSL connection. Instead, with the approach outlined below, an encrypted TLS connection is made from the start. 3522 | 3523 | Also, as discussed in [issue #29](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/29) and [here](https://blog.dhampir.no/content/exim4-line-length-in-debian-stretch-mail-delivery-failed-returning-message-to-sender), exim4 will fail for messages with long lines. We'll fix this in this section too. 3524 | 3525 | ** **IMPORTANT** ** As mentioned in [#106](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/106), Google no longer lets you use your account's password for authentication. You have to enable 2FA and then use an app-password. 3526 | 3527 | #### Goals 3528 | 3529 | - `mail` configured to send e-mails from your server using [Gmail](https://mail.google.com/) 3530 | - long line support for exim4 3531 | 3532 | #### References 3533 | 3534 | - Thanks to [remyabel](https://github.com/remyabel) for figuring out how to get this to work with TLS as documented in [issue #24](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/24) and [pull request #26](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/pull/26). 3535 | - https://wiki.debian.org/Exim 3536 | - https://wiki.debian.org/GmailAndExim4 3537 | - https://www.exim.org/exim-html-current/doc/html/spec_html/ch-encrypted_smtp_connections_using_tlsssl.html 3538 | - https://php.quicoto.com/setup-exim4-to-use-gmail-in-ubuntu/ 3539 | - https://www.fastmail.com/help/technical/ssltlsstarttls.html 3540 | - exim4 fails for messages with long lines - [issue #29](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/29) and https://blog.dhampir.no/content/exim4-line-length-in-debian-stretch-mail-delivery-failed-returning-message-to-sender 3541 | - https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/106 3542 | 3543 | #### Steps 3544 | 3545 | 1. Install exim4. You will also need openssl and ca-certificates. 3546 | 3547 | On Debian based systems: 3548 | 3549 | ``` bash 3550 | sudo apt install exim4 openssl ca-certificates 3551 | ``` 3552 | 3553 | 1. Configure exim4: 3554 | 3555 | For Debian based systems: 3556 | ``` bash 3557 | sudo dpkg-reconfigure exim4-config 3558 | ``` 3559 | 3560 | You'll be prompted with some questions: 3561 | 3562 | |Prompt|Answer| 3563 | |--:|--| 3564 | |General type of mail configuration|`mail sent by smarthost; no local mail`| 3565 | |System mail name|`localhost`| 3566 | |IP-addresses to listen on for incoming SMTP connections|`127.0.0.1; ::1`| 3567 | |Other destinations for which mail is accepted|(default)| 3568 | |Visible domain name for local users|`localhost`| 3569 | |IP address or host name of the outgoing smarthost|`smtp.gmail.com::465`| 3570 | |Keep number of DNS-queries minimal (Dial-on-Demand)?|`No`| 3571 | |Split configuration into small files?|`No`| 3572 | 3573 | 1. Make a backup of `/etc/exim4/passwd.client`: 3574 | 3575 | ``` bash 3576 | sudo cp --archive /etc/exim4/passwd.client /etc/exim4/passwd.client-COPY-$(date +"%Y%m%d%H%M%S") 3577 | ``` 3578 | 3579 | 1. Add a line like this to `/etc/exim4/passwd.client` 3580 | 3581 | ``` 3582 | smtp.gmail.com:yourAccount@gmail.com:yourPassword 3583 | *.google.com:yourAccount@gmail.com:yourPassword 3584 | ``` 3585 | 3586 | **Notes**: 3587 | - Replace `yourAccount@gmail.com` and `yourPassword` with your details. If you have 2FA/MFA enabled on your Gmail then you'll need to create and use an app password here. 3588 | - Always check `host smtp.gmail.com` for the most up-to-date domains to list. 3589 | 3590 | 1. This file has your Gmail password so we need to lock it down: 3591 | 3592 | ``` bash 3593 | sudo chown root:Debian-exim /etc/exim4/passwd.client 3594 | sudo chmod 640 /etc/exim4/passwd.client 3595 | ``` 3596 | 3597 | 1. The next step is to create an TLS certificate that exim4 will use to make the encrypted connection to `smtp.gmail.com`. You can use your own certificate, like one from [Let's Encrypt](https://letsencrypt.org/), or create one yourself using openssl. We will use a script that comes with exim4 that calls openssl to make our certificate: 3598 | 3599 | ``` bash 3600 | sudo bash /usr/share/doc/exim4-base/examples/exim-gencert 3601 | ``` 3602 | 3603 | > ``` 3604 | > [*] Creating a self signed SSL certificate for Exim! 3605 | > This may be sufficient to establish encrypted connections but for 3606 | > secure identification you need to buy a real certificate! 3607 | > 3608 | > Please enter the hostname of your MTA at the Common Name (CN) prompt! 3609 | > 3610 | > Generating a RSA private key 3611 | > ..........................................+++++ 3612 | > ................................................+++++ 3613 | > writing new private key to '/etc/exim4/exim.key' 3614 | > ----- 3615 | > You are about to be asked to enter information that will be incorporated 3616 | > into your certificate request. 3617 | > What you are about to enter is what is called a Distinguished Name or a DN. 3618 | > There are quite a few fields but you can leave some blank 3619 | > For some fields there will be a default value, 3620 | > If you enter '.', the field will be left blank. 3621 | > ----- 3622 | > Country Code (2 letters) [US]:[redacted] 3623 | > State or Province Name (full name) []:[redacted] 3624 | > Locality Name (eg, city) []:[redacted] 3625 | > Organization Name (eg, company; recommended) []:[redacted] 3626 | > Organizational Unit Name (eg, section) []:[redacted] 3627 | > Server name (eg. ssl.domain.tld; required!!!) []:localhost 3628 | > Email Address []:[redacted] 3629 | > [*] Done generating self signed certificates for exim! 3630 | > Refer to the documentation and example configuration files 3631 | > over at /usr/share/doc/exim4-base/ for an idea on how to enable TLS 3632 | > support in your mail transfer agent. 3633 | > ``` 3634 | 3635 | 1. Instruct exim4 to use TLS and port 465, and [fix exim4's long lines issue](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/29), by creating the file `/etc/exim4/exim4.conf.localmacros` and adding: 3636 | 3637 | ``` 3638 | MAIN_TLS_ENABLE = 1 3639 | REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = * 3640 | TLS_ON_CONNECT_PORTS = 465 3641 | REQUIRE_PROTOCOL = smtps 3642 | IGNORE_SMTP_LINE_LENGTH_LIMIT = true 3643 | ``` 3644 | 3645 | [For the lazy](#editing-configuration-files---for-the-lazy): 3646 | 3647 | ``` bash 3648 | cat << EOF | sudo tee /etc/exim4/exim4.conf.localmacros 3649 | MAIN_TLS_ENABLE = 1 3650 | REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = * 3651 | TLS_ON_CONNECT_PORTS = 465 3652 | REQUIRE_PROTOCOL = smtps 3653 | IGNORE_SMTP_LINE_LENGTH_LIMIT = true 3654 | EOF 3655 | ``` 3656 | 3657 | 1. Make a backup of exim4's configuration file `/etc/exim4/exim4.conf.template`: 3658 | 3659 | ``` bash 3660 | sudo cp --archive /etc/exim4/exim4.conf.template /etc/exim4/exim4.conf.template-COPY-$(date +"%Y%m%d%H%M%S") 3661 | ``` 3662 | 3663 | 1. Add the below to `/etc/exim4/exim4.conf.template` after the `.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS ... .endif` block: 3664 | 3665 | ``` 3666 | .ifdef REQUIRE_PROTOCOL 3667 | protocol = REQUIRE_PROTOCOL 3668 | .endif 3669 | ``` 3670 | 3671 | > ``` 3672 | > .ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS 3673 | > hosts_require_tls = REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS 3674 | > .endif 3675 | > .ifdef REQUIRE_PROTOCOL 3676 | > protocol = REQUIRE_PROTOCOL 3677 | > .endif 3678 | > .ifdef REMOTE_SMTP_HEADERS_REWRITE 3679 | > headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE 3680 | > .endif 3681 | > ``` 3682 | 3683 | [For the lazy](#editing-configuration-files---for-the-lazy): 3684 | 3685 | ``` bash 3686 | sudo sed -i -r -e '/^.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS$/I { :a; n; /^.endif$/!ba; a\# added by '"$(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")"'\n.ifdef REQUIRE_PROTOCOL\n protocol = REQUIRE_PROTOCOL\n.endif\n# end add' -e '}' /etc/exim4/exim4.conf.template 3687 | ``` 3688 | 3689 | 1. Add the below to `/etc/exim4/exim4.conf.template` inside the `.ifdef MAIN_TLS_ENABLE` block: 3690 | 3691 | ``` 3692 | .ifdef TLS_ON_CONNECT_PORTS 3693 | tls_on_connect_ports = TLS_ON_CONNECT_PORTS 3694 | .endif 3695 | ``` 3696 | 3697 | > ``` 3698 | > .ifdef MAIN_TLS_ENABLE 3699 | > .ifdef TLS_ON_CONNECT_PORTS 3700 | > tls_on_connect_ports = TLS_ON_CONNECT_PORTS 3701 | > .endif 3702 | > ``` 3703 | 3704 | [For the lazy](#editing-configuration-files---for-the-lazy): 3705 | 3706 | ``` bash 3707 | sudo sed -i -r -e "/\.ifdef MAIN_TLS_ENABLE/ a # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")\n.ifdef TLS_ON_CONNECT_PORTS\n tls_on_connect_ports = TLS_ON_CONNECT_PORTS\n.endif\n# end add" /etc/exim4/exim4.conf.template 3708 | ``` 3709 | 3710 | 1. Update exim4 configuration to use TLS and then restart the service: 3711 | 3712 | ``` bash 3713 | sudo update-exim4.conf 3714 | sudo service exim4 restart 3715 | ``` 3716 | 3717 | 1. If you're using [UFW](#ufw-uncomplicated-firewall), you'll need to allow outbound traffic on 465. To do this we'll create a custom UFW application profile and then enable it. Create the file `/etc/ufw/applications.d/smtptls`, add this, then run `ufw allow out smtptls comment 'open TLS port 465 for use with SMPT to send e-mails'`: 3718 | 3719 | ``` 3720 | [SMTPTLS] 3721 | title=SMTP through TLS 3722 | description=This opens up the TLS port 465 for use with SMPT to send e-mails. 3723 | ports=465/tcp 3724 | ``` 3725 | 3726 | [For the lazy](#editing-configuration-files---for-the-lazy): 3727 | 3728 | ``` bash 3729 | cat << EOF | sudo tee /etc/ufw/applications.d/smtptls 3730 | [SMTPTLS] 3731 | title=SMTP through TLS 3732 | description=This opens up the TLS port 465 for use with SMPT to send e-mails. 3733 | ports=465/tcp 3734 | EOF 3735 | 3736 | sudo ufw allow out smtptls comment 'open TLS port 465 for use with SMPT to send e-mails' 3737 | ``` 3738 | 3739 | 1. Add some mail aliases so we can send e-mails to local accounts by adding lines like this to `/etc/aliases`: 3740 | 3741 | ``` 3742 | user1: user1@gmail.com 3743 | user2: user2@gmail.com 3744 | ... 3745 | ``` 3746 | 3747 | You'll need to add all the local accounts that exist on your server. 3748 | 3749 | 1. Test your setup: 3750 | 3751 | ``` 3752 | echo "test" | mail -s "Test" email@gmail.com 3753 | sudo tail /var/log/exim4/mainlog 3754 | ``` 3755 | 3756 | ([Table of Contents](#table-of-contents)) 3757 | 3758 | ### Separate iptables Log File 3759 | 3760 | #### Why 3761 | 3762 | There will come a time when you'll need to look through your iptables logs. Having all the iptables logs go to their own file will make it a lot easier to find what you're looking for. 3763 | 3764 | #### References 3765 | 3766 | - https://blog.shadypixel.com/log-iptables-messages-to-a-separate-file-with-rsyslog/ 3767 | - https://gist.github.com/netson/c45b2dc4e835761fbccc 3768 | - https://www.rsyslog.com/doc/v8-stable/configuration/actions.html 3769 | 3770 | #### Steps 3771 | 3772 | 1. The first step is by telling your firewall to prefix all log entries with some unique string. If you're using iptables directly, you would do something like `--log-prefix "[IPTABLES] "` for all the rules. We took care of this in [step 4 of installing psad](#psad_step4). 3773 | 3774 | 1. After you've added a prefix to the firewall logs, we need to tell rsyslog to send those lines to its own file. Do this by creating the file `/etc/rsyslog.d/10-iptables.conf` and adding this: 3775 | 3776 | ``` 3777 | :msg, contains, "[IPTABLES] " /var/log/iptables.log 3778 | & stop 3779 | ``` 3780 | 3781 | If you're expecting a lot if data being logged by your firewall, prefix the filename with a `-` ["to omit syncing the file after every logging"](https://www.rsyslog.com/doc/v8-stable/configuration/actions.html#regular-file). For example: 3782 | 3783 | ``` 3784 | :msg, contains, "[IPTABLES] " -/var/log/iptables.log 3785 | & stop 3786 | ``` 3787 | 3788 | **Note**: Remember to change the prefix to whatever you use. 3789 | 3790 | [For the lazy](#editing-configuration-files---for-the-lazy): 3791 | 3792 | ``` bash 3793 | cat << EOF | sudo tee /etc/rsyslog.d/10-iptables.conf 3794 | :msg, contains, "[IPTABLES] " /var/log/iptables.log 3795 | & stop 3796 | EOF 3797 | ``` 3798 | 3799 | 1. Since we're logging firewall messages to a different file, we need to tell psad where the new file is. Edit `/etc/psad/psad.conf` and set `IPT_SYSLOG_FILE` to the path of the log file. For example: 3800 | 3801 | ``` 3802 | IPT_SYSLOG_FILE /var/log/iptables.log; 3803 | ``` 3804 | 3805 | **Note**: Remember to change the prefix to whatever you use. 3806 | 3807 | [For the lazy](#editing-configuration-files---for-the-lazy): 3808 | 3809 | ``` bash 3810 | sudo sed -i -r -e "s/^(IPT_SYSLOG_FILE\s+)([^;]+)(;)$/# \1\2\3 # commented by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")\n\1\/var\/log\/iptables.log\3 # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")/" /etc/psad/psad.conf 3811 | ``` 3812 | 3813 | 1. Restart psad and rsyslog to activate the changes (or reboot): 3814 | 3815 | ``` bash 3816 | sudo psad -R 3817 | sudo psad --sig-update 3818 | sudo psad -H 3819 | sudo service rsyslog restart 3820 | ``` 3821 | 3822 | 1. The last thing we have to do is tell logrotate to rotate the new log file so it doesn't get to big and fill up our disk. Create the file `/etc/logrotate.d/iptables` and add this: 3823 | 3824 | ``` 3825 | /var/log/iptables.log 3826 | { 3827 | rotate 7 3828 | daily 3829 | missingok 3830 | notifempty 3831 | delaycompress 3832 | compress 3833 | postrotate 3834 | invoke-rc.d rsyslog rotate > /dev/null 3835 | endscript 3836 | } 3837 | ``` 3838 | 3839 | [For the lazy](#editing-configuration-files---for-the-lazy): 3840 | 3841 | ``` bash 3842 | cat << EOF | sudo tee /etc/logrotate.d/iptables 3843 | /var/log/iptables.log 3844 | { 3845 | rotate 7 3846 | daily 3847 | missingok 3848 | notifempty 3849 | delaycompress 3850 | compress 3851 | postrotate 3852 | invoke-rc.d rsyslog rotate > /dev/null 3853 | endscript 3854 | } 3855 | EOF 3856 | ``` 3857 | 3858 | ([Table of Contents](#table-of-contents)) 3859 | 3860 | ## Left Over 3861 | 3862 | ### Contacting Me 3863 | 3864 | For any questions, comments, concerns, feedback, or issues, submit a [new issue](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/new). 3865 | 3866 | ([Table of Contents](#table-of-contents)) 3867 | 3868 | ### Helpful Links 3869 | 3870 | - [https://github.com/pratiktri/server_init_harden](https://github.com/pratiktri/server_init_harden) - Bash script that automates few of the tasks that you need to perform on a new Linux server to give it basic amount security. 3871 | 3872 | ([Table of Contents](#table-of-contents)) 3873 | 3874 | ### Acknowledgments 3875 | 3876 | - https://www.reddit.com/r/linuxquestions/comments/aopzl7/new_guide_created_by_me_how_to_secure_a_linux/ 3877 | - https://www.reddit.com/r/selfhosted/comments/aoxd4l/new_guide_created_by_me_how_to_secure_a_linux/ 3878 | - https://news.ycombinator.com/item?id=19177435#19178618 3879 | - https://www.reddit.com/r/linuxadmin/comments/arx7xo/howtosecurealinuxserver_an_evolving_howto_guide/ 3880 | - https://www.reddit.com/r/linux/comments/arx7st/howtosecurealinuxserver_an_evolving_howto_guide/ 3881 | - https://github.com/moltenbit/How-To-Secure-A-Linux-Server-With-Ansible 3882 | 3883 | ([Table of Contents](#table-of-contents)) 3884 | 3885 | ### License and Copyright 3886 | 3887 | [![CC-BY-SA](https://i.creativecommons.org/l/by-sa/4.0/88x31.png)](http://creativecommons.org/licenses/by-sa/4.0/) 3888 | 3889 | [How To Secure A Linux Server](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server) by [Anchal Nigam](https://github.com/imthenachoman) is licensed under [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0). 3890 | 3891 | See [LICENSE](LICENSE.txt) for the full license. 3892 | 3893 | ([Table of Contents](#table-of-contents)) 3894 | --------------------------------------------------------------------------------