FIX: More security hardening
[ta/infra-ansible.git] / roles / ops-hardening / tasks / main.yaml
1 ---
2
3 # Copyright 2019 Nokia
4
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 #     http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 #
18 # Linux password hardening
19 #
20
21 - name: "Set Password Strength Minimum Digit Characters."
22   lineinfile:
23     path: /etc/security/pwquality.conf
24     regexp: '^[#\s]*dcredit'
25     line: 'dcredit = -1'
26
27 - name: "Set Password Minimum Length."
28   lineinfile:
29     path: /etc/security/pwquality.conf
30     regexp: '^[#\s]*minlen'
31     line: 'minlen = 8'
32
33 - name: "Set Password Strength Minimum Uppercase Characters."
34   lineinfile:
35     path: /etc/security/pwquality.conf
36     regexp: '^[#\s]*ucredit'
37     line: 'ucredit = -1'
38
39 - name: "Set Password Strength Minimum Special Characters."
40   lineinfile:
41     path: /etc/security/pwquality.conf
42     regexp: '^[#\s]*ocredit'
43     line: 'ocredit = -1'
44
45 - name: "Set Password Strength Minimum Lowercase Characters."
46   lineinfile:
47     path: /etc/security/pwquality.conf
48     regexp: '^[#\s]*lcredit'
49     line: 'lcredit = -1'
50
51 - name: "Set Password Strength Minimum Different Categories."
52   lineinfile:
53     path: /etc/security/pwquality.conf
54     regexp: '^[#\s]*minclass'
55     line: 'minclass = 3'
56
57 - name: "Set Password Minimum Length in login.defs"
58   lineinfile:
59     path: /etc/login.defs
60     regexp: '^PASS_MIN_LEN[\s]*[0-9]*$'
61     line: 'PASS_MIN_LEN   8'
62
63 - name: "Set Password Minimum Age"
64   lineinfile:
65     path: /etc/login.defs
66     regexp: '^PASS_MIN_DAYS[\s]*[0-9]*$'
67     line: 'PASS_MIN_DAYS   0'
68
69 - name: "Set password hash to SHA512"
70   lineinfile:
71     path: /etc/login.defs
72     regexp: '^ENCRYPT_METHOD[\s]*[a-z0-9]*$'
73     line: 'ENCRYPT_METHOD   SHA512'
74
75 - name: "Set minimum number of password hash rounds"
76   lineinfile:
77     path: /etc/login.defs
78     regexp: '^SHA_CRYPT_MIN_ROUNDS[\s]*[0-9]*$'
79     line: 'SHA_CRYPT_MIN_ROUNDS   10000'
80
81 - name: "Set maximum number of password hash rounds"
82   lineinfile:
83     path: /etc/login.defs
84     regexp: '^SHA_CRYPT_MAX_ROUNDS[\s]*[0-9]*$'
85     line: 'SHA_CRYPT_MAX_ROUNDS   10000'
86
87 #
88 # Linux Failed password attempts
89 #
90 - name: "Ensure authconfig is properly configured"
91   command: authconfig --updateall
92   with_items:
93     - /etc/pam.d/system-auth-ac
94     - /etc/pam.d/password-auth-ac
95   when: not (item|exists and item|is_file)
96   tags:
97     - REC-443
98
99 - name: "Set Deny for failed password attempts 1"
100   lineinfile:
101     path: "{{item}}"
102     insertbefore: '^auth[\s]*sufficient[\s]*pam_unix.so'
103     line: 'auth        required      pam_faillock.so preauth silent audit deny=3 unlock_time=3600 fail_interval=900'
104   with_items:
105     - /etc/pam.d/system-auth-ac
106     - /etc/pam.d/password-auth-ac
107   tags:
108     - REC-443
109
110 - name: "Set Deny for failed password attempts 2"
111   lineinfile:
112     path: "{{item}}"
113     insertafter: '^auth[\s]*sufficient[\s]*pam_unix.so'
114     line: 'auth        [default=die]  pam_faillock.so authfail audit deny=3 unlock_time=3600 fail_interval=900'
115   with_items:
116     - /etc/pam.d/system-auth-ac
117     - /etc/pam.d/password-auth-ac
118   tags:
119     - REC-443
120
121 - name: "Set Deny for failed password attempts 3"
122   lineinfile:
123     path: "{{item}}"
124     insertbefore: '^account[\s]*required[\s]*pam_unix.so'
125     line: 'account     required      pam_faillock.so'
126   with_items:
127     - /etc/pam.d/system-auth-ac
128     - /etc/pam.d/password-auth-ac
129   tags:
130     - REC-443
131
132 - name: "Set Account expiration following inactivity"
133   lineinfile:
134     create: yes
135     path: "/etc/default/useradd"
136     regexp: "^INACTIVE"
137     line: "INACTIVE=35"
138   tags:
139     - REC-443
140
141 #
142 # YUM config
143 #
144
145 - name: "Ensure YUM Removes Previous Package Versions"
146   lineinfile:
147     path: /etc/yum.conf
148     insertafter: '^[#\s]*\[main\]'
149     line: 'clean_requirements_on_remove = 1'
150
151 - name: "Ensure gpgcheck Enabled for Local Packages"
152   lineinfile:
153     path: /etc/yum.conf
154     insertafter: '^[#\s]*\[main\]'
155     line: 'localpkg_gpgcheck = 1'
156
157 #
158 # Setting Ctrl-Alt-Del action
159 #
160
161 - name: "Disable Ctrl-Alt-Del Burst Action"
162   lineinfile:
163     path: /etc/systemd/system.conf
164     insertafter: '^[#\s]*CtrlAltDelBurstAction'
165     line: 'CtrlAltDelBurstAction=none'
166
167 - name: "Disable Ctrl-Alt-Del Reboot Activation"
168   command: systemctl mask ctrl-alt-del.target
169
170 #
171 # Configure kernel modules
172 #
173
174 - name: "kernel module setting"
175   lineinfile:
176     create=yes
177     dest="/etc/modprobe.d/{{item}}.conf"
178     regexp="{{item}}"
179     line="install {{item}} /bin/true"
180   with_items:
181     - bluetooth
182     - dccp
183     - squashfs
184     - hfsplus
185     - hfs
186     - jffs2
187     - freevxfs
188     - cramfs
189     - usb-storage
190     - udf
191     - nfsd
192
193 #
194 # Disable interactive boot
195 #
196
197 - name:  Verify that Interactive Boot is Disabled GRUB_CMDLINE_LINUX Setting
198   lineinfile:
199     path: /etc/default/grub
200     backrefs: yes
201     regexp: '^GRUB_CMDLINE_LINUX=(.*)systemd\.confirm_spawn=(1|yes|true|on)\s*(.*)$'
202     line: 'GRUB_CMDLINE_LINUX=\1\3'
203
204 - name:  Verify that Interactive Boot is Disabled GRUB_CMDLINE_LINUX_DEFAULT Setting
205   lineinfile:
206     path: /etc/default/grub
207     backrefs: yes
208     regexp: '^GRUB_CMDLINE_LINUX_DEFAULT=(.*)systemd\.confirm_spawn=(1|yes|true|on)\s*(.*)$'
209     line: 'GRUB_CMDLINE_LINUX_DEFAULT=\1\3'
210
211 #
212 # Set file permissions
213 #
214
215 - name: "Check files exist to determine the proper location of grub.cfg on UEFI systems"
216   stat: path={{item}}
217   with_items:
218     - /boot/efi/EFI/centos/grub.cfg
219     - /boot/grub2/grub.cfg
220     - /var/log/boot.log
221     - /var/log/cron
222   register: file_stat
223
224 - name: "Set the 600 file permissions"
225   file:
226     path: "{{item.item}}"
227     state: touch
228     mode: "600"
229   with_items: "{{ file_stat.results }}"
230   when:
231     - item.stat.exists == true
232
233 - name: Limit access to the assembler binary
234   file:
235     path: "/usr/bin/as"
236     state: file
237     mode: "0700"
238     owner: root
239     group: root
240
241 #
242 # Disable direct root login
243 #
244
245 - name: "Direct root Logins Not Allowed"
246   shell: echo > /etc/securetty
247
248 - name: Change 'root' shell to nologin
249   user:
250     name: root
251     shell: /sbin/nologin
252
253 - name: Lock 'root' password
254   user:
255     name: root
256     password: '!!'
257
258 #
259 # Configure IPv6
260 #
261
262 - name: Disable ipv6 support if the ipv6 is not needed
263   when: ansible_default_ipv6|length == 0
264   sysctl:
265     name: net.ipv6.conf.all.disable_ipv6
266     value: 1
267     state: present
268     reload: yes
269
270 - name: Disable Support for udp6
271   when: ansible_default_ipv6|length == 0
272   lineinfile:
273     path: /etc/netconfig
274     state: absent
275     regexp: '^udp6.*'
276
277 - name: Disable Support for tcp6
278   when: ansible_default_ipv6|length == 0
279   lineinfile:
280     path: /etc/netconfig
281     state: absent
282     regexp: '^tcp6.*'
283
284 - name: Disable automatic ipv6 configuration and routing
285   sysctl:
286     name: "{{ item.name }}"
287     value: "{{ item.value }}"
288     state: present
289     reload: yes
290   with_items:
291     - { name: 'net.ipv6.conf.all.accept_source_route', value: 0 }
292     - { name: 'net.ipv6.conf.default.accept_source_route', value: 0 }
293     - { name: 'net.ipv6.conf.all.accept_ra', value: 0 }
294     - { name: 'net.ipv6.conf.default.accept_ra', value: 0 }
295     - { name: 'net.ipv6.conf.all.accept_redirects', value: 0 }
296     - { name: 'net.ipv6.conf.default.accept_redirects', value: 0 }
297     - { name: 'net.ipv6.conf.all.forwarding', value: 0 }
298     - { name: 'net.ipv6.conf.default.forwarding', value: 0 }
299
300 #
301 # Configure kernel parameters
302 #
303
304 - name: Configure the kernel parameters
305   sysctl:
306     name: "{{ item.name }}"
307     value: "{{ item.value }}"
308     state: present
309     reload: yes
310   with_items:
311     - { name: 'net.ipv4.conf.default.send_redirects', value: 0 }
312     - { name: 'net.ipv4.conf.all.send_redirects', value: 0 }
313     - { name: 'net.ipv4.ip_forward', value: 0 }
314     - { name: 'net.ipv4.conf.all.accept_redirects', value: 0 }
315     - { name: 'net.ipv4.conf.all.secure_redirects', value: 0 }
316     - { name: 'net.ipv4.conf.all.log_martians', value: 1 }
317     - { name: 'net.ipv4.conf.default.log_martians', value: 1 }
318     - { name: 'net.ipv4.conf.default.accept_redirects', value: 0 }
319     - { name: 'net.ipv4.conf.default.secure_redirects', value: 0 }
320     - { name: 'net.ipv4.icmp_echo_ignore_broadcasts', value: 1 }
321     - { name: 'net.ipv4.icmp_ignore_bogus_error_responses', value: 1 }
322     - { name: 'net.ipv4.tcp_syncookies', value: 1 }
323     - { name: 'fs.suid_dumpable', value: 0 }
324     - { name: 'kernel.dmesg_restrict', value: 1 }
325     - { name: 'kernel.core_uses_pid', value: 1 }
326     - { name: 'kernel.randomize_va_space', value: 2 }
327     - { name: 'kernel.core_pattern', value: '/var/core/core'}
328     - { name: 'kernel.kptr_restrict', value: 2 }
329     - { name: 'kernel.sysrq', value: 0 }
330     - { name: 'kernel.yama.ptrace_scope', value: 3 }
331
332 #
333 # Configure core dump
334 #
335
336 - name: "Disable core dump for all user"
337   lineinfile:
338     path: /etc/security/limits.conf
339     insertbefore: '^[a-z].*'
340     line: '*               hard    core            0'
341
342 - name: "Configure systemd not to store core dumps"
343   lineinfile:
344     path: /etc/systemd/coredump.conf
345     insertafter: '^\[Coredump\]'
346     line: 'Storage=none'
347
348 #
349 # Confingure kernel dump
350 - name: "Disable kernel dump service"
351   shell: systemctl stop kdump.service
352
353 - name: "Disable kernel dump service"
354   shell: systemctl disable kdump.service
355
356 # Configure syslog
357 #
358 - name: "Stop rsyslog Service"
359   shell: systemctl stop rsyslog.service
360
361 - name: "Disable rsyslog Service"
362   shell: systemctl disable rsyslog.service
363
364 - name: "Ensure the /var/log/boot.log Rotated by logrotate"
365   lineinfile:
366     path: /etc/logrotate.d/syslog
367     insertbefore: 'cron$'
368     line: /var/log/boot.log
369
370 - name: "Set the umasks by profile file"
371   lineinfile:
372     path: /etc/profile
373     regexp: '{{ item.old }}'
374     line: '{{ item.new }}'
375   with_items:
376     - { old: 'umask 002', new: umask 027 }
377     - { old: 'umask 022', new: umask 077 }
378
379 #
380 # Keystone config
381 #
382
383 - name: Set the max_request_body_size in the keystone.conf
384   lineinfile:
385     path: /etc/keystone/keystone.conf
386     insertafter: 'DEFAULT'
387     line: "# enforced by optional sizelimit middleware (keystone.middleware:RequestBodySizeLimiter)\nmax_request_body_size = 114688\n"
388
389 - name: Set the insecure_debug in the keystone.conf
390   lineinfile:
391     path: /etc/keystone/keystone.conf
392     insertafter: 'DEFAULT'
393     line: "# If set to true, then the server will return information in HTTP responses\n# that may allow an unauthenticated or authenticated user to get more\n# information than normal, such as additional details about why authentication\n# failed. This may be useful for debugging but is insecure. (boolean value)\ninsecure_debug = false\n"
394
395 #
396 #Setting bootloader password
397 #
398 - name: set host os variable
399   when: host_os is defined
400   set_fact:
401     grub2_pass: "{{  host_os.grub2_password | default('Empty')  }}"
402
403 - name: protect grub with root password
404   when: grub2_pass is defined and grub2_pass != 'Empty'
405   blockinfile:
406     dest: /etc/grub.d/40_custom
407     state: present
408     insertafter: 'EOF'
409     content: |
410       # define superusers
411       set superusers="root"
412       #define users
413       password_pbkdf2 root "{{ grub2_pass }}"
414
415 - name: check whether grub-efi exists
416   stat:
417     path: /boot/efi/EFI/centos/grub.cfg
418   register: grub_efi_file_stat
419
420 - name: generate grub config
421   when: grub2_pass is defined and grub2_pass != 'Empty'
422   command: /usr/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg
423
424 - name: generate grub-efi config
425   command: /usr/sbin/grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
426   when:
427     - grub2_pass is defined and grub2_pass != 'Empty'
428     - grub_efi_file_stat.stat.exists == true
429
430 #
431 #Setting the noexec option to the /dev/shm mount dir
432 #
433
434 - name: get back device associated to mountpoint
435   shell: mount | grep ' /dev/shm ' |cut -d ' ' -f 1
436   register: device_name
437   check_mode: no
438
439 - name: get back device previous mount option
440   shell: mount | grep ' /dev/shm ' | sed -re 's:.*\((.*)\):\1:'
441   register: device_cur_mountoption
442   check_mode: no
443
444 - name: get back device fstype
445   shell: mount | grep ' /dev/shm ' | cut -d ' ' -f 5
446   register: device_fstype
447   check_mode: no
448
449 - name: Ensure permission noexec are set on /dev/shm
450   mount:
451     path: "/dev/shm"
452     src: "{{device_name.stdout}}"
453     opts: "{{device_cur_mountoption.stdout}},noexec"
454     state: "mounted"
455     fstype: "{{device_fstype.stdout}}"
456
457 #
458 # Disable NFS service
459 #
460
461 - name: disable NFS related services
462   service:
463     name: "{{ item }}"
464     enabled: no
465     state: stopped
466   ignore_errors: yes
467   with_items:
468     - nfslock
469     - rpcgssd
470     - rpcidmapd
471     - nfs-idmap
472     - nfs-server
473     - nfs
474
475 - name: remove nfs-utils package
476   yum:
477     name: nfs-utils
478     state: absent
479
480 #
481 # tighten USB permissions
482 #
483 - name: Set USBGuard RestoreControllerDeviceState to false
484   lineinfile:
485     path: /etc/usbguard/usbguard-daemon.conf
486     regexp: '^[#\s]*RestoreControllerDeviceState\s*=\s*[a-z\-]*\s*$'
487     line: 'RestoreControllerDeviceState=false'
488
489 - name: Set USBGuard ImplicitPolicyTarget to block
490   lineinfile:
491     path: /etc/usbguard/usbguard-daemon.conf
492     regexp: '^[#\s]*ImplicitPolicyTarget\s*=\s*[a-z\-]*\s*$'
493     line: 'ImplicitPolicyTarget=block'
494
495 - name: Apply USBGuard policy in all cases
496   lineinfile:
497     path: /etc/usbguard/usbguard-daemon.conf
498     regexp: "^[#\\s]*{{ item }}\\s*=\\s*[a-z\\-]*\\s*$"
499     line: "{{ item }}=apply-policy"
500   with_items:
501     - PresentControllerPolicy
502     - PresentDevicePolicy
503     - InsertedDevicePolicy
504
505 - name: Limit USBGuard IPC to root
506   lineinfile:
507     path: /etc/usbguard/usbguard-daemon.conf
508     regexp: "^[#\\s]*IPCAllowed{{item}}\\s*="
509     line: "IPCAllowed{{item}}=root"
510   with_items:
511     - Users
512     - Groups
513
514 - Name: Ban suspect USB devices
515   blockinfile:
516     # this isn't the optimal way to do this, i know, but i don't
517     # want to create a whole new template tree just to add this.
518     path: /etc/usbguard/rules.conf
519     create: yes
520     owner: root
521     group: root
522     mode: 0700
523     insertbefore: BOF
524     # rules.conf doesn't seem to allow comments
525     marker: ''
526     block: |
527      # the akraino REC is targeted at server installs; as such
528      # we're liberal about allowing standard devices on the
529      # assumption we will be deployed in a relatively secure
530      # environment.  The values below were chosen based on the
531      # devices that appear on a nokia OE19 with the virtual console
532      # enabled:
533      # xHCI controller/hub
534      allow with-interface equals { 09:00:00 }
535      # mass media — sites may want to consider restricting
536      # this to 08:06:50 to just get the virtual CDROM and ban
537      # other USB media
538      allow with-interface equals { 08:*:* }
539      # ethernet
540      allow with-interface equals { 02:02:ff }
541      # keyboard/mouse
542      allow with-interface one-of { 03:00:01 03:01:01 }
543      # per usbguard-rules.conf manpage: ban keyboard devices
544      # that expose other, suspicious, interfaces
545      reject with-interface all-of { 08:*:* 03:00:* }
546      reject with-interface all-of { 08:*:* 03:01:* }
547      reject with-interface all-of { 08:*:* e0:*:* }
548      reject with-interface all-of { 08:*:* 02:*:* }
549
550 # Setting file permissions
551 #
552
553 #- name: "Remove the other user write permission from the system directorys"
554 #  command: find / -xdev \( -perm -0002 -a ! -perm -1000 \) -type d -exec chmod o-w {} \;
555 #
556 #- name: "Remove the other user write permission from the system files"
557 #  command: find / -xdev -perm -0002 -type f -exec chmod o-w {} \;
558 #
559 #- name: "Modified the unauthorized SUID/SGID system executables"
560 #  command: sudo chmod -s $(sudo find / -xdev \( -perm -4000 -o -perm -2000 \) -type f | grep -v sudo)