Compare commits
	
		
			25 Commits
		
	
	
		
			2023.1
			...
			e0d115790e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e0d115790e | |||
| 58ac46126a | |||
| a7970c4f6b | |||
| 3dacbe7a5d | |||
| 798a72cb73 | |||
| 59cc645b98 | |||
| feb8c93737 | |||
| 27bc683f8f | |||
| 3f94410716 | |||
| e3a71a851d | |||
| 542718b956 | |||
| 34f871ae75 | |||
| f3f8bd5dc6 | |||
| 5971c27a8f | |||
| 47e8208ce2 | |||
| af1fef189c | |||
| c33e63978e | |||
| 963f7e5702 | |||
| 450792b2d2 | |||
| ffe144f6b5 | |||
| a20145b447 | |||
| b5f16f161c | |||
| 7c7734c996 | |||
| bd12b2a18a | |||
| 64523ae8b5 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -12,6 +12,3 @@ htmlcov/ | |||||||
| dist/ | dist/ | ||||||
| build/ | build/ | ||||||
| *.egg-info/ | *.egg-info/ | ||||||
|  |  | ||||||
| coverage.xml |  | ||||||
| report.xml |  | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| run tests: | run tests: | ||||||
|   stage: test |   stage: test | ||||||
|   image: python:3.9 |   image: python:3.8 | ||||||
|   script: |   script: | ||||||
|     - pip install pytest pytest-cov pytest-mock pytest-flask |     - pip install pytest pytest-cov pytest-mock pytest-flask | ||||||
|     - pip install Flask-HTTPAuth |     - pip install Flask-HTTPAuth | ||||||
| @ -11,9 +11,7 @@ run tests: | |||||||
|   artifacts: |   artifacts: | ||||||
|     when: always |     when: always | ||||||
|     reports: |     reports: | ||||||
|       coverage_report: |       cobertura: coverage.xml | ||||||
|         coverage_format: cobertura |  | ||||||
|         path: coverage.xml |  | ||||||
|       junit: report.xml |       junit: report.xml | ||||||
|   tags: |   tags: | ||||||
|     - docker |     - docker | ||||||
|  | |||||||
							
								
								
									
										127
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										127
									
								
								README.md
									
									
									
									
									
								
							| @ -1,130 +1,3 @@ | |||||||
