Initial commit
This commit is contained in:
commit
0c5ee3d3d1
12 changed files with 292 additions and 0 deletions
18
README.md
Normal file
18
README.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
An ansible role to set up an ssh tunnel and port forwardings from the remote machine to local machines
|
||||
|
||||
# Caution
|
||||
Since the current debian version of sshd does not yet support dynamic configuration files (as in `/etc/ssh/sshd_config.d/*`), this role will **overwrite** your current sshd configuration! Normal ssh access on port 22 is still possible, but custom modifications will be lost on the remote machine.
|
||||
|
||||
# Variables you need to set
|
||||
... e.g. in `group_vars`
|
||||
- `ssh_tunnel_pubkey`: The complete line to be used in `authorized_keys`, e.g. "ssh-ed25519 AAAA[...]aU root@mylocalmachine"
|
||||
- `ssh_tunnel_privkey`: The content of the corresponding private key file, including the BEGIN and END tags. It is highly recommended to put this inside an encrypted ansible vault.
|
||||
- `tunneled_ports`: A list of port forwardings. Example:
|
||||
```
|
||||
tunneled_ports:
|
||||
- exposed_port: 80 # public port at the remote machine
|
||||
ephemeral_port: 10080 # internal port at remote machine's localhost address. The ssh tunnel will fetch traffic from there
|
||||
dest_host: my-internal-http-server.local.domain.tld # domain or IP address of the destination machine. Must be reachable form the local machine.
|
||||
dest_port: 80 # open port at the destination machine
|
||||
protocols: ["tcp"] # list of protocols for this forwarding. "tcp" and "udp" are supported.
|
||||
```
|
5
defaults/main.yml
Normal file
5
defaults/main.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
ssh_tunnel_os_supported: False
|
||||
|
||||
ssh_tunnel_autossh_system_user: autossh
|
||||
ssh_tunnel_sshd_unprivileged_user: ssh-tunnel
|
12
example_playbook.yml
Normal file
12
example_playbook.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
- hosts: my-remote-vps.domain.tld
|
||||
roles:
|
||||
- ssh_tunnel
|
||||
vars:
|
||||
location: "remote"
|
||||
|
||||
- hosts: my-local-machine.domain.tld
|
||||
roles:
|
||||
- ssh_tunnel
|
||||
vars:
|
||||
location: "local"
|
18
handlers/main.yml
Normal file
18
handlers/main.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
- name: restart autossh
|
||||
service:
|
||||
name: autossh
|
||||
state: restarted
|
||||
|
||||
- name: restart sshd
|
||||
service:
|
||||
name: sshd
|
||||
state: restarted
|
||||
|
||||
- name: save iptables v4 rules
|
||||
shell: iptables-save > /etc/iptables/rules.v4
|
||||
listen: persist iptables
|
||||
|
||||
- name: save iptables v6 rules
|
||||
shell: ip6tables-save > /etc/iptables/rules.v6
|
||||
listen: persist iptables
|
45
tasks/local.yml
Normal file
45
tasks/local.yml
Normal file
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
- name: Install autossh
|
||||
apt:
|
||||
name: autossh
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Ensure unprivileged ssh user exists
|
||||
user:
|
||||
name: "{{ ssh_tunnel_autossh_system_user }}"
|
||||
system: true
|
||||
state: present
|
||||
|
||||
- name: Set user's ssh config
|
||||
template:
|
||||
src: local/ssh_config.j2
|
||||
dest: "{{ ssh_tunnel_local_sshdir }}config"
|
||||
owner: "{{ ssh_tunnel_autossh_system_user }}"
|
||||
mode: 0644
|
||||
|
||||
- name: Set private key
|
||||
copy:
|
||||
dest: "{{ ssh_tunnel_local_sshdir }}tunnel-key"
|
||||
content: "{{ ssh_tunnel_privkey }}"
|
||||
owner: "{{ ssh_tunnel_autossh_system_user }}"
|
||||
mode: 0600
|
||||
|
||||
- name: Set public key
|
||||
copy:
|
||||
dest: "{{ ssh_tunnel_local_sshdir }}tunnel-key.pub"
|
||||
content: "{{ ssh_tunnel_pubkey }}"
|
||||
owner: "{{ ssh_tunnel_autossh_system_user }}"
|
||||
mode: 0644
|
||||
|
||||
- name: Set systemd service file
|
||||
become: yes
|
||||
template:
|
||||
src: local/autossh.service.j2
|
||||
dest: "{{ ssh_tunnel_autossh_service_file }}"
|
||||
|
||||
- name: Enable service and run it
|
||||
service:
|
||||
name: autossh
|
||||
state: restarted
|
||||
enabled: yes
|
28
tasks/main.yml
Normal file
28
tasks/main.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
- name: Set OS dependent variables
|
||||
ansible.builtin.include_vars: "{{ lookup('first_found', params) }}"
|
||||
vars:
|
||||
params:
|
||||
files:
|
||||
- "{{ ansible_distribution | lower }}_{{ ansible_distribution_version | lower }}.yml"
|
||||
- "{{ ansible_distribution | lower }}_{{ ansible_distribution_major_version | lower }}.yml"
|
||||
- "{{ ansible_distribution | lower }}.yml"
|
||||
- "{{ ansible_os_family | lower }}.yml"
|
||||
- "{{ ansible_system | lower }}.yml"
|
||||
paths:
|
||||
- '{{ role_path }}/vars'
|
||||
ignore_errors: True
|
||||
|
||||
- name: OS is supported
|
||||
ansible.builtin.assert:
|
||||
that: __os_supported
|
||||
quiet: True
|
||||
vars:
|
||||
__os_supported: "{{ lookup('vars', '{}_os_supported'.format(role_name)) | bool }}"
|
||||
|
||||
|
||||
- include_tasks: local.yml
|
||||
when: location == "local"
|
||||
|
||||
- include_tasks: remote.yml
|
||||
when: location == "remote"
|
125
tasks/remote.yml
Normal file
125
tasks/remote.yml
Normal file
|
@ -0,0 +1,125 @@
|
|||
---
|
||||
- name: Ensure unprivileged ssh user exists
|
||||
user:
|
||||
name: "{{ ssh_tunnel_sshd_unprivileged_user }}"
|
||||
system: true
|
||||
state: present
|
||||
|
||||
- name: Set authorized_keys for unprivileged user
|
||||
template:
|
||||
src: remote/authorized_keys.j2
|
||||
dest: "{{ ssh_tunnel_remote_sshdir }}authorized_keys"
|
||||
owner: "{{ ssh_tunnel_sshd_unprivileged_user }}"
|
||||
mode: 0600
|
||||
|
||||
- name: Set sshd_config
|
||||
become: yes
|
||||
template:
|
||||
src: remote/sshd_config.j2
|
||||
dest: "{{ ssh_tunnel_sshd_conf_dir }}tunnel.conf"
|
||||
mode: 0644
|
||||
owner: root
|
||||
|
||||
- name: Enable IPv4 forwarding
|
||||
sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
value: '1'
|
||||
sysctl_set: yes
|
||||
state: present
|
||||
reload: yes
|
||||
|
||||
- name: Enable IPv6 forwarding
|
||||
sysctl:
|
||||
name: net.ipv6.conf.all.forwarding
|
||||
value: '1'
|
||||
sysctl_set: yes
|
||||
state: present
|
||||
reload: yes
|
||||
|
||||
- name: Enable IPv4 local network forwarding
|
||||
sysctl:
|
||||
name: net.ipv4.conf.all.route_localnet
|
||||
value: '1'
|
||||
sysctl_set: yes
|
||||
state: present
|
||||
reload: yes
|
||||
|
||||
- name: Install iptables-persistent
|
||||
apt:
|
||||
name: iptables-persistent
|
||||
update_cache: yes
|
||||
state: present
|
||||
|
||||
- name: Flush existing iptables entries (IPv4)
|
||||
become: yes
|
||||
iptables:
|
||||
ip_version: ipv4
|
||||
table: nat
|
||||
flush: yes
|
||||
|
||||
- name: Flush existing iptables entries (IPv6)
|
||||
become: yes
|
||||
iptables:
|
||||
ip_version: ipv6
|
||||
table: nat
|
||||
flush: yes
|
||||
|
||||
- name: Forward privileged ports to ephemeral localhost ports (IPv4, TCP)
|
||||
become: yes
|
||||
iptables:
|
||||
ip_version: ipv4
|
||||
table: nat
|
||||
chain: PREROUTING
|
||||
in_interface: eth0
|
||||
protocol: tcp
|
||||
destination_port: "{{ item.exposed_port }}"
|
||||
jump: DNAT
|
||||
to_destination: "127.0.0.1:{{ item.ephemeral_port }}"
|
||||
loop: "{{ tunneled_ports }}"
|
||||
when: "'tcp' in item.protocols"
|
||||
notify: persist iptables
|
||||
|
||||
- name: Forward privileged ports to ephemeral localhost ports (IPv4, UDP)
|
||||
become: yes
|
||||
iptables:
|
||||
ip_version: ipv4
|
||||
table: nat
|
||||
chain: PREROUTING
|
||||
in_interface: eth0
|
||||
protocol: udp
|
||||
destination_port: "{{ item.exposed_port }}"
|
||||
jump: DNAT
|
||||
to_destination: "127.0.0.1:{{ item.ephemeral_port }}"
|
||||
loop: "{{ tunneled_ports }}"
|
||||
when: "'udp' in item.protocols"
|
||||
notify: persist iptables
|
||||
|
||||
- name: Forward privileged ports to ephemeral localhost ports (IPv6, TCP)
|
||||
become: yes
|
||||
iptables:
|
||||
ip_version: ipv6
|
||||
table: nat
|
||||
chain: PREROUTING
|
||||
in_interface: eth0
|
||||
protocol: tcp
|
||||
destination_port: "{{ item.exposed_port }}"
|
||||
jump: DNAT
|
||||
to_destination: "[::1]:{{ item.ephemeral_port }}"
|
||||
loop: "{{ tunneled_ports }}"
|
||||
when: "'tcp' in item.protocols"
|
||||
notify: persist iptables
|
||||
|
||||
- name: Forward privileged ports to ephemeral localhost ports (IPv6, UDP)
|
||||
become: yes
|
||||
iptables:
|
||||
ip_version: ipv6
|
||||
table: nat
|
||||
chain: PREROUTING
|
||||
in_interface: eth0
|
||||
protocol: udp
|
||||
destination_port: "{{ item.exposed_port }}"
|
||||
jump: DNAT
|
||||
to_destination: "[::1]:{{ item.ephemeral_port }}"
|
||||
loop: "{{ tunneled_ports }}"
|
||||
when: "'udp' in item.protocols"
|
||||
notify: persist iptables
|
12
templates/local/autossh.service.j2
Normal file
12
templates/local/autossh.service.j2
Normal file
|
@ -0,0 +1,12 @@
|
|||
[Unit]
|
||||
Description=AutoSSH tunnel service
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=autossh
|
||||
Environment="AUTOSSH_GATETIME=0"
|
||||
ExecStart=/usr/bin/autossh -M 0 gateway -N
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
12
templates/local/ssh_config.j2
Normal file
12
templates/local/ssh_config.j2
Normal file
|
@ -0,0 +1,12 @@
|
|||
Host gateway
|
||||
HostName tunnel-end.a-0.me
|
||||
User ssh-tunnel
|
||||
Port 22
|
||||
IdentityFile /home/autossh/.ssh/tunnel-key
|
||||
IdentitiesOnly yes
|
||||
ExitOnForwardFailure yes
|
||||
ServerAliveInterval 5
|
||||
ServerAliveCountMax 3
|
||||
{% for forwarding in tunneled_ports %}
|
||||
RemoteForward localhost:{{ forwarding.ephemeral_port }} {{ forwarding.dest_host }}:{{ forwarding.dest_port }}
|
||||
{% endfor %}
|
1
templates/remote/authorized_keys.j2
Normal file
1
templates/remote/authorized_keys.j2
Normal file
|
@ -0,0 +1 @@
|
|||
{{ ssh_tunnel_pubkey }}
|
9
templates/remote/sshd_config.j2
Normal file
9
templates/remote/sshd_config.j2
Normal file
|
@ -0,0 +1,9 @@
|
|||
ClientAliveInterval 30
|
||||
ClientAliveCountMax 3
|
||||
|
||||
Match User ssh-tunnel
|
||||
AllowTcpForwarding yes
|
||||
X11Forwarding no
|
||||
PermitTunnel no
|
||||
GatewayPorts clientspecified
|
||||
ForceCommand echo "Only forwarding"
|
7
vars/debian.yml
Normal file
7
vars/debian.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
ssh_tunnel_os_supported: True
|
||||
|
||||
ssh_tunnel_local_sshdir: "/home/{{ ssh_tunnel_autossh_system_user }}/.ssh/"
|
||||
ssh_tunnel_remote_sshdir: "/home/{{ ssh_tunnel_sshd_unprivileged_user }}/.ssh/"
|
||||
ssh_tunnel_autossh_service_file: "/etc/systemd/system/autossh.service"
|
||||
ssh_tunnel_sshd_conf_dir: "/etc/ssh/sshd_config/"
|
Loading…
Add table
Add a link
Reference in a new issue