def initialize_ufw(): """Initialize the UFW firewall Ensure critical ports have explicit allows :return: None """ if not config('enable-firewall'): log("Firewall has been administratively disabled", "DEBUG") return # this charm will monitor exclusively the ports used, using 'allow' as # default policy enables sharing the machine with other services ufw.default_policy('allow', 'incoming') ufw.default_policy('allow', 'outgoing') ufw.default_policy('allow', 'routed') # Rsync manages its own ACLs ufw.service('rsync', 'open') # Guarantee SSH access ufw.service('ssh', 'open') # Enable ufw.enable(soft_fail=config('allow-ufw-ip6-softfail')) # Allow GRE traffic add_ufw_gre_rule(os.path.join(UFW_DIR, 'before.rules')) ufw.reload()
def test_with_ipv6(self, modprobe, check_output, isdir, is_enabled, log): def c(*args, **kwargs): if args[0] == ['lsmod']: return LSMOD_IP6 else: return 'Firewall is active and enabled on system startup\n' check_output.side_effect = c is_enabled.return_value = False isdir.return_value = True ufw.enable()
def test_no_ipv6(self, check_output, call, isdir, log, is_enabled): check_output.return_value = ('Firewall is active and enabled ' 'on system startup\n') isdir.return_value = False call.return_value = 0 is_enabled.return_value = False ufw.enable() call.assert_called_with(['sed', '-i', 's/IPV6=.*/IPV6=no/g', '/etc/default/ufw']) log.assert_any_call('IPv6 support in ufw disabled', level='INFO')
def initialize_ufw(): """Initialize the UFW firewall Ensure critical ports have explicit allows :return: None """ # this charm will monitor exclusively the ports used, using 'allow' as # default policy enables sharing the machine with other services ufw.default_policy('allow', 'incoming') # Rsync manages its own ACLs ufw.service('rsync', 'open') # Guarantee SSH access ufw.service('ssh', 'open') # Enable ufw.enable(soft_fail=config('allow-ufw-ip6-softfail'))
def test_enable_fail(self, modprobe, check_output, log): msg = 'neneene\n' check_output.return_value = msg self.assertFalse(ufw.enable()) check_output.assert_any_call(['ufw', 'enable'], universal_newlines=True, env={'LANG': 'en_US', 'PATH': os.environ['PATH']}) log.assert_any_call(msg, level='DEBUG') log.assert_any_call("ufw couldn't be enabled", level='WARN')
def test_enable_ok(self, modprobe, check_output, log): msg = 'Firewall is active and enabled on system startup\n' check_output.return_value = msg self.assertTrue(ufw.enable()) check_output.assert_any_call(['ufw', 'enable'], universal_newlines=True, env={'LANG': 'en_US', 'PATH': os.environ['PATH']}) log.assert_any_call(msg, level='DEBUG') log.assert_any_call('ufw enabled', level='INFO')
def test_no_ip6_tables(self, modprobe, check_output, call, isdir, log, is_enabled): def c(*args, **kwargs): if args[0] == ['lsmod']: return LSMOD_NO_IP6 elif args[0] == ['modprobe', 'ip6_tables']: return "" else: return 'Firewall is active and enabled on system startup\n' check_output.side_effect = c isdir.return_value = True call.return_value = 0 is_enabled.return_value = False self.assertTrue(ufw.enable())
def test_no_ip6_tables_fail_to_load_soft_fail(self, check_output, call, is_module_loaded, modprobe, isdir, log, is_enabled): is_module_loaded.return_value = False def c(m): raise subprocess.CalledProcessError(1, ['modprobe', 'ip6_tables'], "fail to load ip6_tables") modprobe.side_effect = c isdir.return_value = True call.return_value = 0 check_output.return_value = ("Firewall is active and enabled on " "system startup\n") is_enabled.return_value = False self.assertTrue(ufw.enable(soft_fail=True)) call.assert_called_with( ['sed', '-i', 's/IPV6=.*/IPV6=no/g', '/etc/default/ufw']) log.assert_any_call('IPv6 support in ufw disabled', level='INFO')
def configure_firewall(): '''Configure firewall rules using ufw. This is primarily to block access to the replication and JMX ports, as juju's default port access controls are not strict enough and allow access to the entire environment. ''' config = hookenv.config() ufw.enable(soft_fail=True) # Enable SSH from anywhere, relying on Juju and external firewalls # to control access. ufw.service('ssh', 'open') ufw.service('nrpe', 'open') # Also NRPE for nagios checks. # Clients need client access. These protocols are configured to # require authentication. client_keys = ['native_transport_port', 'rpc_port'] client_ports = [config[key] for key in client_keys] # Peers need replication access. This protocols does not # require authentication, so firewall it from other nodes. peer_ports = [config['storage_port'], config['ssl_storage_port']] # Enable client access from anywhere. Juju and external firewalls # can still restrict this further of course (ie. 'juju expose'). for key in client_keys: if config.changed(key) and config.previous(key) is not None: # First close old ports. We use this order in the unlikely case # someone is trying to swap the native and Thrift ports. ufw.service(config.previous(key), 'close') for port in client_ports: # Then open or close the configured ports. ufw.service(port, 'open') desired_rules = set() # ufw.grant_access/remove_access commands. # Rules for peers for relinfo in hookenv.relations_of_type('cluster'): if relinfo['private-address']: for port in peer_ports: desired_rules.add((relinfo['private-address'], 'any', port)) # Rules for admin connections. We allow database-admin relations access # to the cluster communication ports so that tools like sstableloader # can run. for relinfo in hookenv.relations_of_type('database-admin'): if relinfo['private-address']: for port in peer_ports: desired_rules.add((relinfo['private-address'], 'any', port)) previous_rules = set(tuple(rule) for rule in config.get('ufw_rules', [])) # Close any rules previously opened that are no longer desired. for rule in sorted(list(previous_rules - desired_rules)): ufw.revoke_access(*rule) # Open all the desired rules. for rule in sorted(list(desired_rules)): ufw.grant_access(*rule) # Store our rules for next time. Note that this is inherantly racy - # this value is only persisted if the hook exits cleanly. If the # hook fails, then someone changes port configuration or IP # addresses change, then the failed hook retried, we can lose track # of previously granted rules and they will never be revoked. It is # impossible to remove this race entirely, so we stick with this # simple approach. config['ufw_rules'] = list(desired_rules) # A list because JSON.
def configure_firewall(): '''Configure firewall rules using ufw. This is primarily to block access to the replication and JMX ports, as juju's default port access controls are not strict enough and allow access to the entire environment. ''' config = hookenv.config() ufw.enable(soft_fail=True) # Enable SSH from anywhere, relying on Juju and external firewalls # to control access. ufw.service('ssh', 'open') ufw.service('nrpe', 'open') # Also NRPE for nagios checks. # Clients need client access. These protocols are configured to # require authentication. client_keys = ['native_transport_port', 'rpc_port'] client_ports = [config[key] for key in client_keys] # Peers need replication access. This protocols does not # require authentication, so firewall it from other nodes. peer_ports = [config['storage_port'], config['ssl_storage_port']] # Enable client access from anywhere. Juju and external firewalls # can still restrict this further of course (ie. 'juju expose'). for key in client_keys: if config.changed(key) and config.previous(key) is not None: # First close old ports. We use this order in the unlikely case # someone is trying to swap the native and Thrift ports. ufw.service(config.previous(key), 'close') for port in client_ports: # Then open or close the configured ports. ufw.service(port, 'open') desired_rules = set() # ufw.grant_access/remove_access commands. # Rules for peers for relinfo in hookenv.relations_of_type('cluster'): if relinfo['private-address']: for port in peer_ports: desired_rules.add((relinfo['private-address'], 'any', port)) # Rules for admin connections. We allow database-admin relations access # to the cluster communication ports so that tools like sstableloader # can run. for relinfo in hookenv.relations_of_type('database-admin'): if relinfo['private-address']: for port in peer_ports: desired_rules.add((relinfo['private-address'], 'any', port)) previous_rules = set(tuple(rule) for rule in config.get('ufw_rules', [])) # Close any rules previously opened that are no longer desired. for rule in sorted(list(previous_rules - desired_rules)): ufw.revoke_access(*rule) # Open all the desired rules. for rule in sorted(list(desired_rules)): ufw.grant_access(*rule) # Store our rules for next time. Note that this is inherantly racy - # this value is only persisted if the hook exits cleanly. If the # hook fails, then someone changes port configuration or IP # addresses change, then the failed hook retried, we can lose track # of previously granted rules and they will never be revoked. It is # impossible to remove this race entirely, so we stick with this # simple approach. config['ufw_rules'] = list(desired_rules) # A list because JSON.