Implement SSH passthrough mode and refactor Gitea domain configuration
Major Changes: - Add dual SSH mode system (passthrough default, dedicated fallback) - Refactor domain configuration to use direct specification pattern - Fix critical fail2ban security gap in dedicated mode - Separate HTTP and SSH domains for cleaner Git URLs
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
---
|
||||
# Gitea fail2ban Configuration - Rick-Infra
|
||||
# Protects Gitea SSH from brute force attacks
|
||||
# Integrates with system fail2ban service
|
||||
# Mode-aware: Only protects dedicated mode (port 2222)
|
||||
# In passthrough mode, system 'sshd' jail protects port 22
|
||||
|
||||
- name: Install fail2ban
|
||||
pacman:
|
||||
@@ -13,6 +13,7 @@
|
||||
content: |
|
||||
# Fail2ban filter for Gitea SSH authentication failures
|
||||
# Rick-Infra: Gitea role
|
||||
# Only used in dedicated mode (port {{ gitea_ssh_port }})
|
||||
|
||||
[Definition]
|
||||
# Match failed authentication attempts in Gitea logs
|
||||
@@ -33,14 +34,17 @@
|
||||
modification_time: preserve
|
||||
access_time: preserve
|
||||
|
||||
- name: Add Gitea SSH jail to fail2ban
|
||||
- name: Add Gitea SSH jail to fail2ban (mode-aware)
|
||||
blockinfile:
|
||||
path: /etc/fail2ban/jail.local
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK - Gitea SSH"
|
||||
block: |
|
||||
# Gitea SSH Protection - Rick-Infra
|
||||
# Mode: {{ gitea_ssh_mode }}
|
||||
# - dedicated: Monitors Gitea logs on port {{ gitea_ssh_port }}
|
||||
# - passthrough: Disabled (system 'sshd' jail protects port 22)
|
||||
[gitea-ssh]
|
||||
enabled = true
|
||||
enabled = {{ 'true' if gitea_ssh_mode == 'dedicated' else 'false' }}
|
||||
port = {{ gitea_ssh_port }}
|
||||
filter = gitea-ssh
|
||||
logpath = {{ gitea_home }}/log/gitea.log
|
||||
@@ -57,19 +61,61 @@
|
||||
enabled: yes
|
||||
state: started
|
||||
|
||||
- name: Add fail2ban restart handler
|
||||
- name: Flush handlers to ensure fail2ban restarts
|
||||
meta: flush_handlers
|
||||
|
||||
- name: Display fail2ban status for Gitea
|
||||
- name: Wait for fail2ban to be ready
|
||||
pause:
|
||||
seconds: 2
|
||||
|
||||
- name: Verify gitea-ssh jail status (dedicated mode only)
|
||||
command: fail2ban-client status gitea-ssh
|
||||
register: gitea_jail_verify
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: gitea_ssh_mode == 'dedicated'
|
||||
|
||||
- name: Verify sshd jail status (passthrough mode)
|
||||
command: fail2ban-client status sshd
|
||||
register: sshd_jail_verify
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: gitea_ssh_mode == 'passthrough'
|
||||
|
||||
- name: Display fail2ban configuration status
|
||||
debug:
|
||||
msg: |
|
||||
🛡️ fail2ban configured for Gitea SSH
|
||||
📍 Filter: /etc/fail2ban/filter.d/gitea-ssh.conf
|
||||
📍 Jail: gitea-ssh (in /etc/fail2ban/jail.local)
|
||||
🔒 Protection: Port {{ gitea_ssh_port }}
|
||||
⏱️ Ban time: 1 hour (3600 seconds)
|
||||
🔢 Max retries: 5 attempts in 10 minutes
|
||||
🛡️ fail2ban Protection for Gitea SSH
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
📍 Mode: {{ gitea_ssh_mode | upper }}
|
||||
|
||||
Check status: fail2ban-client status gitea-ssh
|
||||
{% if gitea_ssh_mode == 'dedicated' %}
|
||||
📍 Jail: gitea-ssh
|
||||
📍 Port: {{ gitea_ssh_port }}
|
||||
📍 Status: {{ 'Active ✅' if gitea_jail_verify.rc == 0 else 'Not Active ⚠️' }}
|
||||
📍 Filter: /etc/fail2ban/filter.d/gitea-ssh.conf
|
||||
📍 Logfile: {{ gitea_home }}/log/gitea.log
|
||||
|
||||
Protection Settings:
|
||||
• Max retries: 5 attempts
|
||||
• Find time: 10 minutes (600 seconds)
|
||||
• Ban time: 1 hour (3600 seconds)
|
||||
|
||||
Check status:
|
||||
fail2ban-client status gitea-ssh
|
||||
|
||||
{% else %}
|
||||
📍 Jail: sshd (system jail)
|
||||
📍 Port: 22
|
||||
📍 Status: {{ 'Active ✅' if sshd_jail_verify.rc == 0 else 'Not Active ⚠️' }}
|
||||
📍 Coverage: All SSH traffic including Gitea Git operations
|
||||
|
||||
Note: In passthrough mode, the system 'sshd' jail automatically
|
||||
protects all SSH traffic on port 22, including Gitea Git
|
||||
operations. No separate gitea-ssh jail is needed.
|
||||
|
||||
Check status:
|
||||
fail2ban-client status sshd
|
||||
{% endif %}
|
||||
|
||||
# Rick-Infra: Self-contained fail2ban protection per role
|
||||
|
||||
@@ -16,23 +16,30 @@
|
||||
name: gitea
|
||||
state: present
|
||||
|
||||
# Firewall configuration - self-managed by Gitea role
|
||||
- name: Configure firewall for Gitea SSH
|
||||
import_tasks: firewall.yml
|
||||
tags: ['firewall']
|
||||
when: gitea_manage_firewall | default(true)
|
||||
# SSH Mode Configuration - Conditional based on gitea_ssh_mode
|
||||
# Mode determines how Git SSH operations are handled
|
||||
|
||||
# fail2ban protection - self-managed by Gitea role
|
||||
- name: Configure fail2ban for Gitea SSH
|
||||
import_tasks: fail2ban.yml
|
||||
tags: ['fail2ban', 'security']
|
||||
when: gitea_manage_firewall | default(true)
|
||||
- name: Configure SSH passthrough mode (default)
|
||||
import_tasks: ssh_passthrough.yml
|
||||
when: gitea_ssh_mode == "passthrough"
|
||||
tags: ['ssh', 'passthrough']
|
||||
|
||||
- name: Configure SSH dedicated mode (fallback)
|
||||
import_tasks: ssh_dedicated.yml
|
||||
when: gitea_ssh_mode == "dedicated"
|
||||
tags: ['ssh', 'dedicated']
|
||||
|
||||
- name: Install Git
|
||||
pacman:
|
||||
name: git
|
||||
state: present
|
||||
|
||||
- name: Create Gitea group
|
||||
group:
|
||||
name: "{{ gitea_group }}"
|
||||
system: yes
|
||||
state: present
|
||||
|
||||
- name: Create Gitea user and group
|
||||
user:
|
||||
name: "{{ gitea_user }}"
|
||||
@@ -156,8 +163,8 @@
|
||||
msg: |
|
||||
✅ Gitea Git service deployed successfully!
|
||||
|
||||
🌐 Web Interface: https://{{ gitea_full_domain }}
|
||||
🔗 SSH Clone: ssh://git@{{ gitea_full_domain }}:{{ gitea_ssh_port }}
|
||||
🌐 Web Interface: https://{{ gitea_http_domain }}
|
||||
🔗 SSH Clone: ssh://git@{{ gitea_ssh_domain }}:{{ gitea_ssh_port }}
|
||||
📦 Local HTTP: http://127.0.0.1:{{ gitea_http_port }}
|
||||
🗄️ Database: {{ gitea_db_name }} (self-managed)
|
||||
|
||||
|
||||
74
roles/gitea/tasks/ssh_dedicated.yml
Normal file
74
roles/gitea/tasks/ssh_dedicated.yml
Normal file
@@ -0,0 +1,74 @@
|
||||
---
|
||||
# Gitea Dedicated SSH Server Configuration - Rick-Infra
|
||||
# Configures Gitea to run its own SSH server on port 2222
|
||||
# This is the fallback mode when passthrough is not desired
|
||||
|
||||
- name: Configure firewall for Gitea SSH (dedicated mode)
|
||||
import_tasks: firewall.yml
|
||||
tags: ['firewall']
|
||||
|
||||
- name: Configure fail2ban for Gitea SSH (dedicated mode)
|
||||
import_tasks: fail2ban.yml
|
||||
tags: ['fail2ban', 'security']
|
||||
|
||||
- name: Wait for fail2ban to be ready
|
||||
pause:
|
||||
seconds: 2
|
||||
|
||||
- name: Verify gitea-ssh jail is active
|
||||
command: fail2ban-client status gitea-ssh
|
||||
register: gitea_jail_status
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Display fail2ban protection status
|
||||
debug:
|
||||
msg: |
|
||||
🛡️ Gitea SSH fail2ban protection:
|
||||
{% if gitea_jail_status.rc == 0 %}
|
||||
✅ gitea-ssh jail is ACTIVE
|
||||
{{ gitea_jail_status.stdout }}
|
||||
{% else %}
|
||||
⚠️ WARNING: gitea-ssh jail not active!
|
||||
This is a security risk - port {{ gitea_ssh_port }} is vulnerable to brute force attacks.
|
||||
{% endif %}
|
||||
|
||||
- name: Fail if gitea-ssh jail is not running (security critical)
|
||||
fail:
|
||||
msg: |
|
||||
SECURITY ERROR: gitea-ssh fail2ban jail is not active!
|
||||
Port {{ gitea_ssh_port }} is exposed but not protected.
|
||||
Check fail2ban configuration and logs.
|
||||
when: gitea_jail_status.rc != 0
|
||||
|
||||
- name: Remove SSH passthrough configuration if present
|
||||
blockinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK - Gitea SSH Passthrough"
|
||||
state: absent
|
||||
backup: yes
|
||||
register: sshd_config_cleaned
|
||||
notify: restart sshd
|
||||
|
||||
- name: Remove AuthorizedKeysCommand script if present
|
||||
file:
|
||||
path: /usr/local/bin/gitea-keys
|
||||
state: absent
|
||||
|
||||
- name: Display dedicated mode configuration
|
||||
debug:
|
||||
msg: |
|
||||
🔧 Gitea SSH Mode: DEDICATED
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
📍 SSH Server: Gitea built-in (port {{ gitea_ssh_port }})
|
||||
🔗 Clone URL: ssh://git@{{ gitea_ssh_domain }}:{{ gitea_ssh_port }}/user/repo.git
|
||||
🔥 Firewall: Port {{ gitea_ssh_port }} opened (nftables)
|
||||
🛡️ fail2ban: gitea-ssh jail protecting port {{ gitea_ssh_port }}
|
||||
|
||||
Test connection:
|
||||
ssh -T -p {{ gitea_ssh_port }} git@{{ gitea_ssh_domain }}
|
||||
|
||||
Clone repository:
|
||||
git clone ssh://git@{{ gitea_ssh_domain }}:{{ gitea_ssh_port }}/username/repo.git
|
||||
|
||||
# Rick-Infra: Self-contained dedicated SSH mode with full security
|
||||
128
roles/gitea/tasks/ssh_passthrough.yml
Normal file
128
roles/gitea/tasks/ssh_passthrough.yml
Normal file
@@ -0,0 +1,128 @@
|
||||
---
|
||||
# Gitea SSH Passthrough Configuration - Rick-Infra
|
||||
# Configures system SSH to handle Gitea Git authentication
|
||||
# This is the default mode: more secure, standard Git URLs
|
||||
|
||||
- name: Ensure OpenSSH server is installed
|
||||
pacman:
|
||||
name: openssh
|
||||
state: present
|
||||
|
||||
- name: Create Gitea AuthorizedKeysCommand script
|
||||
template:
|
||||
src: gitea-keys.sh.j2
|
||||
dest: /usr/local/bin/gitea-keys
|
||||
mode: '0755'
|
||||
owner: root
|
||||
group: root
|
||||
register: gitea_keys_script
|
||||
|
||||
- name: Configure SSH for Gitea passthrough
|
||||
blockinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK - Gitea SSH Passthrough"
|
||||
block: |
|
||||
# Gitea SSH Passthrough - Rick-Infra
|
||||
# System SSH delegates git user authentication to Gitea
|
||||
# This allows standard Git URLs: git@{{ gitea_ssh_domain }}:user/repo.git
|
||||
Match User {{ gitea_user }}
|
||||
AuthorizedKeysCommandUser {{ gitea_user }}
|
||||
AuthorizedKeysCommand /usr/local/bin/gitea-keys %u %t %k
|
||||
AllowTcpForwarding no
|
||||
AllowAgentForwarding no
|
||||
X11Forwarding no
|
||||
PermitTTY no
|
||||
backup: yes
|
||||
validate: '/usr/bin/sshd -t -f %s'
|
||||
register: sshd_config_changed
|
||||
notify: restart sshd
|
||||
|
||||
- name: Verify SSH configuration syntax
|
||||
command: sshd -t
|
||||
changed_when: false
|
||||
register: sshd_test
|
||||
|
||||
- name: Display SSH validation result
|
||||
debug:
|
||||
msg: |
|
||||
{% if sshd_test.rc == 0 %}
|
||||
✅ SSH configuration is valid
|
||||
{% else %}
|
||||
⚠️ SSH configuration test failed:
|
||||
{{ sshd_test.stderr }}
|
||||
{% endif %}
|
||||
|
||||
- name: Fail if SSH configuration is invalid
|
||||
fail:
|
||||
msg: "SSH configuration test failed. Rolling back changes."
|
||||
when: sshd_test.rc != 0
|
||||
|
||||
- name: Remove Gitea firewall rule (passthrough uses port 22)
|
||||
file:
|
||||
path: /etc/nftables.d/50-gitea.nft
|
||||
state: absent
|
||||
notify: reload nftables
|
||||
register: firewall_cleaned
|
||||
|
||||
- name: Reload nftables if firewall rule was removed
|
||||
systemd:
|
||||
name: nftables
|
||||
state: reloaded
|
||||
when: firewall_cleaned.changed
|
||||
|
||||
- name: Configure fail2ban for passthrough mode
|
||||
import_tasks: fail2ban.yml
|
||||
tags: ['fail2ban', 'security']
|
||||
|
||||
- name: Flush handlers to ensure sshd restarts if needed
|
||||
meta: flush_handlers
|
||||
|
||||
- name: Wait for SSH service to be available after restart
|
||||
wait_for:
|
||||
port: 22
|
||||
host: "{{ ansible_host | default('127.0.0.1') }}"
|
||||
timeout: 30
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
when: sshd_config_changed.changed
|
||||
|
||||
- name: Test SSH connection after configuration
|
||||
ping:
|
||||
when: sshd_config_changed.changed
|
||||
|
||||
- name: Verify passthrough is working
|
||||
command: sudo -u {{ gitea_user }} /usr/local/bin/gitea-keys ssh-rsa test
|
||||
register: gitea_keys_test
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Display passthrough mode configuration
|
||||
debug:
|
||||
msg: |
|
||||
🔧 Gitea SSH Mode: PASSTHROUGH (Default)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
📍 SSH Server: System SSH (port 22)
|
||||
🔗 Clone URL: git@{{ gitea_ssh_domain }}:user/repo.git
|
||||
🔥 Firewall: Port 2222 closed (not needed)
|
||||
🛡️ fail2ban: System 'sshd' jail protects all SSH traffic
|
||||
🔑 AuthorizedKeysCommand: /usr/local/bin/gitea-keys
|
||||
|
||||
How it works:
|
||||
1. User connects: ssh git@{{ gitea_ssh_domain }}
|
||||
2. System SSH checks: /usr/local/bin/gitea-keys
|
||||
3. Script queries Gitea database for SSH key
|
||||
4. If authorized, Gitea handles Git operation
|
||||
|
||||
Test connection:
|
||||
ssh -T git@{{ gitea_ssh_domain }}
|
||||
|
||||
Clone repository:
|
||||
git clone git@{{ gitea_ssh_domain }}:username/repo.git
|
||||
|
||||
Benefits:
|
||||
✅ Standard Git URLs (no :2222 port number)
|
||||
✅ Single SSH daemon (smaller attack surface)
|
||||
✅ System fail2ban protects everything
|
||||
✅ One port to manage and monitor
|
||||
|
||||
# Rick-Infra: Self-contained SSH passthrough mode with enhanced security
|
||||
Reference in New Issue
Block a user