| [](https://gitlab.niet.verweg.com/ruben/jail2ban-pf/-/commits/main) | [](https://gitlab.niet.verweg.com/ruben/jail2ban-pf/-/commits/main) | ||||||
| [](https://gitlab.niet.verweg.com/ruben/jail2ban-pf/-/commits/main) | [](https://gitlab.niet.verweg.com/ruben/jail2ban-pf/-/commits/main) | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Installation |  | ||||||
|  |  | ||||||
|  |  | ||||||
| * Install uwsgi  |  | ||||||
|  |  | ||||||
| ``` |  | ||||||
| sudo pkg install www/uwsgi |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| * Clone this repository |  | ||||||
|  |  | ||||||
| ## Configuration |  | ||||||
|  |  | ||||||
| ### rc.conf |  | ||||||
|  |  | ||||||
| * Use the following for configuring uwsgi in rc.conf |  | ||||||
|  |  | ||||||
| ``` |  | ||||||
| sudo sysrc uwsgi\_enable="YES" |  | ||||||
| sudo sysrc uwsgi\_profiles="jail2ban\_pf" |  | ||||||
| sudo sysrc uwsgi\_jail2ban\_pf\_flags="-L -M --uid \_jail2ban --python-path /opt/jail2ban-pf --wsgi-file /opt/jail2ban-pf/wsgi.py --stats 127.0.0.1:9191 --socket 127.0.0.1:3031 --chdir /var/empty --callable app --manage-script-name" |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### jail2ban |  | ||||||
|  |  | ||||||
| * Configure <installation root>/instance/config.py |  | ||||||
|  |  | ||||||
| ``` |  | ||||||
| SECRET\_KEY = os.urandom(32).hex() |  | ||||||
| AUTHFILE = '/usr/local/etc/jail2ban-pf-users.txt' |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### nginx |  | ||||||
|  |  | ||||||
| * Configure a nginx upstream and vhost |  | ||||||
|  |  | ||||||
| _Of course you can listen on ipv4/ipv6 but you want to protect these addresses from inadvertent or malicious probes_ |  | ||||||
|  |  | ||||||
|     upstream uwsgi_pf_jail2ban { |  | ||||||
|         server 127.0.0.1:3031; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     server { |  | ||||||
|         listen       unix:/path/to/jail_1/var/run/pf2ban/pf_jail2ban.sock; |  | ||||||
|         listen       unix:/path/to/jail_2/var/run/pf2ban/pf_jail2ban.sock; |  | ||||||
|         listen       unix:/path/to/jail_3/var/run/pf2ban/pf_jail2ban.sock; |  | ||||||
|         server_name  _; |  | ||||||
|  |  | ||||||
|         location / { |  | ||||||
|             index     index.html index.htm index.php; |  | ||||||
|             allow all; |  | ||||||
|             include /usr/local/etc/nginx/uwsgi_params-dist; |  | ||||||
|             uwsgi_pass uwsgi_pf_jail2ban; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| ### /etc/pf.conf |  | ||||||
|  |  | ||||||
| * Place anchors in pf for jail2ban to use. You probably want to place the early in your existing pf configuration |  | ||||||
|  |  | ||||||
| ``` |  | ||||||
| anchor "f2b/*" |  | ||||||
| anchor f2b-jail { |  | ||||||
|     anchor "jail1_fqdn" to { <addr_jail1>, <addr_extra_jail1>, <addr_extra6_jail1> } |  | ||||||
|     anchor "jail2_fqdn" to { <addr_jail2>, <addr_extra_jail2>, <addr_extra6_jail2> } |  | ||||||
|     anchor "jail3_fqdn" to { <addr_jail3>, <addr_extra_jail3>, <addr_extra6_jail3> } |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Having seperate anchors per jail makes it possible to have fine grained |  | ||||||
| blocking: Something that is harmful to jail2 might be perfectly legit for jail2. |  | ||||||
|  |  | ||||||
| #### Checking rules/tables made with fail2ban/jail2ban |  | ||||||
| Fail2ban will (re)create the per anchor rules on startup, and populate the designated address tables with offenders, e.g.: |  | ||||||
|  |  | ||||||
|     sudo pfctl -a f2b-jail/jail1\_fqdn -T show -t f2b-recidive |  | ||||||
|     192.0.2.66 |  | ||||||
|     2001:db8:abad:cafe:0bad:f00d |  | ||||||
|  |  | ||||||
| And the rules referencing these tables |  | ||||||
|  |  | ||||||
|     sudo pfctl -a 'f2b-jail/jail1\_fqdn' -s rules |  | ||||||
|     block drop quick proto tcp from <f2b-dovecot> to any port = pop3 |  | ||||||
|     block drop quick proto tcp from <f2b-dovecot> to any port = pop3s |  | ||||||
|     block drop quick proto tcp from <f2b-dovecot> to any port = imap |  | ||||||
|     block drop quick proto tcp from <f2b-dovecot> to any port = imaps |  | ||||||
|     block drop quick proto tcp from <f2b-dovecot> to any port = submission |  | ||||||
|     block drop quick proto tcp from <f2b-dovecot> to any port = smtps |  | ||||||
|     block drop quick proto tcp from <f2b-dovecot> to any port = sieve |  | ||||||
|     block drop quick proto tcp from <f2b-sendmail-auth> to any port = submission |  | ||||||
|     block drop quick proto tcp from <f2b-sendmail-auth> to any port = smtps |  | ||||||
|     block drop quick proto tcp from <f2b-sendmail-auth> to any port = smtp |  | ||||||
|     block drop quick proto tcp from <f2b-sshd> to any port = ssh |  | ||||||
|     block drop quick proto tcp from <f2b-recidive> to any |  | ||||||
|      |  | ||||||
| ### fail2ban |  | ||||||
|  |  | ||||||
| * Create the following action plugin for fail2ban on the jail desiring to use fail2ban/jail2ban |  | ||||||
|  |  | ||||||
| ``` |  | ||||||
| cat <<'EOT' | tee /usr/local/etc/fail2ban/action.d/jail2ban-pf.conf > /dev/null |  | ||||||
| Definition] |  | ||||||
| actionstart = curl --unix-socket <jail2ban_sock> --basic -u '<jail2ban_user>:<jail2ban_pass>' -XPUT -H 'Content-Type: application/json' -d '{"port":"<actiontype>","name":"<name>","protocol":"<protocol>"}' http://localhost/register |  | ||||||
| actionstart_on_demand = false |  | ||||||
| actionstop = curl --unix-socket <jail2ban_sock> --basic -u '<jail2ban_user>:<jail2ban_pass>' -XDELETE -H 'Content-Type: application/json' -d '{"port":"<actiontype>","name":"<name>","protocol":"<protocol>"}' http://localhost/register |  | ||||||
| actionflush = curl --unix-socket <jail2ban_sock> --basic -u '<jail2ban_user>:<jail2ban_pass>' -X GET http://localhost/flush/<name> |  | ||||||
| actioncheck =  |  | ||||||
| actionban = curl --unix-socket <jail2ban_sock> --basic -u '<jail2ban_user>:<jail2ban_pass>' -X PUT -H 'Content-Type: application/json' -d '{"name":"<name>","ip":"<ip>"}' http://localhost/ban |  | ||||||
| actionunban = curl --unix-socket <jail2ban_sock> --basic -u '<jail2ban_user>:<jail2ban_pass>' -X DELETE -H 'Content-Type: application/json' -d '{"name":"<name>","ip":"<ip>"}' http://localhost/ban |  | ||||||
| [Init] |  | ||||||
| protocol = tcp |  | ||||||
| actiontype = <multiport> |  | ||||||
| allports = any |  | ||||||
| multiport = any port {<port>} |  | ||||||
| jail2ban_sock = /var/run/pf2ban/jail2ban.sock |  | ||||||
| jail2ban_user = login as set in password file for jail2ban |  | ||||||
| jail2ban_pass = password as set in password file for jail2ban |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| * Configure jail.local |  | ||||||
|  |  | ||||||
| ``` |  | ||||||
| cat <<'EOT' | tee /usr/local/etc/fail2ban/jail.local > /dev/null |  | ||||||
| [DEFAULT] |  | ||||||
| banaction = jail2ban-pf |  | ||||||
| ``` |  | ||||||
|  | |||||||
| @ -42,15 +42,6 @@ def create_app(): | |||||||
|                 check_password_hash(users.get(username), password): |                 check_password_hash(users.get(username), password): | ||||||
|             return username |             return username | ||||||
|  |  | ||||||
|     @app.route("/ping", methods=['GET']) |  | ||||||
|     @auth.login_required |  | ||||||
|     def ping(): |  | ||||||
|         remote_user = auth.username() |  | ||||||
|         app.logger.info('Received ping for' |  | ||||||
|                         f' anchor f2b-jail/{remote_user}') |  | ||||||
|         return jsonify({'anchor': f'f2b-jail/{remote_user}', |  | ||||||
|                         'operation': 'ping', |  | ||||||
|                         'result': 'pong'}) |  | ||||||
|     @app.route("/flush/<name>", methods=['GET']) |     @app.route("/flush/<name>", methods=['GET']) | ||||||
|     @auth.login_required |     @auth.login_required | ||||||
|     def flush(name): |     def flush(name): | ||||||
|  | |||||||
| @ -1,10 +0,0 @@ | |||||||
| def test_ping(client, mocker, valid_credentials): |  | ||||||
|     ''' |  | ||||||
|     Test application health check |  | ||||||
|     ''' |  | ||||||
|  |  | ||||||
|     response = client.get("/ping", |  | ||||||
|                           headers={"Authorization": |  | ||||||
|                                    "Basic " + valid_credentials}) |  | ||||||
|  |  | ||||||
|     assert response.json['operation'] == 'ping' |  | ||||||
		Reference in New Issue
	
	Block a user