more documentation

release
Matthew Salerno 1 year ago
parent 03aa0704b4
commit fb7f315db9

@ -12,43 +12,6 @@ You can start by reading the `ACL Configuration` section, then reading
exist to provide helpful context and advanced usage, but should not be
necessary for a working setup.
# Glosary
## ACL
Access Control List:
This is your shared configuration for the network.
## Subnet
In Wirenix, the word subnet represents any network of connected peers.
In the implementation, subnets are keyed by their `name` property. Subnet names
define the initial 32 bits after `fd` in of an the IPv6 addresses peers
connecting to the subnet will use. Generally speaking, one subnet = one
wireguard interface for each client on the subnet.
## Peer
In Wirenix, peer is any machine with a unique public key In the
implementation, peer names define last 80 bits of their IPv6 address.
## Group
In Wirenix, a group is just a tag that peers can have. These are used for
matching peers and can contain arbitrary names.
## Endpoint
In wirenix, an endpoint specifies external IP of a peer that other peers should
connect to.
In the ACL configuration, endpoints can exist on subnets, groups, and peers,
but these are just for convenience. Think of adding an endpoint to a subnet or
group as being the same as adding the endpoint to all peers in the subnet or
group.
Endpoints have filters, which can specify for which connecting clients the
endpoint will apply to.
## Filter
In Wirenix, a filter is used to select peers by their subnets, groups, and
names. A filter is made up of filter rules, specifying multiple rules will
yield the intersection of those rules.
Note that selecting by peer name will always return a list of 1 or 0 entries,
on account of names needing to be unique.
# ACL Configuration
The ACL is a nix attrset designed to be represented in JSON for easy importing
and potential use outside of the nix ecosystem.
@ -61,9 +24,10 @@ type ACL = {
groups: group[];
peers: peer[];
connections: connection[];
extraArgs?: any;
extraArgs?: any; // goes to intermediate config
};
```
Version is used to check for config compatibility and is recommended. Not
specifying version will parse the configuration with the most recent parser
available and generate a warning. Using an older configuration version than
@ -75,7 +39,7 @@ a version newer than any parsers available will throw an error.
type subnet = {
name: str;
endpoints?: endpoint[];
extraArgs?: any;
extraArgs?: any; // goes to intermediate config subnet
};
```
@ -84,7 +48,7 @@ type subnet = {
type group = {
name: str;
endpoints?: endpoint[];
extraArgs?: any;
extraArgs?: any; // goes to intermediate config group
};
```
@ -95,13 +59,13 @@ type peer = {
subnets: [subnetName: str]: {
listenPort: int;
ipAddresses?: str[];
extraArgs?: any;
extraArgs?: any; // goes to intermediate config subnetConnection
};
publicKey: string;
privateKeyFile: string;
groups?: str[];
endpoints?: endpoint[];
extraArgs?: any;
extraArgs?: any; // goes to intermediate config peer
};
```
@ -111,7 +75,7 @@ type connection = {
a: filter;
b: filter;
subnets: str[];
extraArgs?: any;
extraArgs?: any; // merged into intermediate config peerConnection
};
```
@ -131,9 +95,10 @@ type endpoint = {
persistentKeepalive?: int;
dynamicEndpointRefreshSeconds?: int;
dynamicEndpointRefreshRestartSeconds?: int;
extraArgs?: any;
extraArgs?: any; // merged to intermediate config peerConnection.endpoin
};
```
Endpoints are merged in this order: First lists of endpoints are merged top to
bottom, with the bottom endpoints overriding the top ones. Then, lists are
merged in this order: subnet -> group -> peer; with peer being the highest
@ -163,6 +128,7 @@ WireNix consists of 4 main components:
2. Parser Modules
3. The intermediate Configuration
4. Configuration Modules
The goal of splitting WireNix into modules is both for my own sanity when
developing, and to make it hackable without requiring users to make their own
fork. Users are able to specify their own Parser Modules, enabling them to use
@ -179,10 +145,7 @@ not need to consist only of NixOS peers (although at the moment, other peers
will have to be configured manually to conform to the expected settings). The
details of this file are documented in the `Top Level ACL` section.
You can make your own ACL configuration format so long as you keep the
`version` field and set it to some unique name. You can then register your
parser which takes your ACL and produces an intermediate configuration like so:
TODO
`version` field and set it to some unique name.
## Parser Modules
Parser Modules are responsible for taking an ACL and converting it to the
@ -191,7 +154,19 @@ ACL version field. A parser module must take an ACL and return the
corresponding Intermediate Configuration You can register your own parser
module like so:
TODO
```nix
modules.wirenix.additionalParsers = {
myParser = import ./my-parser.nix;
}
```
and then in your acl, set the version:
```nix
...
version = "myConfigurer";
...
```
## Intermediate Configuration
The Intermediate Configuration is a recursive attrset that is more suited for
@ -216,6 +191,7 @@ type intermediateConfiguration = {
```
### Peer
```typescript
type peer = {
subnetConnections: {[subnetName: string]: subnetConnection};
@ -228,6 +204,7 @@ type peer = {
### Subnet
```typescript
type subnet = {
peers: {[peerName: string]: peer};
@ -236,6 +213,7 @@ type subnet = {
```
### Group
```typescript
type group = {
peers: {[peerName: string]: peer};
@ -244,6 +222,7 @@ type group = {
```
### Peer Connection
```typescript
type peerConnection = {
peer: peer;
@ -254,6 +233,7 @@ type peerConnection = {
```
### Subnet Connection
```typescript
type subnetConnection = {
subnet: subnet;
@ -265,6 +245,7 @@ type subnetConnection = {
```
### Endpoint
```typescript
type endpoint = {
ip: str;
@ -289,21 +270,138 @@ intelligently selects which module to use (with priority being networkd >
network manager > static configuration). However, you can manually override
which module is used (or use your own module) in your flake.nix file:
TODO
```nix
modules.wirenix.configurer = "v0"; # there is no v0, this is just an example
```
or for your own module:
```nix
modules.wirenix.additionalConfigurers.myConfigurer = import ./my-parser.nix;
modules.wirenix.configurer = "myConfigurer";
```
# Troubleshooting
Wirenix tries to stay seperated from the inner working of your config for as
long as possible. As a result, you can do most of your troubleshooting in the
nix repl:
```sh
$ nix repl
$ nix-repl> :l <nixpkgs>
> Added 17766 variables.
$ nix-repl> :lf "sourcehut:~msalerno/wirenix"
> Added 11 variables.
$ nix-repl> parse = wirenix.lib.defaultParsers.v1 {inherit lib;}
$ nix-repl> configure = wirenix.lib.defaultConfigurers.static {inherit lib;}
$ nix-repl> acl = import ./examples/fullMesh/acl.nix # replace with your acl
# get intermediate config
$ nix-repl> intConfig = parse acl
# you can explore the structure
$ nix-repl> intConfig
> { groups = { ... }; peers = { ... }; subnets = { ... }; }
# we can also see what the generated network config would be
$ nix-repl> genPeerConfig = configure intConfig
# `configure` is only partially applied, and genPeerConfig still needs a peer name
$ nix-repl> genPeerConfig
> «lambda @ /nix/store/h8gyjv62yddarvr533vi8f2rh5w0wh1p-source/configurers/static.nix:1:33»
# we can then inspect the result
$ nix-repl> :p genPeerConfig "peer1"
> { networking = { wireguard = { interfaces = { ... }; }; }
# printing the intermediate config with :p will cause a stack overflow
# but we have a helper function for this
$ nix-repl> :p wirenix.lib.breakIntermediateRecursion intConfig
> { a bunch of hard to read data }
# you can get a string and paste it into echo -e for pretty printing
$ nix-repl> lib.generators.toPretty {} (wirenix.lib.breakIntermediateRecursion intConfig)
> "even uglier result but it copy pastes well"
```
In your terminal:
```sh
$ echo -e "paste the big text result from nix repl in here"
> a nice result
```
# Integrations:
By default, WireNix supports setting wireguard keypairs with agenix-rekey if
the module is detected (via the existence of `config.rekey`). WireNix also
supports networkd, network manager, and the nixos static network configuration
(in that order of preference).
By default, WireNix supports setting wireguard keypairs with agenix-rekey.
WireNix also supports networkd, network manager, and the nixos static network
configuration (default).
Using networkd:
```nix
TODO
```
Using network manager:
```nix
TODO
```
Using static configuration:
```nix
TODO
```
Using agenix-rekey (assuming it's already set up properly)
```nix
TODO
```
# Current Issues / Drawbacks
- To keep configuration and the initial POC simpler, assigning IP addresses
manually on subnets is not supported (yet).
- WireNix does not do NAT traversal, it's up to you to forward the correct
ports on your NAT device(s) and apply the correct firewall rules on your
router(s).
- WireNix does not allow for dynamic addition of peers. If you need something
more dynamic, look into Tailscale/Headscale.
- Peers cannot have multiple keys. If this is a desirable feature I may think
of adding it, but I cannot think of a good reason for it.
of adding it, but I cannot think of a good reason for it.
# Glosary
## ACL
Access Control List:
This is your shared configuration for the network.
## Subnet
In Wirenix, the word subnet represents any network of connected peers.
In the implementation, subnets are keyed by their `name` property. Subnet names
define the initial 32 bits after `fd` in of an the IPv6 addresses peers
connecting to the subnet will use. Generally speaking, one subnet = one
wireguard interface for each client on the subnet.
## Peer
In Wirenix, peer is any machine with a unique public key In the
implementation, peer names define last 80 bits of their IPv6 address.
## Group
In Wirenix, a group is just a tag that peers can have. These are used for
matching peers and can contain arbitrary names.
## Endpoint
In wirenix, an endpoint specifies external IP of a peer that other peers should
connect to.
In the ACL configuration, endpoints can exist on subnets, groups, and peers,
but these are just for convenience. Think of adding an endpoint to a subnet or
group as being the same as adding the endpoint to all peers in the subnet or
group.
Endpoints have filters, which can specify for which connecting clients the
endpoint will apply to.
## Filter
In Wirenix, a filter is used to select peers by their subnets, groups, and
names. A filter is made up of filter rules, specifying multiple rules will
yield the intersection of those rules.
Note that selecting by peer name will always return a list of 1 or 0 entries,
on account of names needing to be unique.
Loading…
Cancel
Save