- Python 70.3%
- Shell 23.9%
- Dockerfile 5.8%
| .vscode | add Redis support for session management | |
| files | refactor: update configuration and environment variable references | |
| .gitignore | refactor: update configuration and environment variable references | |
| .gitlab-ci.yml | feat: refactor CI/CD configuration and update Docker setup | |
| CHANGELOG.md | refactor: update configuration and environment variable references | |
| cliff.toml | feat: refactor CI/CD configuration and update Docker setup | |
| docker-compose.yml | refactor: update configuration and environment variable references | |
| Dockerfile | feat: update Dockerfiles | |
| Dockerfile-local | feat: update Dockerfiles | |
| README.md | docs: add Fail2ban configuration instructions for HAProxy | |
GEANT Captcha - Flask
Flask CAPTCHA for HAProxy
Preamble
This container runs a Flask application to verify a captcha against a supported provider.
Two providers are currently supported: hCaptcha and Google reCaptcha.
Switching from reCAPTCHA to hCaptcha is explained in this page
The parameters are stored here as Consul keys: https://consul.service.ha.geant.net/ui/geant/kv/nomad/test/captcha
Google reCaptcha parameters
- api_url:
https://www.google.com/recaptcha/api.js - provider_name:
g-recaptcha
---config:verify_url:"https://www.google.com/recaptcha/api/siteverify"provider_name:"g-recaptcha-response"max_age:3600# cookie lifetime in secondsvalkey:host:"redis.service.consul"record_type:"SRV"ssl:falsesites:www.mysite.org:wordpresswiki.geant.org:wikihCaptcha parameters
- api_url:
https://js.hcaptcha.com/1/api.js - provider_name:
h-captcha
---config:verify_url:"https://api.hcaptcha.com/siteverify"provider_name:"h-captcha-response"max_age:3600# cookie lifetime in secondsvalkey:host:"redis.example.org"record_type:"A"ssl:falsesites:www.mysite.org:wordpresswiki.geant.org:wikiHAProxy configuration
Frontend configuration
frontend http-in
# Track source IP in the backend's stick-table (per-IP rate limiting)
http-request track-sc0 src table wiki_backend
# ACL for rate limiting: more than 10 connections in 10 seconds from the same IP
acl captcha_rate_limited sc0_conn_rate(wiki_backend) gt 10
# ACLs for cookie and path checks
acl is_valid_cookie hdr_sub(cookie) captcha_pass=wordpress # Adjust value as needed
acl is_captcha_verify path_beg /verify.html
acl is_captcha_flask path -i /validate
# Redirect to CAPTCHA if not validated and rate limit exceeded
http-request redirect location https://%[req.hdr(Host)]/verify.html \
if !is_valid_cookie !is_captcha_verify !is_captcha_flask captcha_rate_limited
# Route to Flask CAPTCHA backend for validation requests
use_backend captcha_verify if { path -i /verify.html }
Backend configuration
backend captcha_flask
mode http
option httpchk GET /_healthz
timeout connect 20s
timeout server 20s
http-request set-header Host %[req.hdr(Host)]
server-template captcha 1-10 _test-captcha._tcp.service.ha.geant.net check inter 30s ssl verify none resolvers consul init-addr none resolve-opts allow-dup-ip resolve-prefer ipv4
backend captcha_verify
mode http
http-request cache-use verify_cache
http-response cache-store verify_cache
http-request return status 200 content-type "text/html" file "/etc/haproxy/captcha/verify.html" hdr "cache-control" "no-cache"
backend wiki_backend
stick-table type ip size 100k expire 10m store conn_rate(10s)
server wiki wiki-backend.example.org:443 maxconn 10 check inter 10s ssl verify none
HAProxy and Fail2ban
💥 This solution has drawbacks 💥 Against distributed attacks the service will be reloaded continuously.
To protect your backend from brute-force login attacks, you can use Fail2ban to monitor HAProxy logs, check for 401 error codes, and store IP addresses that exceed a certain number of failed attempts.
The addresses will be stored in a HAProxy map file /etc/haproxy/banned.lst and HAProxy will be reload systemctl reload haproxy.
The file should contain one IP address per line, for example:
# /etc/haproxy/banned.lst
192.0.2.1
203.0.113.5
198.51.100.7
And haproxy configuration should include the following ACL to block requests from these IPs:
# ACL to block banned IPs
acl banned_ip src -f /etc/haproxy/banned.lst
# Redirect to CAPTCHA if not validated and rate limit exceeded
http-request redirect location https://%[req.hdr(Host)]/verify.html \
if !is_valid_cookie !is_captcha_verify !is_captcha_flask banned_ip
# Route to Flask CAPTCHA backend for validation requests
use_backend captcha_verify if { path -i /verify.html }
Docker instructions
First you need a secret key for your provider (see Google reCaptcha parameters and hCaptcha documentation).
You can store your secret key in a file called recaptcha_secret.env (the file is declared in .gitignore) with the following content:
secret_key='your_secret_key_here'
Finally can build and run a local image using Docker Compose as follows:
docker compose --profile all up --build
Create a new release
Add this lines to ~/.gitconfig:
[alias]
pp = !git pull && git push
pushall = !git remote | xargs -L1 git push --all
pushall-tags = !git remote | xargs -L1 git push --tags
We assume that we are applying our change to main branch and create a tag starting from main.
If we want to create version 1.2.3, the commands below triggers the CI and and creates version 1.2.3 of the container:
git checkout main # make your changes ...
git commit "my new change"
git push
git tag 1.2.3
git pushall-tags