title
date
tags
Tinc
2018-07-07T21:43:24+02:00
In this article I will describe how to use my
NixOS
tinc-module.
I had to write my own,
because the standard services.tinc
module
misses a lot of features,
for example maintaining sub-net and network wise activation and deactivation.
I designed it to be used with
NixOps .
You have to enable
and disable
every network you define,
instead of enable
tinc and which enables all defined networks.
This should make it easy to define all your networks
in one file (to keep track about everything).
How to use
To use this module you can use fetchgit
to import it.
{{% note %}}
To find the newest rev
and sha256
just call nix-shell -p nix-prefetch-git --run "nix-prefetch-git https://github.com/mrVanDalo/nixos-tinc.git"
{{% /note %}}
{pkgs, ... }:
let
tincModule = {
url = "https://github.com/mrVanDalo/nixos-tinc.git";
rev = "8755d954fcadeef5d0e30488a7b11e3f1a505769";
sha256 = "0swkk5zxg9vqdf2j0m9zki13wr0g8ws77y4v5wzklrdcmbny5qjm";
};
in {
imports = [
"${tincModule}"
];
}
Now you are ready to go!
Create Keys
First of all,
we have to create tinc keys for every computer in the VPN Mesh.
To put the keys in the current folder we use the '--config .'
option,
$> nix-shell -p tinc_pre --run "tinc --config . generate-keys 4096"
After that is done we create the hostfile
by
$> cat *.pub > hostfile
Key-File-structure for these Examples
In the following examples we use the following file-structure
|-- configuration.nix
`-- secrets
|-- Gibson
| |-- ed25519_key.priv
| |-- hostfile
| `-- rsa_key.priv
|-- Hackbardt
| |-- ed25519_key.priv
| |-- hostfile
| `-- rsa_key.priv
`-- HAL
|-- ed25519_key.priv
|-- hostfile
`-- rsa_key.priv
Using tinc to connect 3 computers
First we want to connect 3 computers in a private network of range 10.1.1.0/24
.
One computer needs to be accessable from the internet,
it will be the computer that connects all the other computer.
You can have multiple computers which are reachable but for this example we only have one.
{{
}}
Here is the configuration.nix
.
First we setup the whole infrastructure in the default
and
than we enable
and configure secret-keys
for every computer in Gibson
, Hackbardt
and HAL
let
includePrivateKeys = host: {
deployment.keys."rsa_key" = {
keyFile = ./secrets/"${host}"/rsa_key.priv;
destDir = "/root/secrets";
};
deployment.keys."ed25519_key" = {
keyFile = ./secrets/"${host}"/ed25519_key.priv;
destDir = "/root/secrets";
};
};
in {
# for all machines
# ----------------
default =
{config, pkgs, lib, ... }:
{
with lib;
services.custom.tinc =
let
publicHostFile = host: fileContent ./secrets/"${host}"/hostfile;
in {
"private" = {
debugLevel = 0;
port = 655;
networkSubnet = "10.1.1.0/24";
hosts = {
Gibson = {
realAddress = [ "my.awesome.dns.com" ];
tincIp = "10.1.1.1";
publicKey = publicHostFile "Gibson";
};
Hackbardt = {
tincIp = "10.1.1.2";
publicKey = publicHostFile "Hackbardt";
};
HAL = {
tincIp = "10.1.1.3";
publicKey = publicHostFile "HAL";
};
};
};
};
}
# Gibson specific
# ---------------
Gibson =
{config, pkgs, ... }:
includePrivateKeys "Gibson" // {
services.custom.tinc = {
"private" = {
enable = true;
privateRsaKeyFile = config.deployment.keys."rsa_key".path;
privateEd25519KeyFile = config.deployment.keys."ed25519_key".path;
};
};
}
# Hackbardt specific
# ------------------
Hackbardt =
{config, pkgs, ... }:
includePrivateKeys "Hackbardt" // {
services.custom.tinc = {
"private" = {
enable = true;
connectTo = [ "Gibson" ];
privateRsaKeyFile = config.deployment.keys."rsa_key".path;
privateEd25519KeyFile = config.deployment.keys."ed25519_key".path;
};
};
}
# HAL specific
# ------------
HAL =
{config, pkgs, ... }:
includePrivateKeys "HAL" // {
services.custom.tinc = {
"private" = {
enable = true;
connectTo = [ "Gibson" ];
privateRsaKeyFile = config.deployment.keys."rsa_key".path;
privateEd25519KeyFile = config.deployment.keys."ed25519_key".path;
};
};
}
}
If we deploy that and check the servers,
we can see tinc creates interfaces called tinc.private
.
Observing the routes we see that tinc sets up everything so these computers can see each other.
$Gibson> ip addr show dev tinc.private
4: tinc.private: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 3f:ac:bd:c2:f6:9c brd ff:ff:ff:ff:ff:ff
inet 10.1.1.1/32 scope global tinc.private
valid_lft forever preferred_lft forever
inet 169.254.22.60/16 brd 169.254.255.255 scope global tinc.private
valid_lft forever preferred_lft forever
inet6 ffa1::2afc:b2ff:fcf2:f97a/64 scope link
valid_lft forever preferred_lft forever
$Gibson> ip route show dev tinc.private
10.1.1.0/24 scope link
169.254.0.0/16 proto kernel scope link src 169.254.22.60 metric 204
It also creates /etc/host
entries <computername>.<networkname>
so you don't have to remember the IPs.
$Gibson> ping HAL.private -c 1
PING HAL.private (10.1.1.3) 56(84) bytes of data.
64 bytes from HAL.private (10.1.1.1): icmp_seq=1 ttl=64 time=5.27 ms
Awesome! That was easy!
Using tinc to connect 2 sub-nets
So far so good,
but lets imagine we have some virtual machines running on 2 computers and want to make these virtual machines see each other.
This is a very common problem in Kubernetes .
It can be resolved by using the tincSubnet
parameter.
{{
}}
Achieving this is very simple,
just add the tincSubnet
parameter in the hosts
attribute and your done.
...
default =
{config, pkgs, lib, ... }:
{
with lib;
services.custom.tinc =
let
publicHostFile = name: fileContent ./secrets/"${name}"/hostfile;
in {
"private" = {
debugLevel = 0;
port = 655;
networkSubnet = "10.1.1.0/24";
hosts = {
Gibson = {
realAddress = [ "my.awesome.dns.com" ];
tincIp = "10.1.1.1";
publicKey = publicHostFile "Gibson";
};
Hackbardt = {
tincIp = "10.1.1.2";
subnetIp = "10.2.2.0/24";
publicKey = publicHostFile "Hackbardt";
};
HAL = {
tincIp = "10.1.1.3";
subnetIp = "10.2.3.0/24";
publicKey = publicHostFile "HAL";
};
};
};
};
}
...
After deployment we can see that Gibson
has proper routing to the configured tincSubnet
ranges as well as to 10.1.1.0/24
to reach other the computers.
$> ip route show dev tinc.private
10.1.1.0/24 scope link
10.2.2.0/24 scope link
10.2.3.0/24 scope link
169.254.0.0/16 proto kernel scope link src 169.254.116.112 metric 203
Hackbardt
has routing to the network provided by HAL
,
but has no routing (on the tinc.private
interface) to the network it provides it self.
$> ip route show dev tinc.private
10.1.1.0/24 scope link
10.2.2.0/24 scope link
169.254.0.0/16 proto kernel scope link src 169.254.116.112 metric 203
The module also sets the sysctl
parameter
net.ipv4.config.tinc/private.forwarding
and
net.ipv6.config.tinc/private.forwarding
to
make sure the tinc.private
interface forwards the traffic
to the configured sub-nets.
{{% note %}}
If that is not set to true, you have to turn it on yourself.
In the future this will also be managed by the module
.
{{% /note %}}