diff --git a/test/integration/ufw/controls/config_spec.rb b/test/integration/ufw/controls/config_spec.rb new file mode 100644 index 0000000..b751875 --- /dev/null +++ b/test/integration/ufw/controls/config_spec.rb @@ -0,0 +1,68 @@ +control 'UFW configuration' do + + title 'Test UFW configuration' + + describe directory('/etc/ufw') do + it { should exist } + end + + describe file('/etc/ufw/ufw.conf') do + its('content') { should include 'ENABLED=' } + its('content') { should include 'LOGLEVEL=' } + end + + describe command('ufw status verbose | grep Status') do + its('exit_status') { should eq 0 } + its('stdout') { should match /active/ } + end + + describe command('ufw status verbose | grep Logging') do + its('exit_status') { should eq 0 } + its('stdout') { should match /low/ } + end + + describe command('ufw status | grep MySQL') do + its('exit_status') { should eq 0 } + its('stdout') { should match /ALLOW/ } + end + + describe command('ufw status | grep Postgresql') do + its('exit_status') { should eq 0 } + its('stdout') { should match /LIMIT/ } + end + + describe command('ufw status | grep SSH223') do + its('exit_status') { should eq 0 } + its('stdout') { should match /DENY/ } + end + + describe command('ufw status | grep 10.0.0.0') do + its('exit_status') { should eq 0 } + its('stdout') { should match /DENY/ } + end + + describe command('ufw status | grep 22/tcp') do + its('exit_status') { should eq 0 } + its('stdout') { should match /LIMIT/ } + end + + describe command('ufw status | grep 80/tcp') do + its('exit_status') { should eq 0 } + its('stdout') { should match /DENY/ } + end + + describe command('ufw status | grep 443/tcp') do + its('exit_status') { should eq 0 } + its('stdout') { should match /ALLOW/ } + end + + describe command('ufw status | grep 10.0.0.1') do + its('exit_status') { should eq 0 } + its('stdout') { should match /DENY/ } + end + + describe command('ufw status | grep 10.0.0.2') do + its('exit_status') { should eq 0 } + its('stdout') { should match /DENY/ } + end +end diff --git a/test/integration/ufw/controls/package_spec.rb b/test/integration/ufw/controls/package_spec.rb new file mode 100644 index 0000000..61fbccb --- /dev/null +++ b/test/integration/ufw/controls/package_spec.rb @@ -0,0 +1,7 @@ +control 'UFW package' do + title 'should be installed' + + describe package('ufw') do + it { should be_installed } + end +end diff --git a/test/integration/ufw/controls/ufw.rb b/test/integration/ufw/controls/ufw.rb deleted file mode 100644 index 1727e9f..0000000 --- a/test/integration/ufw/controls/ufw.rb +++ /dev/null @@ -1,71 +0,0 @@ -# encoding: utf-8 - -title 'Test Ufw installation' - -describe package('ufw') do - it { should be_installed } -end - -describe directory('/etc/ufw') do - it { should exist } -end - -describe file('/etc/ufw/ufw.conf') do - its('content') { should include 'ENABLED=' } - its('content') { should include 'LOGLEVEL=' } -end - -describe command('ufw status verbose | grep Status') do - its('exit_status') { should eq 0 } - its('stdout') { should match /active/ } -end - -describe command('ufw status verbose | grep Logging') do - its('exit_status') { should eq 0 } - its('stdout') { should match /low/ } -end - -describe command('ufw status | grep MySQL') do - its('exit_status') { should eq 0 } - its('stdout') { should match /ALLOW/ } -end - -describe command('ufw status | grep Postgresql') do - its('exit_status') { should eq 0 } - its('stdout') { should match /LIMIT/ } -end - -describe command('ufw status | grep SSH223') do - its('exit_status') { should eq 0 } - its('stdout') { should match /DENY/ } -end - -describe command('ufw status | grep 10.0.0.0') do - its('exit_status') { should eq 0 } - its('stdout') { should match /DENY/ } -end - -describe command('ufw status | grep 22/tcp') do - its('exit_status') { should eq 0 } - its('stdout') { should match /LIMIT/ } -end - -describe command('ufw status | grep 80/tcp') do - its('exit_status') { should eq 0 } - its('stdout') { should match /DENY/ } -end - -describe command('ufw status | grep 443/tcp') do - its('exit_status') { should eq 0 } - its('stdout') { should match /ALLOW/ } -end - -describe command('ufw status | grep 10.0.0.1') do - its('exit_status') { should eq 0 } - its('stdout') { should match /DENY/ } -end - -describe command('ufw status | grep 10.0.0.2') do - its('exit_status') { should eq 0 } - its('stdout') { should match /DENY/ } -end diff --git a/ufw/config/applications.sls b/ufw/config/applications.sls new file mode 100644 index 0000000..d78f02b --- /dev/null +++ b/ufw/config/applications.sls @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- set sls_package_install = tplroot ~ '.package.install' %} +{%- set sls_enable_service = tplroot ~ '.service.enable' %} +{%- set sls_reload_service = tplroot ~ '.service.reload' %} +{%- from tplroot ~ "/map.jinja" import ufw with context %} + +include: + - {{ sls_package_install }} + - {{ sls_enable_service }} + - {{ sls_reload_service }} + +# Applications +{%- for app_name, app_details in ufw.get('applications', {}).items() %} + + {%- set from_addr_raw = app_details.get('from_addr', [None]) %} + {%- set from_addrs = [from_addr_raw] if from_addr_raw is string else from_addr_raw %} + + {%- for from_addr in from_addrs %} + {%- set deny = app_details.get('deny', None) %} + {%- set limit = app_details.get('limit', None) %} + {%- set method = 'deny' if deny else ('limit' if limit else 'allow') %} + {%- set to_addr = app_details.get('to_addr', None) %} + {%- set comment = app_details.get('comment', None) %} + +{%- if from_addr is not none %} +ufw-app-{{method}}-{{app_name}}-{{from_addr}}: +{%- else %} +ufw-app-{{method}}-{{app_name}}: +{%- endif %} + ufw.{{method}}: + - app: '"{{app_name}}"' + {%- if from_addr is not none %} + - from_addr: {{from_addr}} + {%- endif %} + {%- if to_addr is not none %} + - to_addr: {{to_addr}} + {%- endif %} + {%- if comment is not none %} + - comment: '"{{comment}}"' + {%- endif %} + - listen_in: + - cmd: reload-ufw + + {%- endfor %} +{%- endfor %} diff --git a/ufw/config/file.sls b/ufw/config/file.sls new file mode 100644 index 0000000..fb2b21d --- /dev/null +++ b/ufw/config/file.sls @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- set sls_package_install = tplroot ~ '.package.install' %} +{%- from tplroot ~ "/map.jinja" import ufw with context %} +{%- from tplroot ~ "/libtofs.jinja" import files_switch with context %} + +include: + - {{ sls_package_install }} + +ufw-default-file-file-managed: + file.managed: + - name: {{ ufw.default_file }} + - user: root + - group: root + - template: jinja + - source: {{ files_switch(['ufw.default.tmpl', 'ufw.default.tmpl.jinja'], + lookup='ufw-default-file-file-managed' + ) + }} + - require: + - sls: {{ sls_package_install }} + - context: + ufw_settings: {{ ufw.settings | json }} + +ufw-sysctl-file-file-managed: + file.managed: + - name: {{ ufw.sysctl_file }} + - user: root + - group: root + - template: jinja + - source: {{ files_switch(['ufw.sysctl.tmpl', 'ufw.sysctl.tmpl.jinja'], + lookup='ufw-sysctl-file-file-managed' + ) + }} + - require: + - sls: {{ sls_package_install }} + - context: + ufw_sysctl: {{ ufw.sysctl | json }} + +/etc/ufw/applications.d: + file.recurse: + - user: root + - group: root + - file_mode: 644 + - clean: False + - source: salt://ufw/files/applications.d diff --git a/ufw/config/init.sls b/ufw/config/init.sls new file mode 100644 index 0000000..f4748cb --- /dev/null +++ b/ufw/config/init.sls @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .file + - .services + - .applications + - .interfaces + - .open diff --git a/ufw/config/interfaces.sls b/ufw/config/interfaces.sls new file mode 100644 index 0000000..2df51fc --- /dev/null +++ b/ufw/config/interfaces.sls @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- set sls_package_install = tplroot ~ '.package.install' %} +{%- set sls_enable_service = tplroot ~ '.service.enable' %} +{%- set sls_reload_service = tplroot ~ '.service.reload' %} +{%- from tplroot ~ "/map.jinja" import ufw with context %} + +include: + - {{ sls_package_install }} + - {{ sls_enable_service }} + - {{ sls_reload_service }} + +# Interfaces +{%- for interface_name, interface_details in ufw.get('interfaces', {}).items() %} + {%- set comment = interface_details.get('comment', None) %} + +ufw-interface-{{interface_name}}: + ufw.allowed: + - interface: {{interface_name}} + {%- if comment is not none %} + - comment: '"{{comment}}"' + {%- endif %} + - listen_in: + - cmd: reload-ufw + +{%- endfor %} diff --git a/ufw/config/open.sls b/ufw/config/open.sls new file mode 100644 index 0000000..cc9db16 --- /dev/null +++ b/ufw/config/open.sls @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- set sls_package_install = tplroot ~ '.package.install' %} +{%- set sls_enable_service = tplroot ~ '.service.enable' %} +{%- set sls_reload_service = tplroot ~ '.service.reload' %} +{%- from tplroot ~ "/map.jinja" import ufw with context %} + +include: + - {{ sls_package_install }} + - {{ sls_enable_service }} + - {{ sls_reload_service }} + +# Open +{%- for open_addr, open_details in ufw.get('open', {}).items() %} + {%- set comment = open_details.get('comment', None) %} + +ufw-open-{{open_addr}}: + ufw.allowed: + - from_addr: {{open_addr}} + {%- if comment is not none %} + - comment: '"{{comment}}"' + {%- endif %} + - listen_in: + - cmd: reload-ufw + +{%- endfor %} diff --git a/ufw/config/services.sls b/ufw/config/services.sls new file mode 100644 index 0000000..dd549d9 --- /dev/null +++ b/ufw/config/services.sls @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- set sls_package_install = tplroot ~ '.package.install' %} +{%- set sls_enable_service = tplroot ~ '.service.enable' %} +{%- set sls_reload_service = tplroot ~ '.service.reload' %} +{%- from tplroot ~ "/map.jinja" import ufw with context %} + +include: + - {{ sls_package_install }} + - {{ sls_enable_service }} + - {{ sls_reload_service }} + +# Services +{%- for service_name, service_details in ufw.get('services', {}).items() %} + + {%- set from_addr_raw = service_details.get('from_addr', [None]) %} + {%- set from_addrs = [from_addr_raw] if from_addr_raw is string else from_addr_raw %} + + {%- for from_addr in from_addrs %} + {%- set protocol = service_details.get('protocol', None) %} + {%- set deny = service_details.get('deny', None) %} + {%- set limit = service_details.get('limit', None) %} + {%- set method = 'deny' if deny else ('limit' if limit else 'allow') %} + {%- set from_port = service_details.get('from_port', None) %} + {%- set to_addr = service_details.get('to_addr', None) %} + {%- set to_port = service_details.get('to_port', service_name) %} + {%- set comment = service_details.get('comment', None) %} + +ufw-svc-{{method}}-{{service_name}}-{{from_addr}}: + ufw.{{method}}: + {%- if protocol is not none %} + - protocol: {{protocol}} + {%- endif %} + {%- if from_addr is not none %} + - from_addr: {{from_addr}} + {%- endif %} + {%- if from_port is not none %} + - from_port: "{{from_port}}" + {%- endif %} + {%- if to_addr is not none %} + - to_addr: {{to_addr}} + {%- endif %} + {%- if comment is not none %} + - comment: '"{{comment}}"' + {%- endif %} + - to_port: "{{to_port}}" + - listen_in: + - cmd: reload-ufw + + {%- endfor %} +{%- endfor %} diff --git a/ufw/defaults.yaml b/ufw/defaults.yaml index 2c35817..b8e1f14 100644 --- a/ufw/defaults.yaml +++ b/ufw/defaults.yaml @@ -1,2 +1,17 @@ -ufwmap: - pkg: ufw +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +ufw: + package: ufw + packages: [] + service: + name: ufw + default_file: /etc/default/ufw + sysctl_file: /etc/ufw/sysctl.conf + enabled: false + settings: {} + sysctl: {} + services: {} + applications: {} + interfaces: {} + open: {} diff --git a/ufw/files/applications.d/ufw-databaseserver b/ufw/files/applications.d/ufw-databaseserver index d46fdec..889fd4d 100644 --- a/ufw/files/applications.d/ufw-databaseserver +++ b/ufw/files/applications.d/ufw-databaseserver @@ -12,7 +12,3 @@ ports=3306/tcp title=Postgresql database server description=Postgresql database server. ports=5432/tcp - - - - diff --git a/ufw/templates/default.jinja b/ufw/files/default/ufw.default.tmpl.jinja similarity index 65% rename from ufw/templates/default.jinja rename to ufw/files/default/ufw.default.tmpl.jinja index 18d8b8a..6ce36a0 100644 --- a/ufw/templates/default.jinja +++ b/ufw/files/default/ufw.default.tmpl.jinja @@ -1,17 +1,15 @@ -{% set ufw_cfg = pillar.get('ufw', {}) -%} -{% set settings_cfg = ufw_cfg.get('settings', {}) -%} -{% set ipv6 = "yes" if settings_cfg.get('ipv6', True) else "no" -%} -{% set default_input_policy = settings_cfg.get('default_input_policy', 'DROP') -%} -{% set default_output_policy = settings_cfg.get('default_output_policy', 'ACCEPT') -%} -{% set default_forward_policy = settings_cfg.get('default_forward_policy', 'DROP') -%} -{% set default_application_policy = settings_cfg.get('default_application_policy', 'SKIP') -%} -{% set manage_builtins = "yes" if settings_cfg.get('manage_builtins', False) else "no" -%} -{% set ipt_sysctl = settings_cfg.get('ipt_sysctl', '/etc/ufw/sysctl.conf') -%} -{% set ipt_modules = settings_cfg.get('ipt_modules', ['nf_conntrack_ftp', 'nf_nat_ftp', 'nf_conntrack_netbios_ns'])|join(" ") -%} - -# /etc/default/ufw -# -# File managed by Salt. Do not edit manually. +######################################################################## +# File managed by Salt at <{{ source }}>. +# Your changes will be overwritten. +######################################################################## +{%- set ipv6 = "yes" if ufw_settings.get('ipv6', True) else "no" %} +{%- set default_input_policy = ufw_settings.get('default_input_policy', 'DROP') %} +{%- set default_output_policy = ufw_settings.get('default_output_policy', 'ACCEPT') %} +{%- set default_forward_policy = ufw_settings.get('default_forward_policy', 'DROP') %} +{%- set default_application_policy = ufw_settings.get('default_application_policy', 'SKIP') %} +{%- set manage_builtins = "yes" if ufw_settings.get('manage_builtins', False) else "no" %} +{%- set ipt_sysctl = ufw_settings.get('ipt_sysctl', '/etc/ufw/sysctl.conf') %} +{%- set ipt_modules = ufw_settings.get('ipt_modules', ['nf_conntrack_ftp', 'nf_nat_ftp', 'nf_conntrack_netbios_ns'])|join(" ") %} # Set to yes to apply rules to support IPv6 (no means only IPv6 on loopback # accepted). You will need to 'disable' and then 'enable' the firewall for diff --git a/ufw/templates/sysctl.jinja b/ufw/files/default/ufw.sysctl.tmpl.jinja similarity index 68% rename from ufw/templates/sysctl.jinja rename to ufw/files/default/ufw.sysctl.tmpl.jinja index f2b4b68..c58e4ea 100644 --- a/ufw/templates/sysctl.jinja +++ b/ufw/files/default/ufw.sysctl.tmpl.jinja @@ -1,23 +1,23 @@ -{% set ufw_cfg = pillar.get('ufw', {}) -%} -{% set sysctl_cfg = ufw_cfg.get('sysctl', {}) -%} -{% set forwarding = sysctl_cfg.get('forwarding', 0) -%} -{% set rp_filter = sysctl_cfg.get('rp_filter', 1) -%} -{% set accept_source_route = sysctl_cfg.get('accept_source_route', 0) -%} -{% set accept_redirects = sysctl_cfg.get('accept_redirects', 0) -%} -{% set icmp_echo_ignore_broadcasts = sysctl_cfg.get('icmp_echo_ignore_broadcasts', 1) -%} -{% set icmp_ignore_bogus_error_responses = sysctl_cfg.get('icmp_ignore_bogus_error_responses', 1) -%} -{% set icmp_echo_ignore_all = sysctl_cfg.get('icmp_echo_ignore_all', 0) -%} -{% set log_martians = sysctl_cfg.get('log_martians', 0) -%} -{% set tcp_syncookies = sysctl_cfg.get('tcp_syncookies', 0) -%} -{% set tcp_sack = sysctl_cfg.get('tcp_sack', 1) -%} -{% set ipv6_autoconf = sysctl_cfg.get('ipv6_autoconf', 1) -%} -{% set use_tempaddr = sysctl_cfg.get('use_tempaddr', 1) -%} -# File managed by Salt. Do not edit manually. -# +######################################################################## +# File managed by Salt at <{{ source }}>. +# Your changes will be overwritten. +######################################################################## +{%- set forwarding = ufw_sysctl.get('forwarding', 0) %} +{%- set rp_filter = ufw_sysctl.get('rp_filter', 1) %} +{%- set accept_source_route = ufw_sysctl.get('accept_source_route', 0) %} +{%- set accept_redirects = ufw_sysctl.get('accept_redirects', 0) %} +{%- set icmp_echo_ignore_broadcasts = ufw_sysctl.get('icmp_echo_ignore_broadcasts', 1) %} +{%- set icmp_ignore_bogus_error_responses = ufw_sysctl.get('icmp_ignore_bogus_error_responses', 1) %} +{%- set icmp_echo_ignore_all = ufw_sysctl.get('icmp_echo_ignore_all', 0) %} +{%- set log_martians = ufw_sysctl.get('log_martians', 0) %} +{%- set tcp_syncookies = ufw_sysctl.get('tcp_syncookies', 0) %} +{%- set tcp_sack = ufw_sysctl.get('tcp_sack', 1) %} +{%- set ipv6_autoconf = ufw_sysctl.get('ipv6_autoconf', 1) %} +{%- set use_tempaddr = ufw_sysctl.get('use_tempaddr', 1) %} + # Configuration file for setting network variables. Please note these settings # override /etc/sysctl.conf. If you prefer to use /etc/sysctl.conf, please # adjust IPT_SYSCTL in /etc/default/ufw. -# # Uncomment this to allow this host to route packets between interfaces net/ipv4/ip_forward={{ forwarding }} @@ -69,4 +69,4 @@ net/ipv6/conf/all/autoconf={{ ipv6_autoconf }} # Uncomment this to enable ipv6 privacy addressing net/ipv6/conf/default/use_tempaddr={{ use_tempaddr }} -net/ipv6/conf/all/use_tempaddr={{ use_tempaddr }} \ No newline at end of file +net/ipv6/conf/all/use_tempaddr={{ use_tempaddr }} diff --git a/ufw/init.sls b/ufw/init.sls index 3a58a02..858a8e6 100644 --- a/ufw/init.sls +++ b/ufw/init.sls @@ -1,175 +1,7 @@ -# UFW management module -{%- set ufw = pillar.get('ufw', {}) %} -{%- if ufw.get('enabled', False) %} -{% from "ufw/map.jinja" import ufwmap with context %} -{% set default_template = ufw.get('default_template', 'salt://ufw/templates/default.jinja') -%} -{% set sysctl_template = ufw.get('sysctl_template', 'salt://ufw/templates/sysctl.jinja') -%} -{% set settings_cfg = ufw.get('settings', {}) -%} -{% set loglevel = settings_cfg.get('loglevel', 'low') -%} +# -*- coding: utf-8 -*- +# vim: ft=sls -ufw: - pkg.installed: - - name: {{ ufwmap.pkg }} - service.running: - - enable: True - - watch: - - file: /etc/default/ufw - - file: /etc/ufw/sysctl.conf - -/etc/default/ufw: - file.managed: - - template: jinja - - user: root - - group: root - - mode: 644 - - source: {{ default_template }} - -/etc/ufw/sysctl.conf: - file.managed: - - template: jinja - - user: root - - group: root - - mode: 644 - - source: {{ sysctl_template }} - -/etc/ufw/applications.d: - file.recurse: - - user: root - - group: root - - file_mode: 644 - - clean: False - - source: salt://ufw/files/applications.d - - # services - {%- for service_name, service_details in ufw.get('services', {}).items() %} - - {%- set from_addr_raw = service_details.get('from_addr', [None]) -%} - {%- set from_addrs = [from_addr_raw] if from_addr_raw is string else from_addr_raw -%} - - {%- for from_addr in from_addrs %} - {%- set protocol = service_details.get('protocol', None) %} - {%- set deny = service_details.get('deny', None) %} - {%- set limit = service_details.get('limit', None) %} - {%- set method = 'deny' if deny else ('limit' if limit else 'allow') -%} - {%- set from_port = service_details.get('from_port', None) %} - {%- set to_addr = service_details.get('to_addr', None) %} - {%- set to_port = service_details.get('to_port', service_name) %} - {%- set comment = service_details.get('comment', None) %} - -ufw-svc-{{method}}-{{service_name}}-{{from_addr}}: - ufw.{{method}}: - {%- if protocol != None %} - - protocol: {{protocol}} - {%- endif %} - {%- if from_addr != None %} - - from_addr: {{from_addr}} - {%- endif %} - {%- if from_port != None %} - - from_port: "{{from_port}}" - {%- endif %} - {%- if to_addr != None %} - - to_addr: {{to_addr}} - {%- endif %} - {%- if comment != None %} - - comment: '"{{comment}}"' - {%- endif %} - - to_port: "{{to_port}}" - - require: - - pkg: ufw - - listen_in: - - cmd: reload-ufw - - {%- endfor %} - - {%- endfor %} - - # Applications - {%- for app_name, app_details in ufw.get('applications', {}).items() %} - - {%- set from_addr_raw = app_details.get('from_addr', [None]) -%} - {%- set from_addrs = [from_addr_raw] if from_addr_raw is string else from_addr_raw -%} - - {%- for from_addr in from_addrs %} - {%- set deny = app_details.get('deny', None) %} - {%- set limit = app_details.get('limit', None) %} - {%- set method = 'deny' if deny else ('limit' if limit else 'allow') -%} - {%- set to_addr = app_details.get('to_addr', None) %} - {%- set comment = app_details.get('comment', None) %} - -{%- if from_addr != None%} -ufw-app-{{method}}-{{app_name}}-{{from_addr}}: -{%- else %} -ufw-app-{{method}}-{{app_name}}: -{%- endif %} - ufw.{{method}}: - - app: '"{{app_name}}"' - {%- if from_addr != None %} - - from_addr: {{from_addr}} - {%- endif %} - {%- if to_addr != None %} - - to_addr: {{to_addr}} - {%- endif %} - {%- if comment != None %} - - comment: '"{{comment}}"' - {%- endif %} - - require: - - pkg: ufw - - listen_in: - - cmd: reload-ufw - - {%- endfor %} - {%- endfor %} - - # Interfaces - {%- for interface_name, interface_details in ufw.get('interfaces', {}).items() %} - {%- set comment = interface_details.get('comment', None) %} - -ufw-interface-{{interface_name}}: - ufw.allowed: - - interface: {{interface_name}} - {%- if comment != None %} - - comment: '"{{comment}}"' - {%- endif %} - - require: - - pkg: ufw - - listen_in: - - cmd: reload-ufw - - {%- endfor %} - - # Open - {%- for open_addr, open_details in ufw.get('open', {}).items() %} - {%- set comment = open_details.get('comment', None) %} - -ufw-open-{{open_addr}}: - ufw.allowed: - - from_addr: {{open_addr}} - {%- if comment != None %} - - comment: '"{{comment}}"' - {%- endif %} - - require: - - pkg: ufw - - listen_in: - - cmd: reload-ufw - - {%- endfor %} - -enable-ufw: - ufw.enabled: - - require: - - pkg: ufw - -reload-ufw: - cmd.wait: - - name: ufw reload - -set-logging: - cmd.run: - - name: ufw logging {{ loglevel }} - - unless: "grep 'LOGLEVEL={{ loglevel }}' /etc/ufw/ufw.conf" - -{% else %} - #ufw: - #ufw: - #- disabled -{% endif %} +include: + - .package + - .config + - .service diff --git a/ufw/libtofs.jinja b/ufw/libtofs.jinja new file mode 100644 index 0000000..ab0d0f6 --- /dev/null +++ b/ufw/libtofs.jinja @@ -0,0 +1,100 @@ +{%- macro files_switch(source_files, + lookup=None, + default_files_switch=['id', 'os_family'], + indent_width=6, + v1_path_prefix='') %} + {#- + Returns a valid value for the "source" parameter of a "file.managed" + state function. This makes easier the usage of the Template Override and + Files Switch (TOFS) pattern. + + Params: + * source_files: ordered list of files to look for + * lookup: key under ':tofs:source_files' to override + list of source files + * default_files_switch: if there's no config (e.g. pillar) + ':tofs:files_switch' this is the ordered list of grains to + use as selector switch of the directories under + "/files" + * indent_witdh: indentation of the result value to conform to YAML + * v1_path_prefix: (deprecated) only used for injecting a path prefix into + the source, to support older TOFS configs + + Example (based on a `tplroot` of `xxx`): + + If we have a state: + + Deploy configuration: + file.managed: + - name: /etc/yyy/zzz.conf + - source: {{ files_switch(['/etc/yyy/zzz.conf', '/etc/yyy/zzz.conf.jinja'], + lookup='Deploy configuration' + ) }} + - template: jinja + + In a minion with id=theminion and os_family=RedHat, it's going to be + rendered as: + + Deploy configuration: + file.managed: + - name: /etc/yyy/zzz.conf + - source: + - salt://xxx/files/theminion/etc/yyy/zzz.conf + - salt://xxx/files/theminion/etc/yyy/zzz.conf.jinja + - salt://xxx/files/RedHat/etc/yyy/zzz.conf + - salt://xxx/files/RedHat/etc/yyy/zzz.conf.jinja + - salt://xxx/files/default/etc/yyy/zzz.conf + - salt://xxx/files/default/etc/yyy/zzz.conf.jinja + - template: jinja + #} + {#- Get the `tplroot` from `tpldir` #} + {%- set tplroot = tpldir.split('/')[0] %} + {%- set path_prefix = salt['config.get'](tplroot ~ ':tofs:path_prefix', tplroot) %} + {%- set files_dir = salt['config.get'](tplroot ~ ':tofs:dirs:files', 'files') %} + {%- set files_switch_list = salt['config.get']( + tplroot ~ ':tofs:files_switch', + default_files_switch + ) %} + {#- Lookup source_files (v2), files (v1), or fallback to source_files parameter #} + {%- set src_files = salt['config.get']( + tplroot ~ ':tofs:source_files:' ~ lookup, + salt['config.get']( + tplroot ~ ':tofs:files:' ~ lookup, + source_files + ) + ) %} + {#- Only add to [''] when supporting older TOFS implementations #} + {%- set path_prefix_exts = [''] %} + {%- if v1_path_prefix != '' %} + {%- do path_prefix_exts.append(v1_path_prefix) %} + {%- endif %} + {%- for path_prefix_ext in path_prefix_exts %} + {%- set path_prefix_inc_ext = path_prefix ~ path_prefix_ext %} + {#- For older TOFS implementation, use `files_switch` from the config #} + {#- Use the default, new method otherwise #} + {%- set fsl = salt['config.get']( + tplroot ~ path_prefix_ext|replace('/', ':') ~ ':files_switch', + files_switch_list + ) %} + {#- Append an empty value to evaluate as `default` in the loop below #} + {%- if '' not in fsl %} + {%- do fsl.append('') %} + {%- endif %} + {%- for fs in fsl %} + {%- for src_file in src_files %} + {%- if fs %} + {%- set fs_dir = salt['config.get'](fs, fs) %} + {%- else %} + {%- set fs_dir = salt['config.get'](tplroot ~ ':tofs:dirs:default', 'default') %} + {%- endif %} + {%- set url = '- salt://' ~ '/'.join([ + path_prefix_inc_ext, + files_dir, + fs_dir, + src_file.lstrip('/') + ]) %} +{{ url | indent(indent_width, true) }} + {%- endfor %} + {%- endfor %} + {%- endfor %} +{%- endmacro %} diff --git a/ufw/map.jinja b/ufw/map.jinja index 0e47d32..3042fa5 100644 --- a/ufw/map.jinja +++ b/ufw/map.jinja @@ -1,17 +1,24 @@ -{% import_yaml 'ufw/defaults.yaml' as default_settings %} +# -*- coding: utf-8 -*- +# vim: ft=jinja -{% set os_family_map = salt['grains.filter_by']({ - 'Gentoo': { - 'pkg': 'net-firewall/ufw', - }, - }, - grain="os_family", - merge=salt['pillar.get']('ufw:lookup')) or {} -%} +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{#- Start imports as #} +{%- import_yaml tplroot ~ "/defaults.yaml" or {} as default_settings %} +{%- import_yaml tplroot ~ "/osfamilymap.yaml" or {} as osfamilymap %} +{%- import_yaml tplroot ~ "/osmap.yaml" or {} as osmap %} +{%- import_yaml tplroot ~ "/osfingermap.yaml" or {} as osfingermap %} -{% set ufwmap = salt['grains.filter_by']( - default_settings, - merge=os_family_map, - base='ufwmap', +{%- set defaults = salt['grains.filter_by'](default_settings, + default='ufw', + merge=salt['grains.filter_by'](osfamilymap, grain='os_family', + merge=salt['grains.filter_by'](osmap, grain='os', + merge=salt['grains.filter_by'](osfingermap, grain='osfinger', + merge=salt['pillar.get']('ufw:lookup', default={}) + ) ) -%} + ) +) %} + +{#- Merge the ufw pillar #} +{%- set ufw = salt['pillar.get']('ufw', default=defaults, merge=True) %} diff --git a/ufw/osfamilymap.yaml b/ufw/osfamilymap.yaml new file mode 100644 index 0000000..f6f580d --- /dev/null +++ b/ufw/osfamilymap.yaml @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +Debian: + packages: + - python-ufw +RedHat: {} +Suse: + packages: + - iptables +Gentoo: + package: net-firewall/ufw diff --git a/ufw/osfingermap.yaml b/ufw/osfingermap.yaml new file mode 100644 index 0000000..909ab91 --- /dev/null +++ b/ufw/osfingermap.yaml @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +Debian-8: {} +Debian-9: {} +Ubuntu-16.04: {} +Ubuntu-18.04: {} +Fedora-28: {} +Fedora-29: {} +CentOS-7: {} +CentOS-6: {} +openSUSE-4.23: {} diff --git a/ufw/osmap.yaml b/ufw/osmap.yaml new file mode 100644 index 0000000..c1cad1a --- /dev/null +++ b/ufw/osmap.yaml @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +Debian: {} +Ubuntu: {} +Fedora: {} +CentOS: {} +openSUSE: {} diff --git a/ufw/package/init.sls b/ufw/package/init.sls new file mode 100644 index 0000000..d3e5518 --- /dev/null +++ b/ufw/package/init.sls @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .install diff --git a/ufw/package/install.sls b/ufw/package/install.sls new file mode 100644 index 0000000..0e46963 --- /dev/null +++ b/ufw/package/install.sls @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import ufw with context %} + +ufw-package-install-pkg-installed: + pkg.installed: + - name: {{ ufw.package }} + +{%- for pkg in ufw.packages %} +ufw-package-{{ pkg }}-install-pkg-installed: + pkg.installed: + - name: {{ pkg }} +{%- endfor %} diff --git a/ufw/python.sls b/ufw/python.sls deleted file mode 100644 index 65aa7ea..0000000 --- a/ufw/python.sls +++ /dev/null @@ -1,3 +0,0 @@ -python-ufw: - pkg.installed: - - name: python-ufw diff --git a/ufw/service/enable.sls b/ufw/service/enable.sls new file mode 100644 index 0000000..8eebe18 --- /dev/null +++ b/ufw/service/enable.sls @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import ufw with context %} + +{%- if ufw.get('enabled', False) %} +{%- set loglevel = ufw.get('settings:loglevel', 'low') %} + +enable-ufw: + ufw.enabled + +set-logging: + cmd.run: + - name: ufw logging {{ loglevel }} + - unless: "grep 'LOGLEVEL={{ loglevel }}' /etc/ufw/ufw.conf" +{%- endif %} diff --git a/ufw/service/init.sls b/ufw/service/init.sls new file mode 100644 index 0000000..44aba38 --- /dev/null +++ b/ufw/service/init.sls @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +include: + - .enable + - .running diff --git a/ufw/service/reload.sls b/ufw/service/reload.sls new file mode 100644 index 0000000..402b9f9 --- /dev/null +++ b/ufw/service/reload.sls @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import ufw with context %} + +{%- if ufw.get('enabled', False) %} + +reload-ufw: + cmd.wait: + - name: ufw reload + +{%- endif %} diff --git a/ufw/service/running.sls b/ufw/service/running.sls new file mode 100644 index 0000000..4cb172f --- /dev/null +++ b/ufw/service/running.sls @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- set sls_config_file = tplroot ~ '.config.file' %} +{%- from tplroot ~ "/map.jinja" import ufw with context %} + +include: + - {{ sls_config_file }} + +{%- if ufw.get('enabled', False) %} + +ufw-service-running-service-running: + service.running: + - name: {{ ufw.service.name }} + - enable: true + - require: + - sls: {{ sls_config_file }} + +{%- else %} + +ufw-service-dead-service-dead: + service.dead: + - name: {{ ufw.service.name }} + - enable: false + - require: + - sls: {{ sls_config_file }} + +{%- endif %}