2018-06-27 19:09:04 +02:00
|
|
|
---
|
2021-08-23 19:30:11 +02:00
|
|
|
title: "tinc"
|
2018-06-27 19:09:04 +02:00
|
|
|
date: 2018-07-07T21:43:24+02:00
|
|
|
|
tags:
|
|
|
|
- NixOS
|
|
|
|
- NixOps
|
|
|
|
- Tinc
|
2018-09-30 08:50:58 +02:00
|
|
|
summary: >
|
|
|
|
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 forwarding to sub-networks and network wise activation and deactivation.
|
|
|
|
I designed it to work nicely with
|
|
|
|
NixOps.
|
|
|
|
|
|
|
|
|
2018-06-27 19:09:04 +02:00
|
|
|
---
|
|
|
|
|
2018-09-30 07:38:57 +02:00
|
|
|
# Tinc
|
|
|
|
|
2018-06-27 19:09:04 +02:00
|
|
|
In this article I will describe how to use my
|
|
|
|
[NixOS](https://nixos.org/)
|
|
|
|
tinc-module.
|
|
|
|
I had to write my own,
|
|
|
|
because the standard `services.tinc` module
|
|
|
|
misses a lot of features,
|
2018-08-15 15:42:33 +02:00
|
|
|
for example forwarding to sub-networks and network wise activation and deactivation.
|
|
|
|
I designed it to work nicely with
|
2018-06-27 19:09:04 +02:00
|
|
|
[NixOps](https://nixos.org/nixops/).
|
|
|
|
|
|
|
|
You have to `enable` and `disable ` every network you define,
|
2018-08-15 15:42:33 +02:00
|
|
|
instead of `enable ` tinc which enables all defined networks.
|
2018-06-27 19:09:04 +02:00
|
|
|
This should make it easy to define all your networks
|
2018-08-15 15:42:33 +02:00
|
|
|
in one file (to keep track about everything),
|
|
|
|
and micromanage in the computer specific definitions.
|
2018-06-27 19:09:04 +02:00
|
|
|
|
2021-07-20 18:26:46 +02:00
|
|
|
## How to import
|
2018-06-27 19:09:04 +02:00
|
|
|
|
2018-08-15 15:42:33 +02:00
|
|
|
You can use `fetchgit` to import it without downloading it yourself.
|
2018-06-27 19:09:04 +02:00
|
|
|
|
|
|
|
{{% 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
|
2021-07-20 18:08:41 +02:00
|
|
|
tincModule = pkgs.fetchgit {
|
|
|
|
"url" = "https://github.com/mrVanDalo/nixos-tinc.git";
|
|
|
|
"rev" = "1b8c822a20be38ca19120f4c5d7f9f3236851674";
|
|
|
|
"sha256" = "0a99rxhrqwh454q6w1znb0icdpm8fl4rnr1dr7xblacqjmghhyh1";
|
2018-06-27 19:09:04 +02:00
|
|
|
};
|
2021-07-20 18:08:41 +02:00
|
|
|
|
2018-06-27 19:09:04 +02:00
|
|
|
in {
|
|
|
|
imports = [
|
|
|
|
"${tincModule}"
|
|
|
|
];
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Now you are ready to go!
|
|
|
|
|
2021-07-20 18:26:46 +02:00
|
|
|
## Create Keys
|
2018-06-27 19:09:04 +02:00
|
|
|
|
2021-07-20 18:26:46 +02:00
|
|
|
First,
|
2018-06-27 19:09:04 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
```
|
2018-08-15 15:42:33 +02:00
|
|
|
$> cat *.pub > hostfile ; rm *.pub
|
2018-06-27 19:09:04 +02:00
|
|
|
```
|
|
|
|
|
2021-07-20 18:26:46 +02:00
|
|
|
### Key-File-structure for these Examples
|
2018-06-27 19:09:04 +02:00
|
|
|
|
2018-08-15 15:42:33 +02:00
|
|
|
In the following examples I expect the following file-structure for keys and config files.
|
2018-06-27 19:09:04 +02:00
|
|
|
|
|
|
|
```
|
2018-08-15 15:42:33 +02:00
|
|
|
|-- public
|
|
|
|
| |-- Gibson
|
|
|
|
| | `-- hostfile
|
|
|
|
| |-- Hackbardt
|
|
|
|
| | `-- hostfile
|
|
|
|
| `-- HAL
|
|
|
|
| `-- hostfile
|
2018-06-27 19:09:04 +02:00
|
|
|
`-- secrets
|
|
|
|
|-- Gibson
|
|
|
|
| |-- ed25519_key.priv
|
|
|
|
| `-- rsa_key.priv
|
|
|
|
|-- Hackbardt
|
|
|
|
| |-- ed25519_key.priv
|
|
|
|
| `-- rsa_key.priv
|
|
|
|
`-- HAL
|
|
|
|
|-- ed25519_key.priv
|
|
|
|
`-- rsa_key.priv
|
|
|
|
```
|
|
|
|
|
|
|
|
|
2021-07-20 18:26:46 +02:00
|
|
|
## Connect 3 computers
|
2018-06-27 19:09:04 +02:00
|
|
|
|
2018-08-15 15:42:33 +02:00
|
|
|
We want to connect 3 computers in a private network of range ``10.1.1.0/24``.
|
2021-07-20 18:26:46 +02:00
|
|
|
One computer needs to be accessible from the internet,
|
2018-06-27 19:09:04 +02:00
|
|
|
it will be the computer that connects all the other computer.
|
2018-08-15 15:42:33 +02:00
|
|
|
You can have multiple computers which are reachable from the internet
|
|
|
|
but for this example we only have one.
|
2018-06-27 19:09:04 +02:00
|
|
|
|
|
|
|
{{<figure src="/nixos/tinc/3computers.svg">}}
|
|
|
|
|
|
|
|
Here is the `configuration.nix`.
|
2021-07-20 18:08:41 +02:00
|
|
|
First we define the whole topology in `default` and
|
|
|
|
then we `enable` and configure secret-keys
|
2018-06-27 19:09:04 +02:00
|
|
|
for every computer in `Gibson`, `Hackbardt` and `HAL`
|
|
|
|
|
|
|
|
```
|
|
|
|
let
|
|
|
|
|
|
|
|
includePrivateKeys = host: {
|
|
|
|
deployment.keys."rsa_key" = {
|
2021-07-20 18:08:41 +02:00
|
|
|
keyFile = toString (./secrets/ + "/${host}/rsa_key.priv");
|
2018-06-27 19:09:04 +02:00
|
|
|
destDir = "/root/secrets";
|
|
|
|
};
|
|
|
|
deployment.keys."ed25519_key" = {
|
2021-07-20 18:08:41 +02:00
|
|
|
keyFile = toString (./secrets/ + "/${host}/ed25519_key.priv");
|
2018-06-27 19:09:04 +02:00
|
|
|
destDir = "/root/secrets";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
in {
|
|
|
|
|
|
|
|
# for all machines
|
|
|
|
# ----------------
|
|
|
|
default =
|
|
|
|
{config, pkgs, lib, ... }:
|
|
|
|
{
|
|
|
|
with lib;
|
|
|
|
services.custom.tinc =
|
|
|
|
let
|
2021-07-20 18:08:41 +02:00
|
|
|
publicHostFile = host: lib.fileContents (./public + "/${host}/hostfile");
|
2018-06-27 19:09:04 +02:00
|
|
|
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";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
# Hackbardt specific
|
|
|
|
# ------------------
|
2021-07-20 18:08:41 +02:00
|
|
|
Gibson =
|
2018-06-27 19:09:04 +02:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-08-15 15:42:33 +02:00
|
|
|
If we deploy that and check the servers,
|
|
|
|
we can see that tinc creates interfaces called `tinc.private`.
|
|
|
|
Observing the routes we see that tinc sets up everything which is needed for proper routing.
|
2018-06-27 19:09:04 +02:00
|
|
|
|
|
|
|
```
|
|
|
|
$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!
|
|
|
|
|
|
|
|
|
2021-07-20 18:26:46 +02:00
|
|
|
## Connect 2 sub-networks
|
2018-06-27 19:09:04 +02:00
|
|
|
|
2018-08-15 15:42:33 +02:00
|
|
|
So far so good,
|
2021-07-20 18:26:46 +02:00
|
|
|
but let's imagine we have some virtual machines running on 2 computers and want to make these virtual machines see each other.
|
2018-06-27 19:09:04 +02:00
|
|
|
This is a very common problem in [Kubernetes](https://kubernetes.io/).
|
2018-08-15 15:42:33 +02:00
|
|
|
It can be resolved by using the `tincSubnet` parameter,
|
|
|
|
to configure sub-network routing.
|
2018-06-27 19:09:04 +02:00
|
|
|
|
|
|
|
{{<figure src="/nixos/tinc/2subnets.svg">}}
|
|
|
|
|
|
|
|
Achieving this is very simple,
|
|
|
|
just add the `tincSubnet` parameter in the `hosts` attribute and your done.
|
|
|
|
|
2021-07-20 18:26:46 +02:00
|
|
|
```
|
2018-06-27 19:09:04 +02:00
|
|
|
...
|
|
|
|
|
|
|
|
default =
|
|
|
|
{config, pkgs, lib, ... }:
|
|
|
|
{
|
|
|
|
with lib;
|
|
|
|
services.custom.tinc =
|
|
|
|
let
|
2021-07-20 18:08:41 +02:00
|
|
|
publicHostFile = name: lib.fileContents (./public + "/${host}/hostfile");
|
2018-06-27 19:09:04 +02:00
|
|
|
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";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
...
|
|
|
|
```
|
|
|
|
|
2021-07-20 18:26:46 +02:00
|
|
|
After deployment, we can see that `Gibson` has proper routing to the configured `tincSubnet`
|
2018-08-15 15:42:33 +02:00
|
|
|
ranges as well as to `10.1.1.0/24` to reach the other network-nodes.
|
2018-06-27 19:09:04 +02:00
|
|
|
|
|
|
|
```
|
2018-08-15 15:42:33 +02:00
|
|
|
$Gibson> 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
|
2018-06-27 19:09:04 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
`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.
|
|
|
|
|
|
|
|
```
|
2018-08-15 15:42:33 +02:00
|
|
|
$Hackbardt> 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
|
2018-06-27 19:09:04 +02:00
|
|
|
```
|
|
|
|
|
2018-08-15 15:42:33 +02:00
|
|
|
The module also sets the `sysctl` parameter
|
2018-06-27 19:09:04 +02:00
|
|
|
`net.ipv4.config.tinc/private.forwarding`
|
|
|
|
and
|
|
|
|
`net.ipv6.config.tinc/private.forwarding`
|
2018-08-15 15:42:33 +02:00
|
|
|
to
|
2018-06-27 19:09:04 +02:00
|
|
|
make sure the `tinc.private` interface forwards the traffic
|
2018-08-15 15:42:33 +02:00
|
|
|
to the configured sub-networks.
|