From 870f6646480c524c1a0089a2905e0a2449b9c600 Mon Sep 17 00:00:00 2001
From: Ian Wienand <iwienand@redhat.com>
Date: Wed, 1 Jul 2020 11:47:33 +1000
Subject: [PATCH] gitea: Add reverse proxy option

This adds an option to have an Apache based reverse proxy on port 3081
forwarding to 3000.  The idea is that we can use some of the Apache
filtering rules to reject certain traffic if/when required.

It is off by default, but tested in the gate.

Change-Id: Ie34772878d9fb239a5f69f2d7b993cc1f2142930
---
 playbooks/roles/gitea/defaults/main.yaml      |  1 +
 playbooks/roles/gitea/handlers/main.yaml      |  4 +++
 playbooks/roles/gitea/tasks/main.yaml         |  5 ++++
 playbooks/roles/gitea/tasks/proxy.yaml        | 26 ++++++++++++++++
 .../roles/gitea/templates/gitea.vhost.j2      | 30 +++++++++++++++++++
 .../zuul/templates/group_vars/gitea.yaml.j2   |  3 ++
 testinfra/test_gitea.py                       |  8 +++++
 7 files changed, 77 insertions(+)
 create mode 100644 playbooks/roles/gitea/handlers/main.yaml
 create mode 100644 playbooks/roles/gitea/tasks/proxy.yaml
 create mode 100644 playbooks/roles/gitea/templates/gitea.vhost.j2

diff --git a/playbooks/roles/gitea/defaults/main.yaml b/playbooks/roles/gitea/defaults/main.yaml
index ae0017d80d..f001486a4c 100644
--- a/playbooks/roles/gitea/defaults/main.yaml
+++ b/playbooks/roles/gitea/defaults/main.yaml
@@ -1 +1,2 @@
 gitea_no_log: true
+gitea_reverse_proxy: false
diff --git a/playbooks/roles/gitea/handlers/main.yaml b/playbooks/roles/gitea/handlers/main.yaml
new file mode 100644
index 0000000000..a06fe5144d
--- /dev/null
+++ b/playbooks/roles/gitea/handlers/main.yaml
@@ -0,0 +1,4 @@
+- name: gitea Reload apache2
+  service:
+    name: apache2
+    state: reloaded
diff --git a/playbooks/roles/gitea/tasks/main.yaml b/playbooks/roles/gitea/tasks/main.yaml
index e32664d75f..d412c92b58 100644
--- a/playbooks/roles/gitea/tasks/main.yaml
+++ b/playbooks/roles/gitea/tasks/main.yaml
@@ -30,6 +30,11 @@
       - docker-compose
       - python3-requests
     state: present
+
+- name: Install reverse proxy
+  include_tasks: proxy.yaml
+  when: gitea_reverse_proxy
+
 - name: Run docker-compose pull
   shell:
     cmd: docker-compose pull
diff --git a/playbooks/roles/gitea/tasks/proxy.yaml b/playbooks/roles/gitea/tasks/proxy.yaml
new file mode 100644
index 0000000000..f05168fcdb
--- /dev/null
+++ b/playbooks/roles/gitea/tasks/proxy.yaml
@@ -0,0 +1,26 @@
+- name: Install apache2
+  apt:
+    name:
+      - apache2
+      - apache2-utils
+    state: present
+
+- name: Apache modules
+  apache2_module:
+    state: present
+    name: "{{ item }}"
+  loop:
+    - rewrite
+    - proxy
+    - proxy_http
+    - ssl
+    - headers
+
+- name: Copy apache config
+  template:
+    src: gitea.vhost.j2
+    dest: /etc/apache2/sites-enabled/000-default.conf
+    owner: root
+    group: root
+    mode: 0644
+  notify: gitea Reload apache2
diff --git a/playbooks/roles/gitea/templates/gitea.vhost.j2 b/playbooks/roles/gitea/templates/gitea.vhost.j2
new file mode 100644
index 0000000000..b687f9e6ac
--- /dev/null
+++ b/playbooks/roles/gitea/templates/gitea.vhost.j2
@@ -0,0 +1,30 @@
+Listen 3081
+
+<VirtualHost *:3081>
+  ServerName {{ inventory_hostname }}
+  ServerAdmin infra-root@opendev.org
+
+  AllowEncodedSlashes On
+
+  ErrorLog ${APACHE_LOG_DIR}/gitea-ssl-error.log
+
+  LogLevel warn
+
+  CustomLog ${APACHE_LOG_DIR}/gitea-ssl-access.log combined
+
+  SSLEngine on
+  SSLProtocol All -SSLv2 -SSLv3
+  # Note: this list should ensure ciphers that provide forward secrecy
+  SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!AES256:!aNULL:!eNULL:!MD5:!DSS:!PSK:!SRP
+  SSLHonorCipherOrder on
+
+  SSLCertificateFile /etc/letsencrypt-certs/{{ inventory_hostname }}/{{ inventory_hostname }}.cer
+  SSLCertificateKeyFile /etc/letsencrypt-certs/{{ inventory_hostname }}/{{ inventory_hostname }}.key
+  SSLCertificateChainFile /etc/letsencrypt-certs/{{ inventory_hostname }}/ca.cer
+
+  SSLProxyEngine on
+
+  ProxyPass  / https://localhost:3000/ retry=0
+  ProxyPassReverse / https://localhost:3000/
+
+</VirtualHost>
diff --git a/playbooks/zuul/templates/group_vars/gitea.yaml.j2 b/playbooks/zuul/templates/group_vars/gitea.yaml.j2
index d0dfb8a845..a2876a7e6f 100644
--- a/playbooks/zuul/templates/group_vars/gitea.yaml.j2
+++ b/playbooks/zuul/templates/group_vars/gitea.yaml.j2
@@ -7,3 +7,6 @@ gitea_db_password: 5bfuOBKtltff0XZX
 gitea_root_password: BUbBcpToMwR05ZCB
 gitea_no_log: false
 gitea_gerrit_password: yVpMWIUIvT7f6NwA
+gitea_reverse_proxy: true
+iptables_extra_public_tcp_ports:
+  - 3081
diff --git a/testinfra/test_gitea.py b/testinfra/test_gitea.py
index 6990b02c6d..e56f1f6b32 100644
--- a/testinfra/test_gitea.py
+++ b/testinfra/test_gitea.py
@@ -23,6 +23,8 @@ def test_gitea_listening(host):
     assert gitea_http.is_listening
     gitea_ssh = host.socket("tcp://0.0.0.0:222")
     assert gitea_ssh.is_listening
+    gitea_proxy = host.socket("tcp://0.0.0.0:3081")
+    assert gitea_proxy.is_listening
 
 def test_ulimit(host):
     cmd = host.run("docker exec gitea-docker_gitea-web_1 prlimit")
@@ -39,3 +41,9 @@ def test_robots(host):
                    '--resolve gitea99.opendev.org:3000:127.0.0.1 '
                    'https://gitea99.opendev.org:3000/robots.txt')
     assert 'Disallow: /' in cmd.stdout
+
+def test_proxy(host):
+    cmd = host.run('curl --insecure '
+                   '--resolve gitea99.opendev.org:3081:127.0.0.1 '
+                   'https://gitea99.opendev.org:3081/')
+    assert 'Git with a cup of tea' in cmd.stdout