The "limit" and "deny" parameters have been added to both the services and applications sections. Setting "limit: True" will use the "ufw limit" command instead of "ufw allow". Likewise, setting "deny: True" will use the "ufw deny" command.tags/v0.2.0
@@ -37,10 +37,35 @@ provisioner: | |||
enabled: True | |||
settings: | |||
loglevel: 'low' | |||
applications: | |||
MySQL: | |||
comment: Allow MySQL | |||
Postgresql: | |||
limit: True | |||
comment: Limit Postgresql | |||
SSH223: | |||
deny: True | |||
comment: Deny Webscale SSH | |||
'*': | |||
deny: True | |||
from_addr: 10.0.0.0/8 | |||
services: | |||
'*': | |||
deny: True | |||
from_addr: | |||
- 10.0.0.1 | |||
- 10.0.0.2 | |||
'22': | |||
protocol: tcp | |||
comment: Allow SSH | |||
limit: True | |||
comment: Limit SSH | |||
'80': | |||
protocol: tcp | |||
deny: True | |||
comment: Deny HTTP | |||
'443': | |||
protocol: tcp | |||
comment: Allow HTTPS | |||
platforms: | |||
- name: <%= distrib %>-<%= codename %> |
@@ -80,6 +80,47 @@ def _as_rule(method, app, interface, protocol, from_addr, from_port, to_addr, to | |||
return real_cmd | |||
def _add_rule(method, name, app=None, interface=None, protocol=None, | |||
from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None): | |||
if app and app.strip('"\' ') == '*': | |||
app = None | |||
if to_port and to_port.strip('"\' ') == '*': | |||
to_port = None | |||
rule = _as_rule(method, app=app, interface=interface, protocol=protocol, | |||
from_addr=from_addr, from_port=from_port, to_addr=to_addr, to_port=to_port, comment=comment) | |||
try: | |||
out = __salt__['ufw.add_rule'](rule) | |||
except (CommandExecutionError, CommandNotFoundError) as e: | |||
return _error(name, e.message) | |||
adds = False | |||
updates = False | |||
for line in out.split('\n'): | |||
if re.match('^Skipping', line): | |||
return _unchanged(name, "{0} is already configured".format(name)) | |||
break | |||
if re.match('^Rule(s)? added', line): | |||
adds = True | |||
break | |||
if re.match('^Rule(s)? updated', line): | |||
updates = True | |||
break | |||
if __opts__['test']: | |||
return _test(name, "{0} would have been configured".format(name)) | |||
break | |||
return _error(name, line) | |||
if adds: | |||
return _changed(name, "{0} added".format(name), rule=rule) | |||
elif updates: | |||
return _changed(name, "{0} updated".format(name), rule=rule) | |||
else: | |||
return _unchanged(name, "{0} was already configured".format(name)) | |||
def enabled(name, **kwargs): | |||
if __salt__['ufw.is_enabled'](): | |||
return _unchanged(name, "UFW is already enabled") | |||
@@ -137,38 +178,28 @@ def default_outgoing(name, default): | |||
return _unchanged(name, "{0} was already set to {1}".format(name, default)) | |||
def allowed(name, app=None, interface=None, protocol=None, | |||
from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None): | |||
def deny(name, app=None, interface=None, protocol=None, | |||
from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None): | |||
rule = _as_rule("allow", app=app, interface=interface, protocol=protocol, | |||
from_addr=from_addr, from_port=from_port, to_addr=to_addr, to_port=to_port, comment=comment) | |||
return _add_rule('deny', name, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment) | |||
try: | |||
out = __salt__['ufw.add_rule'](rule) | |||
except (CommandExecutionError, CommandNotFoundError) as e: | |||
return _error(name, e.message) | |||
adds = False | |||
updates = False | |||
for line in out.split('\n'): | |||
if re.match('^Skipping', line): | |||
return _unchanged(name, "{0} is already configured".format(name)) | |||
break | |||
if re.match('^Rule(s)? added', line): | |||
adds = True | |||
break | |||
if re.match('^Rule(s)? updated', line): | |||
updates = True | |||
break | |||
if __opts__['test']: | |||
return _test(name, "{0} would have been configured".format(name)) | |||
break | |||
return _error(name, line) | |||
def limit(name, app=None, interface=None, protocol=None, | |||
from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None): | |||
if adds: | |||
return _changed(name, "{0} added".format(name), rule=rule) | |||
elif updates: | |||
return _changed(name, "{0} updated".format(name), rule=rule) | |||
else: | |||
return _unchanged(name, "{0} was already configured".format(name)) | |||
return _add_rule('limit', name, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment) | |||
def allow(name, app=None, interface=None, protocol=None, | |||
from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None): | |||
return _add_rule('allow', name, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment) | |||
def allowed(name, app=None, interface=None, protocol=None, | |||
from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None): | |||
""" | |||
allow() is aliased to allowed() to maintain backwards compatibility. | |||
""" | |||
return allow(name, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment) |
@@ -53,11 +53,36 @@ ufw: | |||
protocol: tcp | |||
comment: Mail relay | |||
# Allow from an specific port, by number. | |||
# Allow from a specific port, by number. | |||
139: | |||
protocol: tcp | |||
comment: Netbios | |||
# Deny from a specific port, by number. | |||
140: | |||
protocol: tcp | |||
deny: True | |||
# Deny everything from a specific ip address | |||
'*': | |||
protocol: tcp | |||
deny: True | |||
from_addr: 10.0.0.1 | |||
# Deny everything from a multiple ip addresses | |||
'*': | |||
protocol: tcp | |||
deny: True | |||
from_addr: | |||
- 10.0.0.2 | |||
- 10.0.0.3 | |||
# Limit a specific port, by number. | |||
170: | |||
limit: True | |||
protocol: tcp | |||
comment: Print service | |||
# Allow from a range of ports, udp. | |||
"10000:20000": | |||
protocol: udp | |||
@@ -68,12 +93,20 @@ ufw: | |||
protocol: udp | |||
comment: Game server and admin | |||
# Allow an application defined at /etc/ufw/applications.d/ | |||
# Allow applications defined at /etc/ufw/applications.d/ | |||
applications: | |||
OpenSSH: | |||
enabled: True | |||
comment: We are using fail2ban anyway | |||
# Limit access to salt master | |||
Saltmaster: | |||
limit: True | |||
# Deny access to Postgresql | |||
Postgresql: | |||
deny: True | |||
# Allow all traffic in on the specified interface | |||
interfaces: | |||
eth1: |
@@ -25,7 +25,47 @@ describe command('ufw status verbose | grep Logging') do | |||
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 |
@@ -43,15 +43,20 @@ ufw: | |||
# services | |||
{%- for service_name, service_details in ufw.get('services', {}).items() %} | |||
{%- for from_addr in service_details.get('from_addr', [None]) %} | |||
{%- 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 comment = service_details.get('comment', None) %} | |||
ufw-svc-{{service_name}}-{{from_addr}}: | |||
ufw.allowed: | |||
ufw-svc-{{method}}-{{service_name}}-{{from_addr}}: | |||
ufw.{{method}}: | |||
{%- if protocol != None %} | |||
- protocol: {{protocol}} | |||
{%- endif %} | |||
@@ -79,17 +84,23 @@ ufw-svc-{{service_name}}-{{from_addr}}: | |||
# Applications | |||
{%- for app_name, app_details in ufw.get('applications', {}).items() %} | |||
{%- for from_addr in app_details.get('from_addr', [None]) %} | |||
{%- 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-{{app_name}}-{{from_addr}}: | |||
ufw-app-{{method}}-{{app_name}}-{{from_addr}}: | |||
{%- else %} | |||
ufw-app-{{app_name}}: | |||
ufw-app-{{method}}-{{app_name}}: | |||
{%- endif %} | |||
ufw.allowed: | |||
ufw.{{method}}: | |||
- app: '"{{app_name}}"' | |||
{%- if from_addr != None %} | |||
- from_addr: {{from_addr}} | |||
@@ -107,7 +118,7 @@ ufw-app-{{app_name}}: | |||
{%- endfor %} | |||
{%- endfor %} | |||
# Interfaces | |||
{%- for interface_name, interface_details in ufw.get('interfaces', {}).items() %} | |||
{%- set comment = interface_details.get('comment', None) %} |