aboutsummaryrefslogtreecommitdiffstats
path: root/posts/2015/201502-ssh-tunnel-and-postfix.rst
blob: 9fa9eb2c5eb78455f97832ed71852746704ba0c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
.. title: SSH tunnel with single hop, using systemd-networkd and autossh
.. date: 2015-02-01 20:00 UTC+02:00
.. modified: 2015-02-01 20:00
.. tags: archlinux, autossh, ssh, tunnel, systemd, systemd.network, postfix, TUN
.. category: admin
.. slug: ssh-tunnel-with-single-hop-using-systemd-networkd-and-autossh
.. summary: HOWTO on setting up a SSH tunnel with the help of a systemd-networkd between two machines, with no direct access to each other and modifying Postfix to use that tunnel.
.. authors: David Runge

| Recently I had the pleasure of setting up a |abbr_ssh| tunnel between two virtual machines that share no route and are located in two different subnets.
| They can however reach each other via SSH, hopping their host.
| Let's assume the following setup:

* **client1** (Arch Linux) has *10.0.5.2/24*
* **client2** (Arch Linux) has *10.0.6.2/24*
* **host** (Debian) is *10.0.5.1/24* to **client1** and *10.0.6.1/24* to **client2**

| As I needed the two clients to be able to send mail to each other and reach each others' services, I did some digging and opted for a SSH connection using |abbr_tun| devices (aka. "poor man's |abbr_vpn|").
| The following is needed to set this up:

* root access on both virtual machines (**client1** & **client2**)
* a user account on the **host** system
* SSH (|openssh| assumed) installed on all three machines

Connect the clients
___________________

Change sshd_config
------------------

| The following two settings have to be made in each clients */etc/ssh/sshd_config* (to allow root login and the creation of TUN devices):  

  .. code:: apache

    PermitRootLogin yes
    PermitTunnel yes

| I hope it is needless to say, that permitting root access via SSH has its caveats. You should make sure to set a very secure password, or only allow SSH keys for login.
|

Generate and exchange keys
--------------------------

| Generate SSH keys on **client1** (you can of course use other key types, if your OpenSSH installation allows and supports it):

  .. code:: bash

    ssh-keygen -t rsa -b 4096 -C "$(whoami)@$(hostname)-$(date -I)"

| Here you can choose between setting a password for the key (to unlock the key with *ssh-add* yourself) or not setting one (to be able to use the key on system boot with an automated service).  
| Add them to your user at **host** like this:

  .. code:: bash

    ssh-copy-id -i .ssh/id_rsa user@host

| Also add it to */root/.ssh/authorized_keys* on **client2**.
|

Use ProxyCommand to connect
---------------------------

| To make a first connection between the clients, one can use the following settings in */root/.ssh/config* of **client1** to hop **host** and connect to **client2**:  

  .. code:: apache

    Host client2
      ProxyCommand ssh user@10.0.5.1 -W 10.0.6.2:%p
      ForwardAgent yes
      User root
      ServerAliveInterval 120
      Compression yes
      ControlMaster auto
      ControlPath ~/.ssh/socket-%r@%h:%p

| The *ForwardAgent yes* setting here is especially interesting, as it forwards the SSH key of **client1** to **client2**.
| On **client1** a simple

  .. code:: bash

    ssh client2 -v

| should now directly connect to **client2** by hopping **host**.
|

Tunneling
_________

Start the tunnel
----------------

| Now to the fun part: Creating the tunnel.
| OpenSSH supports a feature similar to VPN, that creates a TUN device on both ends of the connection. As the "direct" (hopping **host**) connection between **client1** and **client2** has been setup already, let's try the tunnel:  

  .. code:: bash

    ssh -w5:5 client2 -v

| The *-w* switch will create a TUN device (*tun5* to be exact) on each client.  
| Now, to start the tunnel without executing a remote command (*-N*), compression of the data (*-C*) and disabling pseudo-tty allocation (*-T*), one can use the following:  

  .. code:: bash

    ssh -NCTv -w5:5 client2

Setting up the TUN devices
--------------------------

| A short

  .. code:: bash

    ip a s

