Tinc: Difference between revisions
imported>MrVanDalo mNo edit summary |
imported>Aforemny m Add missing quotes around `address`'s value |
||
(11 intermediate revisions by 6 users not shown) | |||
Line 5: | Line 5: | ||
= How peer to peer setup in tinc = | = How peer to peer setup in tinc = | ||
The following tutorial will setup a very simple scenario, where you create a tinc vpn between | The following tutorial will setup a very simple scenario, where you create a tinc vpn between two computers in the same network. In this scenario <code>heinz</code> will connect to <code>peter</code>. But this will make <code>heinz</code> also visible to <code>peter</code>. | ||
It can easily be [https://www.tinc-vpn.org/examples/ improved to a setup with | It can easily be [https://www.tinc-vpn.org/examples/ improved to a setup with multiple computers] involved. | ||
== Overview == | == Overview == | ||
Line 22: | Line 22: | ||
== Generate keys == | == Generate keys == | ||
Tinc clients need to verify | Tinc clients need to verify themselves to each other, which is done by keys. There are multiple ways to generate your keys. Here is one. | ||
<pre>nix-shell -p tinc_pre --run | <pre>nix-shell -p tinc_pre --run "tinc generate-keys 4096"</pre> | ||
The command ask you where to put the keys. If you hit enter a few times it will generate 4 files. (instead of hitting enter you can give it different file path) | The command ask you where to put the keys. If you hit enter a few times it will generate 4 files. (instead of hitting enter you can give it different file path) | ||
Line 32: | Line 32: | ||
* <code>/etc/tinc/ed25519_key.pub</code> | * <code>/etc/tinc/ed25519_key.pub</code> | ||
== | == Create host files == | ||
The hostfile can have a lot of parameters ([https://www.tinc-vpn.org/documentation/Host-configuration-variables.html here is an overview]). | The hostfile can have a lot of parameters ([https://www.tinc-vpn.org/documentation/Host-configuration-variables.html here is an overview]). | ||
Line 43: | Line 43: | ||
Also the host files need to contain the public keys for this host. | Also the host files need to contain the public keys for this host. | ||
So lets create the two hostfiles. | So lets create the two hostfiles. Assuming we have generated keys for the 2 machines and they are stored in the folders <code>heinz</code> and <code>peter</code>. | ||
<pre>cat >hosts_heinz <<EOF | <pre>cat >hosts_heinz <<EOF | ||
Line 60: | Line 60: | ||
== Setup interface == | == Setup interface == | ||
We have to configure the tinc | We have to configure the tinc tunnel interface. | ||
=== networking.interfaces === | === networking.interfaces === | ||
NOTE: There are changes proposed to nix configuration, for using networkd based configuration instead of the current fragile scripted configuration, that will hopefully make the following section obsolete. | |||
The simplest way is to | The simplest way is to use the networking module. But it has some minor flaws on package updates. | ||
<syntaxHighlight lang=nix># for heinz | |||
networking.interfaces."tinc.${networkName}".ipv4.addresses = [ { address = "10.1.1.25"; prefixLength = 24; } ]; | |||
</syntaxHighlight> | |||
Another author has experienced problems with the network failing to restart when using the above to configure interfaces. | |||
The following snippet '''seems''' to fix that (until perhaps a more proper fix is upstreamed?): | |||
<syntaxHighlight lang=nix> | |||
# Start the unit for adding addresses if Tinc is started | |||
systemd.services."tinc.${networkName}".wants = [ "network-addresses-tinc.${networkName}.service" ]; | |||
# Stop the unit for adding addresses if Tinc is stopped or restarted | |||
systemd.services."network-addresses-tinc.${networkName}".partOf = [ "tinc.${networkName}.service" ]; | |||
# Start the unit for adding addresses after the Tinc device is added | |||
systemd.services."network-addresses-tinc.${networkName}".after = [ "sys-subsystem-net-devices-tinc.${networkName}.device" ]; | |||
</syntaxHighlight> | |||
=== tinc-up/tinc-down === | === tinc-up/tinc-down === | ||
A more robust but more complicated way to configure the | A more robust but more complicated way to configure the interfaces are the <code>tinc-up</code> and <code>tinc-down</code> scripts. | ||
First we have to create the scripts: | First we have to create the scripts: | ||
< | <syntaxHighlight lang=nix># for heinz | ||
environment.etc | environment.etc = { | ||
"tinc/private/tinc-up".source = pkgs.writeScript "tinc-up-private" '' | |||
#!${pkgs.stdenv.shell} | |||
''; | ${pkgs.nettools}/bin/ifconfig $INTERFACE 10.1.1.25 netmask 255.255.255.0 | ||
''; | |||
"tinc/private/tinc-down".source = pkgs.writeScript "tinc-down-private" '' | |||
#!${pkgs.stdenv.shell} | |||
'';</ | /run/wrappers/bin/sudo ${pkgs.nettools}/bin/ifconfig $INTERFACE down | ||
For the <code>tinc-down</code> we need to use sudo because | ''; | ||
};</syntaxHighlight> | |||
For the <code>tinc-down</code> we need to use sudo, because the user <code>tinc.private</code> who starts the service is not able to tear down the interface. | |||
So we have to | So we have to make sure this user can call sudo without entering a password. | ||
< | <syntaxHighlight lang=nix> security.sudo.extraRules = [ | ||
{ | { | ||
users = [ | users = [ "tinc.private" ]; | ||
commands = [ | commands = [ | ||
{ | { | ||
command = | command = "${pkgs.nettools}/bin/ifconfig"; | ||
options = [ | options = [ "NOPASSWD" ]; | ||
} | } | ||
]; | ]; | ||
} | } | ||
];</ | ];</syntaxHighlight> | ||
== Open the Firewall == | == Open the Firewall == | ||
The computer which you connect to | The computer which you connect to needs to open some ports. | ||
< | <syntaxHighlight lang=nix>networking.firewall.allowedUDPPorts = [ 655 ]; | ||
networking.firewall.allowedTCPPorts = [ 655 ];</ | networking.firewall.allowedTCPPorts = [ 655 ];</syntaxHighlight> | ||
== use service.tinc module == | == use service.tinc module == | ||
Now we have everything we need to configure the <code>services.tinc</code> module in our <code>configuration.nix</code> | Now we have everything we need to configure the <code>services.tinc</code> module in our <code>configuration.nix</code> file on both machines. | ||
You can recognise that the <code>services.tinc."${myMeshName}".hosts</code> have the same content on both machines. | You can recognise that the <code>services.tinc."${myMeshName}".hosts</code> have the same content on both machines. | ||
It is also ''' | It is also '''important''' that you set <code>services.tinc."${myMeshName}".name</code> to a machine that is contained in the <code>services.tinc."${myMeshName}".hosts</code>. | ||
=== /etc/nixos/tinc.nix on heinz === | === /etc/nixos/tinc.nix on heinz === | ||
< | <syntaxHighlight lang=nix>{ config, pkgs, ... }: | ||
let | let | ||
myMeshIp = | myMeshIp = "10.1.1.25"; | ||
myMeshMask = | myMeshMask = "255.255.255.0"; | ||
myMeshName = | myMeshName = "private"; | ||
in { | in { | ||
# simple interface setup | # simple interface setup | ||
# ---------------------- | # ---------------------- | ||
networking.interfaces. | networking.interfaces."tinc.${myMeshName}" = [ { address = myMeshIp; } ]; | ||
# configure tinc service | # configure tinc service | ||
# ---------------------- | # ---------------------- | ||
services.tinc.networks. | services.tinc.networks."${myMeshName}"= { | ||
name = | name = "heinz"; # who are we in this network. | ||
debugLevel = 3; # the debug level for journal -u tinc.private | debugLevel = 3; # the debug level for journal -u tinc.private | ||
chroot = false; # otherwise addresses can't be a DNS | chroot = false; # otherwise addresses can't be a DNS | ||
interfaceType = | interfaceType = "tap"; # tun might also work. | ||
extraConfig = '' | extraConfig = '' | ||
Line 155: | Line 165: | ||
# if you don't set the path as string, it will import the file in | # if you don't set the path as string, it will import the file in | ||
# in the nix/store where everybody can read it. | # in the nix/store where everybody can read it. | ||
Ed25519PrivateKeyFile = | Ed25519PrivateKeyFile = "/root/secrets/heinz/ed25519_key.priv" | ||
PrivateKeyFile = | PrivateKeyFile = "/root/secrets/heinz/rsa_key.priv" | ||
''; | ''; | ||
hosts = { | hosts = { | ||
Line 182: | Line 192: | ||
}; | }; | ||
} | } | ||
</ | </syntaxHighlight> | ||
=== /etc/nixos/tinc.nix on peter === | === /etc/nixos/tinc.nix on peter === | ||
< | <syntaxHighlight lang=nix>{ config, pkgs, ... }: | ||
let | let | ||
myMeshIp = | myMeshIp = "10.1.1.21"; | ||
myMeshMask = | myMeshMask = "255.255.255.0"; | ||
myMeshName = | myMeshName = "private"; | ||
in { | in { | ||
Line 202: | Line 212: | ||
# simple interface setup | # simple interface setup | ||
# ---------------------- | # ---------------------- | ||
networking.interfaces. | networking.interfaces."tinc.${myMeshName}" = [ { address = myMeshIp; } ]; | ||
# configure tinc service | # configure tinc service | ||
# ---------------------- | # ---------------------- | ||
services.tinc.networks. | services.tinc.networks."${myMeshName}"= { | ||
name = | name = "peter"; # who are we in this network. | ||
debugLevel = 3; # the debug level for journal -u tinc.private | debugLevel = 3; # the debug level for journal -u tinc.private | ||
chroot = false; # otherwise addresses can't be a DNS | chroot = false; # otherwise addresses can't be a DNS | ||
interfaceType = | interfaceType = "tap"; # tun might also work. | ||
extraConfig = '' | extraConfig = '' | ||
Line 220: | Line 230: | ||
# if you don't set the path as string, it will import the file in | # if you don't set the path as string, it will import the file in | ||
# in the nix/store where everybody can read it. | # in the nix/store where everybody can read it. | ||
Ed25519PrivateKeyFile = | Ed25519PrivateKeyFile = "/root/secrets/peter/ed25519_key.priv" | ||
PrivateKeyFile = | PrivateKeyFile = "/root/secrets/peter/rsa_key.priv" | ||
''; | ''; | ||
hosts = { | hosts = { | ||
Line 246: | Line 256: | ||
}; | }; | ||
}; | }; | ||
}</ | }</syntaxHighlight> |