diff --git a/.kitchen.vagrant.yml b/.kitchen.vagrant.yml index d4afa3cf..0ee1c7ca 100644 --- a/.kitchen.vagrant.yml +++ b/.kitchen.vagrant.yml @@ -24,10 +24,6 @@ transport: max_ssh_sessions: 5 platforms: -- name: ubuntu-12.04 - driver_config: - box: opscode-ubuntu-12.04 - box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_ubuntu-12.04_chef-provisionerless.box - name: ubuntu-14.04 driver_config: box: opscode-ubuntu-14.04 diff --git a/.kitchen.yml b/.kitchen.yml index 8b0802a1..56b9b979 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -22,8 +22,6 @@ provisioner: http_proxy: <%= ENV['http_proxy'] || nil %> https_proxy: <%= ENV['https_proxy'] || nil %> playbook: default.yml - ansible_extra_flags: - - "--skip-tags=sysctl" platforms: - name: centos6-ansible-latest @@ -42,10 +40,6 @@ platforms: driver: image: rndmh3ro/docker-oracle7-ansible:latest platform: centos -- name: ubuntu1204-ansible-latest - driver: - image: rndmh3ro/docker-ubuntu1204-ansible:latest - platform: ubuntu - name: ubuntu1404-ansible-latest driver: image: rndmh3ro/docker-ubuntu1404-ansible:latest diff --git a/.travis.yml b/.travis.yml index ce7281d0..2a0c5782 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,10 +29,6 @@ env: version: latest init: /sbin/init - - distro: ubuntu1204 - version: latest - init: /sbin/init - - distro: debian7 version: latest init: /sbin/init @@ -55,10 +51,10 @@ script: # Run container in detached state. - 'docker run --detach --volume="${PWD}":/etc/ansible/roles/ansible-os-hardening:ro ${run_opts} rndmh3ro/docker-${distro}-ansible:${version} "${init}" > "${container_id}"' - # Test role. + # Test role. - 'docker exec "$(cat ${container_id})" ansible-playbook /etc/ansible/roles/ansible-os-hardening/default.yml --skip-tags "sysctl"' - # Verify role + # Verify role - 'inspec exec https://github.com/dev-sec/linux-baseline/ -t docker://$(cat ${container_id}) --controls=os-01 os-02 os-03 os-04 os-05 os-06 os-07 package-01 package-02 package-03 package-04 package-05 package-06' notifications: diff --git a/README.md b/README.md index a7be8899..b3b73498 100644 --- a/README.md +++ b/README.md @@ -78,59 +78,17 @@ We remove the following packages: ## Changing sysctl variables - -If you want to overwrite sysctl-variables, you have to overwrite the *whole* dict, or else only the single overwritten will be actually used. -So for example if you want to change the IPv4 traffic forwarding variable to `1`, you must pass the whole dict like this: ++If you want to overwrite sysctl-variables, you can use the `sysctl_overwrite` variable (in older versions you had to overwrite the whole `sysctl_dict`). ++So for example if you want to change the IPv4 traffic forwarding variable to `1`, do it like this: ``` - hosts: localhost roles: - dev-sec.os-hardening vars: - sysctl_config: + sysctl_overwrite: # Disable IPv4 traffic forwarding. net.ipv4.ip_forward: 1 - - # Disable IPv6 traffic forwarding. - net.ipv6.conf.all.forwarding: 0 - - # ignore RAs on Ipv6. - net.ipv6.conf.all.accept_ra: 0 - net.ipv6.conf.default.accept_ra: 0 - - # Enable RFC-recommended source validation feature. - net.ipv4.conf.all.rp_filter: 1 - net.ipv4.conf.default.rp_filter: 1 - - # Reduce the surface on SMURF attacks. - # Make sure to ignore ECHO broadcasts, which are only required in broad network analysis. - net.ipv4.icmp_echo_ignore_broadcasts: 1 - - # There is no reason to accept bogus error responses from ICMP, so ignore them instead. - net.ipv4.icmp_ignore_bogus_error_responses: 1 - - # Limit the amount of traffic the system uses for ICMP. - net.ipv4.icmp_ratelimit: 100 - - # Adjust the ICMP ratelimit to include ping, dst unreachable, - # source quench, ime exceed, param problem, timestamp reply, information reply - net.ipv4.icmp_ratemask: 88089 - - # Disable IPv6 - net.ipv6.conf.all.disable_ipv6: 1 - - # Protect against wrapping sequence numbers at gigabit speeds - net.ipv4.tcp_timestamps: 0 - - # Define restriction level for announcing the local source IP - net.ipv4.conf.all.arp_ignore: 1 - - # Define mode for sending replies in response to - # received ARP requests that resolve local target IP addresses - net.ipv4.conf.all.arp_announce: 2 - - # RFC 1337 fix F1 - net.ipv4.tcp_rfc1337: 1 ``` Alternatively you can change Ansible's [hash-behaviour](https://docs.ansible.com/ansible/intro_configuration.html#hash-behaviour) to `merge`, then you only have to overwrite the single hash you need to. But please be aware that changing the hash-behaviour changes it for all your playbooks and is not recommended by Ansible. @@ -152,27 +110,27 @@ bundle install ### Testing with Docker ``` # fast test on one machine -bundle exec kitchen test default-ubuntu-1204 +bundle exec kitchen test default-ubuntu-1404 # test on all machines bundle exec kitchen test # for development -bundle exec kitchen create default-ubuntu-1204 -bundle exec kitchen converge default-ubuntu-1204 +bundle exec kitchen create default-ubuntu-1404 +bundle exec kitchen converge default-ubuntu-1404 ``` ### Testing with Virtualbox ``` # fast test on one machine -KITCHEN_YAML=".kitchen.vagrant.yml" bundle exec kitchen test default-ubuntu-1204 +KITCHEN_YAML=".kitchen.vagrant.yml" bundle exec kitchen test default-ubuntu-1404 # test on all machines KITCHEN_YAML=".kitchen.vagrant.yml" bundle exec kitchen test # for development -KITCHEN_YAML=".kitchen.vagrant.yml" bundle exec kitchen create default-ubuntu-1204 -KITCHEN_YAML=".kitchen.vagrant.yml" bundle exec kitchen converge default-ubuntu-1204 +KITCHEN_YAML=".kitchen.vagrant.yml" bundle exec kitchen create default-ubuntu-1404 +KITCHEN_YAML=".kitchen.vagrant.yml" bundle exec kitchen converge default-ubuntu-1404 ``` For more information see [test-kitchen](http://kitchen.ci/docs/getting-started) diff --git a/default.yml b/default.yml index 379e5bc7..719e1ec3 100644 --- a/default.yml +++ b/default.yml @@ -13,8 +13,47 @@ os_auth_allow_homeless: true os_security_suid_sgid_blacklist: ['/bin/umount'] os_security_suid_sgid_whitelist: ['/usr/bin/rlogin'] + sysctl_config: + net.ipv4.ip_forward: 0 + net.ipv6.conf.all.forwarding: 0 + net.ipv6.conf.all.accept_ra: 0 + net.ipv6.conf.default.accept_ra: 0 + net.ipv4.conf.all.rp_filter: 1 + net.ipv4.conf.default.rp_filter: 1 + net.ipv4.icmp_echo_ignore_broadcasts: 1 + net.ipv4.icmp_ignore_bogus_error_responses: 1 + net.ipv4.icmp_ratelimit: 100 + net.ipv4.icmp_ratemask: 88089 + net.ipv6.conf.all.disable_ipv6: 1 + net.ipv4.conf.all.arp_ignore: 1 + net.ipv4.conf.all.arp_announce: 2 + net.ipv4.conf.all.shared_media: 1 + net.ipv4.conf.default.shared_media: 1 + net.ipv4.conf.all.accept_source_route: 0 + net.ipv4.conf.default.accept_source_route: 0 + net.ipv4.conf.default.accept_redirects: 0 + net.ipv4.conf.all.accept_redirects: 0 + net.ipv4.conf.all.secure_redirects: 0 + net.ipv4.conf.default.secure_redirects: 0 + net.ipv6.conf.default.accept_redirects: 0 + net.ipv6.conf.all.accept_redirects: 0 + net.ipv4.conf.all.send_redirects: 0 + net.ipv4.conf.default.send_redirects: 0 + net.ipv4.conf.all.log_martians: 1 + net.ipv6.conf.default.router_solicitations: 0 + net.ipv6.conf.default.accept_ra_rtr_pref: 0 + net.ipv6.conf.default.accept_ra_pinfo: 0 + net.ipv6.conf.default.accept_ra_defrtr: 0 + net.ipv6.conf.default.autoconf: 0 + net.ipv6.conf.default.dad_transmits: 0 + net.ipv6.conf.default.max_addresses: 1 + kernel.sysrq: 0 + fs.suid_dumpable: 0 + kernel.randomize_va_space: 2 + - name: wrapper playbook for kitchen testing "ansible-os-hardening" hosts: localhost roles: - ansible-os-hardening + diff --git a/defaults/main.yml b/defaults/main.yml index 17456833..41df4638 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -58,10 +58,6 @@ ufw_default_application_policy: 'SKIP' ufw_manage_builtins: 'no' ufw_ipt_modules: 'nf_conntrack_ftp nf_nat_ftp nf_conntrack_netbios_ns' -# CAUTION -# If you want to overwrite sysctl-variables, -# you have to overwrite the *whole* dict, or else only the single overwritten will be actually used. - sysctl_config: # Disable IPv4 traffic forwarding. net.ipv4.ip_forward: 0 @@ -107,9 +103,73 @@ sysctl_config: # RFC 1337 fix F1 net.ipv4.tcp_rfc1337: 1 -# CAUTION -# If you want to overwrite sysctl-variables, -# you have to overwrite the *whole* dict, or else only the single overwritten will be actually used. + # Send(router) or accept(host) RFC1620 shared media redirects + net.ipv4.conf.all.shared_media: 1 + net.ipv4.conf.default.shared_media: 1 + + # Accepting source route can lead to malicious networking behavior, + # so disable it if not needed. + net.ipv4.conf.all.accept_source_route: 0 + net.ipv4.conf.default.accept_source_route: 0 + + # Accepting redirects can lead to malicious networking behavior, so disable + # it if not needed. + net.ipv4.conf.default.accept_redirects: 0 + net.ipv4.conf.all.accept_redirects: 0 + net.ipv4.conf.all.secure_redirects: 0 + net.ipv4.conf.default.secure_redirects: 0 + net.ipv6.conf.default.accept_redirects: 0 + net.ipv6.conf.all.accept_redirects: 0 + + # For non-routers: don't send redirects, these settings are 0 + net.ipv4.conf.all.send_redirects: 0 + net.ipv4.conf.default.send_redirects: 0 + + # log martian packets + net.ipv4.conf.all.log_martians: 1 + + # ipv6 config + # NSA 2.5.3.2.5 Limit Network-Transmitted Configuration + net.ipv6.conf.default.router_solicitations: 0 + net.ipv6.conf.default.accept_ra_rtr_pref: 0 + net.ipv6.conf.default.accept_ra_pinfo: 0 + net.ipv6.conf.default.accept_ra_defrtr: 0 + net.ipv6.conf.default.autoconf: 0 + net.ipv6.conf.default.dad_transmits: 0 + net.ipv6.conf.default.max_addresses: 1 + + # This settings controls how the kernel behaves towards module changes at + # runtime. Setting to 1 will disable module loading at runtime. + # Setting it to 0 is actually never supported. + # kernel.modules_disabled: 1 + + # Magic Sysrq should be disabled, but can also be set to a safe value if so + # desired for physical machines. It can allow a safe reboot if the system hangs + # and is a 'cleaner' alternative to hitting the reset button. + # The following values are permitted: + # * **0** - disable sysrq + # * **1** - enable sysrq completely + # * **>1** - bitmask of enabled sysrq functions: + # * **2** - control of console logging level + # * **4** - control of keyboard (SAK, unraw) + # * **8** - debugging dumps of processes etc. + # * **16** - sync command + # * **32** - remount read-only + # * **64** - signalling of processes (term, kill, oom-kill) + # * **128** - reboot/poweroff + # * **256** - nicing of all RT tasks + kernel.sysrq: 0 + + # Prevent core dumps with SUID. These are usually only + # needed by developers and may contain sensitive information. + fs.suid_dumpable: 0 + + # Virtual memory regions protection + kernel.randomize_va_space: 2 + +# Do not delete the following line or otherwise the playbook will fail +# at task "create a combined sysctl-dict if overwrites are defined" +sysctl_overwrite: sysctl_rhel_config: # ExecShield protection against buffer overflows diff --git a/tasks/rhosts.yml b/tasks/rhosts.yml index 2ea15e7a..12f966c8 100644 --- a/tasks/rhosts.yml +++ b/tasks/rhosts.yml @@ -7,7 +7,7 @@ - name: delete rhosts-files from system | DTAG SEC Req 3.21-4 file: dest='~{{ item }}/.rhosts' state=absent - with_items: '{{ users.stdout_lines | default(omit) }}' + with_flattened: '{{ users.stdout_lines | default([]) }}' - name: delete hosts.equiv from system | DTAG SEC Req 3.21-4 file: dest='/etc/hosts.equiv' state=absent diff --git a/tasks/suid_sgid.yml b/tasks/suid_sgid.yml index f692ad1d..603c80c8 100644 --- a/tasks/suid_sgid.yml +++ b/tasks/suid_sgid.yml @@ -2,7 +2,7 @@ - name: remove suid/sgid bit from binaries in blacklist file: path='{{item}}' mode='a-s' state=file follow=yes failed_when: false - with_items: + with_flattened: - '{{ os_security_suid_sgid_system_blacklist }}' - '{{ os_security_suid_sgid_blacklist }}' @@ -19,6 +19,6 @@ - name: remove suid/sgid bit from all binaries except in system and user whitelist file: path='{{item}}' mode='a-s' state=file follow=yes - with_items: - - '{{ suid | default(omit) | difference(os_security_suid_sgid_whitelist) }}' + with_flattened: + - '{{ suid | default([]) | difference(os_security_suid_sgid_whitelist) }}' when: os_security_suid_sgid_remove_from_unknown diff --git a/tasks/sysctl.yml b/tasks/sysctl.yml index 38f03cc6..46f8aa7d 100644 --- a/tasks/sysctl.yml +++ b/tasks/sysctl.yml @@ -19,6 +19,10 @@ command: 'update-initramfs -u' when: initramfs.changed +- name: create a combined sysctl-dict if overwrites are defined + set_fact: sysctl_config="{{ sysctl_config | combine(sysctl_overwrite) }}" + when: sysctl_overwrite | default() + - name: Change various sysctl-settings, look at the sysctl-vars file for documentation sysctl: name: '{{ item.key }}' diff --git a/tasks/user_accounts.yml b/tasks/user_accounts.yml index 01a62a19..1b456401 100644 --- a/tasks/user_accounts.yml +++ b/tasks/user_accounts.yml @@ -31,5 +31,5 @@ - name: change system accounts not on the user provided ignore-list user: name='{{item}}' shell='{{os_nologin_shell_path}}' password='*' - with_items: - - '{{sys_accs_cond | default(omit) | difference(os_ignore_users) | list }}' + with_flattened: + - '{{sys_accs_cond | default([]) | difference(os_ignore_users) | list }}' diff --git a/tasks/yum.yml b/tasks/yum.yml index 128b0955..2c3b9b47 100644 --- a/tasks/yum.yml +++ b/tasks/yum.yml @@ -21,7 +21,7 @@ # https://stackoverflow.com/questions/37067827/ansible-deprecation-warning-for-undefined-variable-despite-when-clause - name: activate gpg-check for yum-repos replace: dest='{{item}}' regexp='^\s*gpgcheck=0' replace='gpgcheck=1' - with_items: + with_flattened: - '/etc/yum.conf' - '{{ yum_repos.stdout_lines| default([]) }}'