| on **client1** and **client2** shows, that the *tun5* devices have been created on both clients. However they don't feature a link yet.
| This can be achieved by setting up a |systemd_network| with the help of |systemd-networkd|. By placing a *.network* file in */etc/systemd/network/*, the TUN device will be configured as soon as it shows up.
| Here I chose the *10.0.10.0/24* subnet, but you could use any other private subnet (that's still available in your setup).
| On **client1** (*/etc/systemd/network/client1-tun.network*):

  .. code:: ini

    [Match]
    Name=tun5
    Host=client1
    
    [Network]
    Address=10.0.10.1/24
    
    [Address]
    Address=10.0.10.1/24
    Peer=10.0.10.2/24

| On **client2** (*/etc/systemd/network/client2-tun.network*):

  .. code:: ini

    [Match]
    Name=tun5
    Host=client2
    
    [Network]
    Address=10.0.10.2/24
    
    [Address]
    Address=10.0.10.2/24
    Peer=10.0.10.1/24

| After adding the files a restart of the **systemd-networkd** service on both machines is necessary.

  .. code:: bash

    systemctl restart systemd-networkd

| Now starting the tunnel again should give a fully working point-to-point |abbr_tcp| connection between the two (virtual) machines using the TUN devices.
| If you need a more complex setup (i.e. to access the other clients' subnet), you will have to apply some routes (either using |netfilter| or |systemd-networkd|), depending on your individual setup.
|

Hosts
_____

| To make both hosts know about each other by hostname (and domain, if any), too, those can be added to the clients' */etc/hosts* files.
| On **client1** (*/etc/hosts*):

  .. code:: bash

    10.0.10.2 client2.org client2

| On **client2** (*/etc/hosts*):

  .. code:: bash

    10.0.10.1 client1.org client1

Postfix
_______

| If using |postfix| as |abbr_mta|, the service has to be configured to use */etc/hosts* before resolving to your networks DNS resolving.
| On **client1** and **client2** (*/etc/postfix/main.cf*):

  .. code:: ini

    lmtp_host_lookup = native
    smtp_host_lookup = native
    ignore_mx_lookup_error = yes

Autossh and system boot
_______________________

| Wrapping it all up, it's usually intended to have a tunnel service be started on system boot. SSH tunnels are supposedly known for their poor connectivity. One way to get around this issue is to manage them with |autossh| .
| A simple |systemd_service| file can then be used to manage this behavior.
| On **client1** (*/etc/systemd/system/tunnel@.service*):

  .. code:: ini

    [Unit]
    Description=AutoSSH tunnel to a host
    After=network.target
    
    [Service]
    Environment="AUTOSSH_GATETIME=0"
    ExecStart=/usr/bin/autossh -M 0 -NCTv -o ServerAliveInterval=45 -o ServerAliveCountMax=2 -o TCPKeepAlive=yes -w 5:5 %I
    
    [Install]
    WantedBy=multi-user.target

| Enable the service with

  .. code:: bash

    systemctl enable tunnel@client2

| Start the service with

  .. code:: bash

    systemctl start tunnel@client2


.. |openssh| raw:: html

  <a href="http://openssh.com" target="_blank">OpenSSH</a>

.. |systemd_network| raw:: html

  <a href="http://www.freedesktop.org/software/systemd/man/systemd.network.html" target="_blank">systemd network</a>

.. |systemd-networkd| raw:: html

  <a href="http://www.freedesktop.org/software/systemd/man/systemd-networkd.service.html" target="_blank">systemd-networkd</a>

.. |netfilter| raw:: html

  <a href="http://www.netfilter.org/" target="_blank">netfilter</a>

.. |systemd_service| raw:: html

  <a href="http://www.freedesktop.org/software/systemd/man/systemd.service.html" target="_blank">systemd service</a>

.. |autossh| raw:: html

  <a href="http://www.harding.motd.ca/autossh/" target="_blank">autossh</a>

.. |postfix| raw:: html

  <a href="http://www.postfix.org/" target="_blank">postfix</a>

.. |abbr_ssh| raw:: html

  <abbr title="Secure Shell" >SSH</abbr>

.. |abbr_tun| raw:: html

   <abbr title="network TUNnel (virtual-network kernel devices)" >TUN</abbr>

.. |abbr_vpn| raw:: html

  <abbr title="Virtual Private Network" >VPN</abbr>

.. |abbr_tcp| raw:: html

  <abbr title="Transmission Control Protocol" >TCP</abbr>

.. |abbr_mta| raw:: html

  <abbr title="Message Transfer Agent" >MTA</abbr>