diff --git a/.gitignore b/.gitignore index 4a99281..9c22647 100644 --- a/.gitignore +++ b/.gitignore @@ -95,3 +95,4 @@ playbooks/ /vaultwarden.yml /mirrors.yml /lb.yml +/gitea-proxy.yml diff --git a/bin/newrole.sh b/bin/newrole.sh index 01fb7d8..380b16f 100755 --- a/bin/newrole.sh +++ b/bin/newrole.sh @@ -24,7 +24,7 @@ echo " roles:" >> private/playbooks/$1.yml echo " - $1" >> private/playbooks/$1.yml ln -s private/playbooks/$1.yml . -echo "/${1}.yml\n" >> .gitignore +echo "/${1}.yml" >> .gitignore ( cd private/ diff --git a/roles/gitea-proxy/handlers/main.yml b/roles/gitea-proxy/handlers/main.yml new file mode 100644 index 0000000..3237fd7 --- /dev/null +++ b/roles/gitea-proxy/handlers/main.yml @@ -0,0 +1,5 @@ +--- + +- name: update known_hosts + command: "/usr/local/bin/update_known_hosts.sh" + become_user: "{{ gitea_user.username }}" diff --git a/roles/gitea-proxy/tasks/gitea-proxy.yml b/roles/gitea-proxy/tasks/gitea-proxy.yml new file mode 100644 index 0000000..f2d47dd --- /dev/null +++ b/roles/gitea-proxy/tasks/gitea-proxy.yml @@ -0,0 +1,55 @@ +--- + +- name: template gitea config in sshd_config.d + template: + src: gitea.conf.j2 + dest: /etc/ssh/sshd_config.d/gitea.conf + owner: root + group: root + mode: '0644' + tags: + - sshd + - gitea + notify: + # - reload ssh + - restart ssh + +- name: copy the ssh keys used for the ssh proxy (gitea manages authorized_keys) + copy: + src: "private/gitea/{{ item.name }}" + dest: "{{ gitea_user.home }}/.ssh/{{ item.name }}" + mode: "{{ item.mode }}" + owner: "{{ gitea_user.username }}" + group: "{{ gitea_user.username }}" + no_log: true + with_items: + - name: id_rsa + mode: "0600" + - name: id_rsa.pub + mode: "0644" + tags: + - sshd + - gitea + +- name: template scripts for ssh proxy to gitea + template: + src: "{{ item.name }}.j2" + dest: "/usr/local/bin/{{ item.name }}" + owner: "{{ item.owner }}" + group: "{{ item.owner }}" + mode: "{{ item.mode }}" + loop_control: + label: "{{ item.name }}" + with_items: + - name: update_known_hosts.sh + owner: "{{ gitea_user.username }}" + mode: '0750' + - name: gitea + owner: root + mode: '0755' + tags: + - sshd + - gitea + notify: + - update known_hosts + - restart ssh diff --git a/roles/gitea-proxy/tasks/main.yml b/roles/gitea-proxy/tasks/main.yml new file mode 100644 index 0000000..58dac17 --- /dev/null +++ b/roles/gitea-proxy/tasks/main.yml @@ -0,0 +1,3 @@ +--- + - import_tasks: gitea-proxy.yml + tags: gitea-proxy diff --git a/roles/gitea-proxy/templates/gitea.conf.j2 b/roles/gitea-proxy/templates/gitea.conf.j2 new file mode 100644 index 0000000..b415488 --- /dev/null +++ b/roles/gitea-proxy/templates/gitea.conf.j2 @@ -0,0 +1,14 @@ +# {{ ansible_managed }} + +Match User {{ gitea_user.username }} + AuthorizedKeysCommandUser {{ gitea_user.username }} + + # this sshes to the gitea container, where it runs 'gitea keys': https://docs.gitea.io/en-us/command-line/#keys + # that generates an ssh authorized_file output, which the users key is checked against + AuthorizedKeysCommand /usr/bin/ssh -p {{ gitea_ssh_port }} {{ gitea_user.username }}@{{ gitea_host }} /usr/local/bin/gitea keys -e {{ gitea_user.username }} -u %u -t %t -k %k + + # in the authorized_keys output from gitea, userse keys are prefixed with command="/usr/local/bin/gitea...", which needs + # to exist both inside of the container (its the path to the gitea binary), and on this system, where it is a wrapper + # script that ssh's to ssh on the gitea container. + # + # see: templates/gitea.j2 diff --git a/roles/gitea-proxy/templates/gitea.j2 b/roles/gitea-proxy/templates/gitea.j2 new file mode 100644 index 0000000..2e6fb92 --- /dev/null +++ b/roles/gitea-proxy/templates/gitea.j2 @@ -0,0 +1,3 @@ +#!/bin/bash +# {{ ansible_managed }} +/usr/bin/ssh -p {{ gitea_ssh_port }} {{ gitea_user.username }}@{{ gitea_host }} "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@" diff --git a/roles/gitea-proxy/templates/update_known_hosts.sh.j2 b/roles/gitea-proxy/templates/update_known_hosts.sh.j2 new file mode 100644 index 0000000..e63b72a --- /dev/null +++ b/roles/gitea-proxy/templates/update_known_hosts.sh.j2 @@ -0,0 +1,27 @@ +#!/bin/bash +# {{ ansible_managed }} + +set -e + +{% set known_hosts = gitea_user.home + "/.ssh/known_hosts" -%} + +# remove keys for {{ gitea_host }}:{{ gitea_ssh_port }} +ssh-keygen -R [{{ gitea_host }}]:{{ gitea_ssh_port }} || true +rm -v {{ known_hosts }} || true +touch {{ known_hosts }} + +# add to known_hosts +# not piping stderr (2>&1) because that tends to corrupt the file +{% for item in ["rsa", "ecdsa", "ed22519"] -%} +# ssh-keyscan -t rsa -p {{ gitea_ssh_port }} {{ gitea_host }} >> {{ known_hosts }} +{% endfor %} + +# hashed hostnames +ssh-keyscan -H -p {{ gitea_ssh_port }} {{ gitea_host }} >> {{ known_hosts }} + +# hashed ip +IPADDR=$(host {{ gitea_host }} | awk '{print $4}') +ssh-keyscan -H -p {{ gitea_ssh_port }} ${IPADDR} >> {{ known_hosts }} + +chmod 0600 {{ known_hosts }} +chown {{ gitea_user.uid }}:{{ gitea_user.gid }} {{ known_hosts }} diff --git a/roles/gitea/tasks/gitea.yml b/roles/gitea/tasks/gitea.yml index a5fa838..22bc744 100644 --- a/roles/gitea/tasks/gitea.yml +++ b/roles/gitea/tasks/gitea.yml @@ -55,32 +55,6 @@ tags: - gitea-mirror -- name: template ssh passthrough script - template: - src: ssh-passthrough.j2 - dest: /usr/local/bin/gitea - mode: 0755 - owner: git - group: git - when: gitea_ssh_enabled - tags: - - gitea-mirror - -- name: copy the ssh keys used for the ssh shim (gitea manages authorized_keys) - copy: - src: "private/gitea/{{ item.name }}" - dest: "{{ gitea_user.home }}/.ssh/{{ item.name }}" - mode: "{{ item.mode }}" - owner: "{{ gitea_user.username }}" - group: "{{ gitea_user.username }}" - no_log: true - when: gitea_ssh_enabled - with_items: - - name: id_rsa - mode: "0600" - - name: id_rsa.pub - mode: "0644" - - name: template config template: src: app.ini.j2 @@ -177,7 +151,7 @@ state: "{{ container_state | default('started') }}" container_default_behavior: compatibility ports: - - "127.0.0.1:{{ gitea_ssh_port }}:22" + - "{{ gitea_ssh_port }}:22" volumes: - "{{ gitea_user.home }}/data:/data" - "{{ gitea_user.home }}/.ssh/:/data/git/.ssh" diff --git a/roles/gitea/templates/ssh-passthrough.j2 b/roles/gitea/templates/ssh-passthrough.j2 deleted file mode 100644 index 4deac5e..0000000 --- a/roles/gitea/templates/ssh-passthrough.j2 +++ /dev/null @@ -1 +0,0 @@ -ssh -o StrictHostKeyChecking=no git@{{ bridgewithdns.gitea }} "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@" diff --git a/roles/lb/meta/main.yml b/roles/lb/meta/main.yml new file mode 100644 index 0000000..78dc6da --- /dev/null +++ b/roles/lb/meta/main.yml @@ -0,0 +1,6 @@ +--- + +dependencies: + - sshd + - gitea-proxy + - haproxy diff --git a/roles/sshd/handlers/main.yml b/roles/sshd/handlers/main.yml index d73e8e2..38b5398 100644 --- a/roles/sshd/handlers/main.yml +++ b/roles/sshd/handlers/main.yml @@ -4,3 +4,8 @@ service: name: ssh state: reloaded + +- name: restart ssh + service: + name: ssh + state: restarted diff --git a/roles/sshd/templates/sshd_config.j2 b/roles/sshd/templates/sshd_config.j2 index abc193d..5333afb 100644 --- a/roles/sshd/templates/sshd_config.j2 +++ b/roles/sshd/templates/sshd_config.j2 @@ -6,17 +6,11 @@ # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin -# The strategy used for options in the default sshd_config shipped with -# OpenSSH is to specify options with their default value where -# possible, but leave them commented. Uncommented options override the -# default value. -Include /etc/ssh/sshd_config.d/*.conf - -#Port 22 +Port {{ sshd_port | default('22') }} #AddressFamily any -#ListenAddress 0.0.0.0 -#ListenAddress :: +ListenAddress {{ sshd_listen_addr4 | default('0.0.0.0') }} +#ListenAddress {{ sshd_listen_addr6 | default('::') }} #HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_ecdsa_key @@ -57,7 +51,6 @@ PermitRootLogin {{ sshd_permit_root_login | default('yes') }} # To disable tunneled clear text passwords, change to no here! PasswordAuthentication no -#PermitEmptyPasswords no # Change to yes to enable challenge-response passwords (beware issues with # some PAM modules and threads) @@ -122,4 +115,17 @@ Subsystem sftp /usr/lib/openssh/sftp-server # AllowTcpForwarding no # PermitTTY no # ForceCommand cvs server -PasswordAuthentication no + + +# the include statement does not work as you would expect. theres a bug that makes Match rules +# included files igored: +# https://unix.stackexchange.com/questions/603224/sshd-config-using-a-match-statement-inside-an-included-file +# +# but the workaround proposed here seems to work (add "Match all" befure the "Include" statement to prevent +# the included match statements form being interpreted as parts of other statements): +# https://serverfault.com/a/1106224 +# +# it also works to place the "Include" statment at the top of the file with this workaround. + +Match all +Include /etc/ssh/sshd_config.d/*.conf