forked from mirrors_public/oddlama_nix-config
feat: implement cidr coersion to automatically determine wireguard network size from participants
This commit is contained in:
parent
6d8f8ab2e3
commit
4057ee9051
14 changed files with 240 additions and 29 deletions
6
flake.lock
generated
6
flake.lock
generated
|
@ -31,11 +31,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1683715679,
|
||||
"narHash": "sha256-Zq2liHoVTNYql94XPTpEInQq5yY0NjRa9ZLYJv55dgE=",
|
||||
"lastModified": 1684539260,
|
||||
"narHash": "sha256-lF3+vp2UZwBjzF4pnOKYZrQOCFdnOdtvGmaFIzsaMN4=",
|
||||
"owner": "oddlama",
|
||||
"repo": "agenix-rekey",
|
||||
"rev": "e5e84230bfa071685a05acdc11a94e3be672e541",
|
||||
"rev": "e9a2bad33b7b1634af65cbc809fc31776df41fe5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -45,6 +45,7 @@ in {
|
|||
'';
|
||||
};
|
||||
|
||||
# TODO mkForce nftables
|
||||
nftables.firewall = {
|
||||
zones = lib.mkForce {
|
||||
local.localZone = true;
|
||||
|
|
|
@ -14,14 +14,142 @@
|
|||
lib.recursiveUpdate libWithNet {
|
||||
net = {
|
||||
cidr = rec {
|
||||
# host :: (ip | mac | integer) -> cidr -> ip
|
||||
#
|
||||
# Wrapper that extends the original host function to
|
||||
# check whether the argument `n` is in-range for the given cidr.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.host 255 "192.168.1.0/24"
|
||||
# "192.168.1.255"
|
||||
# > net.cidr.host (256) "192.168.1.0/24"
|
||||
# <fails with an error message>
|
||||
# > net.cidr.host (-1) "192.168.1.0/24"
|
||||
# "192.168.1.255"
|
||||
# > net.cidr.host (-256) "192.168.1.0/24"
|
||||
# "192.168.1.0"
|
||||
# > net.cidr.host (-257) "192.168.1.0/24"
|
||||
# <fails with an error message>
|
||||
host = i: n: let
|
||||
cap = libWithNet.net.cidr.capacity n;
|
||||
in
|
||||
assert lib.assertMsg (i >= (-cap) && i < cap) "The host ${toString i} lies outside of ${n}";
|
||||
libWithNet.net.cidr.host i n;
|
||||
# hostCidr :: (ip | mac | integer) -> cidr -> cidr
|
||||
#
|
||||
# Returns the nth host in the given cidr range (like cidr.host)
|
||||
# but as a cidr that retains the original prefix length.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.hostCidr 2 "192.168.1.0/24"
|
||||
# "192.168.1.2/24"
|
||||
hostCidr = n: x: "${libWithNet.net.cidr.host n x}/${toString (libWithNet.net.cidr.length x)}";
|
||||
# ip :: (cidr | ip) -> ip
|
||||
#
|
||||
# Returns just the ip part of the cidr.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.ip "192.168.1.100/24"
|
||||
# "192.168.1.100"
|
||||
# > net.cidr.ip "192.168.1.100"
|
||||
# "192.168.1.100"
|
||||
ip = x: lib.head (lib.splitString "/" x);
|
||||
# canonicalize :: cidr -> cidr
|
||||
#
|
||||
# Replaces the ip of the cidr with the canonical network address
|
||||
# (first contained address in range)
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.canonicalize "192.168.1.100/24"
|
||||
# "192.168.1.0/24"
|
||||
canonicalize = x: libWithNet.net.cidr.make (libWithNet.net.cidr.length x) (ip x);
|
||||
# coercev4 :: [cidr4] -> (cidr4 | null)
|
||||
#
|
||||
# Returns the smallest cidr network that includes all given addresses
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.coercev4 ["192.168.1.1/24" "192.168.6.1/32"]
|
||||
# "192.168.0.0/21"
|
||||
coercev4 = addrs: let
|
||||
# The smallest occurring length is the first we need to start checking, since
|
||||
# any greater cidr length represents a smaller address range which
|
||||
# wouldn't contain all of the original addresses.
|
||||
startLength = lib.foldl' lib.min 32 (map libWithNet.net.cidr.length addrs);
|
||||
possibleLengths = lib.reverseList (lib.range 0 startLength);
|
||||
# The first ip address will be "expanded" in cidr length until it covers all other
|
||||
# used addresses.
|
||||
firstIp = ip (lib.head addrs);
|
||||
# Return the first (i.e. greatest length -> smallest prefix) cidr length
|
||||
# in the list that covers all used addresses
|
||||
bestLength = lib.head (lib.filter
|
||||
# All given addresses must be contained by the generated address.
|
||||
(len:
|
||||
lib.all
|
||||
(x:
|
||||
libWithNet.net.cidr.contains
|
||||
(ip x)
|
||||
(libWithNet.net.cidr.make len firstIp))
|
||||
addrs)
|
||||
possibleLengths);
|
||||
in
|
||||
assert lib.assertMsg (!lib.any (lib.hasInfix ":") addrs) "coercev4 cannot operate on ipv6 addresses";
|
||||
if addrs == []
|
||||
then null
|
||||
else libWithNet.net.cidr.make bestLength firstIp;
|
||||
# coercev6 :: [cidr6] -> (cidr6 | null)
|
||||
#
|
||||
# Returns the smallest cidr network that includes all given addresses
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.coercev6 ["fd00:dead:cafe::/64" "fd00:fd12:3456:7890::/56"]
|
||||
# "fd00:c000::/18"
|
||||
coercev6 = addrs: let
|
||||
# The smallest occurring length is the first we need to start checking, since
|
||||
# any greater cidr length represents a smaller address range which
|
||||
# wouldn't contain all of the original addresses.
|
||||
startLength = lib.foldl' lib.min 128 (map libWithNet.net.cidr.length addrs);
|
||||
possibleLengths = lib.reverseList (lib.range 0 startLength);
|
||||
# The first ip address will be "expanded" in cidr length until it covers all other
|
||||
# used addresses.
|
||||
firstIp = ip (lib.head addrs);
|
||||
# Return the first (i.e. greatest length -> smallest prefix) cidr length
|
||||
# in the list that covers all used addresses
|
||||
bestLength = lib.head (lib.filter
|
||||
# All given addresses must be contained by the generated address.
|
||||
(len:
|
||||
lib.all
|
||||
(x:
|
||||
libWithNet.net.cidr.contains
|
||||
(ip x)
|
||||
(libWithNet.net.cidr.make len firstIp))
|
||||
addrs)
|
||||
possibleLengths);
|
||||
in
|
||||
assert lib.assertMsg (lib.all (lib.hasInfix ":") addrs) "coercev6 cannot operate on ipv4 addresses";
|
||||
if addrs == []
|
||||
then null
|
||||
else libWithNet.net.cidr.make bestLength firstIp;
|
||||
# coerce :: [cidr] -> { cidrv4 = (cidr4 | null); cidrv6 = (cidr4 | null); }
|
||||
#
|
||||
# Returns the smallest cidr network that includes all given addresses,
|
||||
# but yields two separate result for all given ipv4 and ipv6 addresses.
|
||||
# Equivalent to calling coercev4 and coercev6 on a partition individually.
|
||||
coerce = addrs: let
|
||||
v4_and_v6 = lib.partition (lib.hasInfix ":") addrs;
|
||||
in {
|
||||
cidrv4 = coercev4 v4_and_v6.wrong;
|
||||
cidrv6 = coercev6 v4_and_v6.right;
|
||||
};
|
||||
};
|
||||
ip = {
|
||||
# Checks whether the given address (with or without cidr notation) is an ipv6 address.
|
||||
isv6 = lib.hasInfix ":";
|
||||
};
|
||||
mac = {
|
||||
# Adds offset to the given base address and ensures the result is in
|
||||
|
@ -55,11 +183,22 @@
|
|||
|
||||
boot = {
|
||||
initrd.systemd.enable = true;
|
||||
|
||||
# Add "rd.systemd.unit=rescue.target" to debug initrd
|
||||
kernelParams = ["log_buf_len=10M"];
|
||||
tmp.useTmpfs = true;
|
||||
};
|
||||
|
||||
# Just before switching, remove the agenix directory if it exists.
|
||||
# This can happen when a secret is used in the initrd because it will
|
||||
# then be copied to the initramfs under the same path. This materializes
|
||||
# /run/agenix as a directory which will cause issues when the actual system tries
|
||||
# to create a link called /run/agenix. Agenix should probably fail in this case,
|
||||
# but doesn't and instead puts the generation link into the existing directory.
|
||||
# TODO See https://github.com/ryantm/agenix/pull/187.
|
||||
system.activationScripts.removeAgenixLink.text = "[[ -d /run/agenix ]] && rm -rf /run/agenix";
|
||||
system.activationScripts.agenixInstall.deps = ["removeAgenixLink"];
|
||||
|
||||
# Disable sudo which is entierly unnecessary.
|
||||
security.sudo.enable = false;
|
||||
|
||||
|
|
1
hosts/ward/microvms/test/secrets/host.pub
Normal file
1
hosts/ward/microvms/test/secrets/host.pub
Normal file
|
@ -0,0 +1 @@
|
|||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBXXjI6uB26xOF0DPy/QyLladoGIKfAtofyqPgIkCH/g
|
|
@ -93,6 +93,7 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
# TODO mkForce nftables
|
||||
networking.nftables.firewall = {
|
||||
zones = lib.mkForce {
|
||||
lan.interfaces = ["lan-self"];
|
||||
|
@ -188,5 +189,6 @@ in {
|
|||
baseCidrv4 = lanCidrv4;
|
||||
baseCidrv6 = lanCidrv6;
|
||||
};
|
||||
wireguard.openFirewallRules = ["lan-to-local"];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
# TODO mkForce nftables
|
||||
networking.nftables.firewall = {
|
||||
zones = lib.mkForce {
|
||||
lan.interfaces = ["lan1"];
|
||||
|
|
|
@ -142,8 +142,8 @@
|
|||
static = {
|
||||
matchConfig.Name = vmCfg.networking.mainLinkName;
|
||||
address = [
|
||||
vmCfg.networking.static.ipv4
|
||||
vmCfg.networking.static.ipv6
|
||||
"${vmCfg.networking.static.ipv4}/${toString (net.cidr.length cfg.networking.static.baseCidrv4)}"
|
||||
"${vmCfg.networking.static.ipv6}/${toString (net.cidr.length cfg.networking.static.baseCidrv6)}"
|
||||
];
|
||||
gateway = [
|
||||
cfg.networking.host
|
||||
|
@ -161,13 +161,14 @@
|
|||
boot.initrd.systemd.enable = mkForce false;
|
||||
|
||||
# Create a firewall zone for the bridged traffic and secure vm traffic
|
||||
# TODO mkForce nftables
|
||||
networking.nftables.firewall = {
|
||||
zones = lib.mkForce {
|
||||
zones = mkForce {
|
||||
"${vmCfg.networking.mainLinkName}".interfaces = [vmCfg.networking.mainLinkName];
|
||||
"local-vms".interfaces = ["wg-local-vms"];
|
||||
};
|
||||
|
||||
rules = lib.mkForce {
|
||||
rules = mkForce {
|
||||
"${vmCfg.networking.mainLinkName}-to-local" = {
|
||||
from = [vmCfg.networking.mainLinkName];
|
||||
to = ["local"];
|
||||
|
@ -184,8 +185,8 @@
|
|||
# We have a resolvable hostname / static ip, so all peers can directly communicate with us
|
||||
server = optionalAttrs (cfg.networking.host != null) {
|
||||
inherit (vmCfg.networking) host;
|
||||
port = 51829;
|
||||
openFirewallInRules = ["${vmCfg.networking.mainLinkName}-to-local"];
|
||||
inherit (cfg.networking.wireguard) port;
|
||||
openFirewallRules = ["${vmCfg.networking.mainLinkName}-to-local"];
|
||||
};
|
||||
# If We don't have such guarantees, so we must use a client-server architecture.
|
||||
client = optionalAttrs (cfg.networking.host == null) {
|
||||
|
@ -262,6 +263,18 @@ in {
|
|||
description = mdDoc "The ipv6 network address range to use for internal vm traffic.";
|
||||
default = "fddd::/64";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
default = 51829;
|
||||
type = types.port;
|
||||
description = mdDoc "The port to listen on.";
|
||||
};
|
||||
|
||||
openFirewallRules = mkOption {
|
||||
default = [];
|
||||
type = types.listOf types.str;
|
||||
description = mdDoc "The {option}`port` will be opened for all of the given rules in the nftable-firewall.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -387,8 +400,7 @@ in {
|
|||
extra.wireguard."${nodeName}-local-vms" = {
|
||||
server = {
|
||||
inherit (cfg.networking) host;
|
||||
port = 51829;
|
||||
openFirewallInRules = ["lan-to-local"];
|
||||
inherit (cfg.networking.wireguard) openFirewallRules port;
|
||||
};
|
||||
cidrv4 = net.cidr.hostCidr 1 cfg.networking.wireguard.cidrv4;
|
||||
cidrv6 = net.cidr.hostCidr 1 cfg.networking.wireguard.cidrv6;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
mkOption
|
||||
optionalAttrs
|
||||
optionals
|
||||
splitString
|
||||
types
|
||||
;
|
||||
|
||||
|
@ -54,6 +53,7 @@
|
|||
peerPrivateKeySecret
|
||||
peerPublicKeyPath
|
||||
usedAddresses
|
||||
toNetworkAddr
|
||||
;
|
||||
|
||||
isServer = wgCfg.server.host != null;
|
||||
|
@ -82,7 +82,7 @@
|
|||
# Figure out if there are duplicate peers or addresses so we can
|
||||
# make an assertion later.
|
||||
duplicatePeers = duplicates externalPeerNamesRaw;
|
||||
duplicateAddrs = duplicates (map (x: head (splitString "/" x)) usedAddresses);
|
||||
duplicateAddrs = duplicates (map net.cidr.ip usedAddresses);
|
||||
|
||||
# Adds context information to the assertions for this network
|
||||
assertionPrefix = "Wireguard network '${wgName}' on '${nodeName}'";
|
||||
|
@ -118,16 +118,27 @@
|
|||
(isServer && wgCfg.server.openFirewall)
|
||||
[wgCfg.server.port];
|
||||
|
||||
# TODO mkForce nftables
|
||||
networking.nftables.firewall.rules =
|
||||
mkIf
|
||||
(isServer && wgCfg.server.openFirewallInRules != [])
|
||||
(genAttrs wgCfg.server.openFirewallInRules (_: {allowedUDPPorts = [wgCfg.server.port];}));
|
||||
(isServer && wgCfg.server.openFirewallRules != [])
|
||||
(lib.mkForce (genAttrs wgCfg.server.openFirewallRules (_: {allowedUDPPorts = [wgCfg.server.port];})));
|
||||
|
||||
rekey.secrets =
|
||||
concatAttrs (map
|
||||
(other: {${peerPresharedKeySecret nodeName other}.file = peerPresharedKeyPath nodeName other;})
|
||||
(other: {
|
||||
${peerPresharedKeySecret nodeName other} = {
|
||||
file = peerPresharedKeyPath nodeName other;
|
||||
owner = "systemd-network";
|
||||
};
|
||||
})
|
||||
neededPeers)
|
||||
// {${peerPrivateKeySecret nodeName}.file = peerPrivateKeyPath nodeName;};
|
||||
// {
|
||||
${peerPrivateKeySecret nodeName} = {
|
||||
file = peerPrivateKeyPath nodeName;
|
||||
owner = "systemd-network";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.network.netdevs."${toString wgCfg.priority}-${wgName}" = {
|
||||
netdevConfig = {
|
||||
|
@ -156,21 +167,18 @@
|
|||
# plus each external peer's addresses,
|
||||
# plus each client's addresses that is connected via that node.
|
||||
AllowedIPs = snCfg.addresses;
|
||||
# TODO this needed? or even wanted at all?
|
||||
# ++ attrValues snCfg.server.externalPeers;
|
||||
# ++ map (n: (wgCfgOf n).addresses) snCfg.ourClientNodes;
|
||||
Endpoint = "${snCfg.server.host}:${toString snCfg.server.port}";
|
||||
};
|
||||
})
|
||||
(filterSelf associatedServerNodes)
|
||||
# All our external peers
|
||||
++ mapAttrsToList (extPeer: allowedIPs: let
|
||||
++ mapAttrsToList (extPeer: ips: let
|
||||
peerName = externalPeerName extPeer;
|
||||
in {
|
||||
wireguardPeerConfig = {
|
||||
PublicKey = builtins.readFile (peerPublicKeyPath peerName);
|
||||
PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName peerName}.path;
|
||||
AllowedIPs = allowedIPs;
|
||||
AllowedIPs = map (net.cidr.make 128) ips;
|
||||
# Connections to external peers should always be kept alive
|
||||
PersistentKeepalive = 25;
|
||||
};
|
||||
|
@ -207,7 +215,7 @@
|
|||
|
||||
systemd.network.networks."${toString wgCfg.priority}-${wgName}" = {
|
||||
matchConfig.Name = wgName;
|
||||
networkConfig.Address = wgCfg.addresses;
|
||||
address = map toNetworkAddr wgCfg.addresses;
|
||||
};
|
||||
};
|
||||
in {
|
||||
|
@ -239,16 +247,16 @@ in {
|
|||
description = mdDoc "Whether to open the firewall for the specified {option}`port`.";
|
||||
};
|
||||
|
||||
openFirewallInRules = mkOption {
|
||||
openFirewallRules = mkOption {
|
||||
default = [];
|
||||
type = types.listOf types.str;
|
||||
description = mdDoc "The {option}`port` will be opened for all of the given rules in the nftable-firewall.";
|
||||
};
|
||||
|
||||
externalPeers = mkOption {
|
||||
type = types.attrsOf (types.listOf (net.types.cidr-in config.addresses));
|
||||
type = types.attrsOf (types.listOf (net.types.ip-in config.addresses));
|
||||
default = {};
|
||||
example = {my-android-phone = ["10.0.0.97/32"];};
|
||||
example = {my-android-phone = ["10.0.0.97"];};
|
||||
description = mdDoc ''
|
||||
Allows defining an extra set of peers that should be added to this wireguard network,
|
||||
but will not be managed by this flake. (e.g. phones)
|
||||
|
@ -329,6 +337,7 @@ in {
|
|||
description = mdDoc ''
|
||||
The addresses (with cidr mask) to configure for this interface.
|
||||
The cidr mask determines this peers allowed address range as configured on other peers.
|
||||
The actual network cidr will automatically be derived from all network participants.
|
||||
By default this will just include {option}`cidrv4` and {option}`cidrv6` as configured.
|
||||
'';
|
||||
};
|
||||
|
|
22
nix/lib.nix
22
nix/lib.nix
|
@ -25,7 +25,6 @@
|
|||
partition
|
||||
recursiveUpdate
|
||||
removeSuffix
|
||||
splitString
|
||||
substring
|
||||
unique
|
||||
;
|
||||
|
@ -135,6 +134,10 @@ in rec {
|
|||
|
||||
# Wireguard related functions that are reused in several files of this flake
|
||||
wireguard = wgName: rec {
|
||||
# Get access to the networking lib by referring to one of the associated nodes.
|
||||
# Not ideal, but ok.
|
||||
inherit (self.nodes.${head associatedNodes}.config.lib) net;
|
||||
|
||||
sortedPeers = peerA: peerB:
|
||||
if peerA < peerB
|
||||
then {
|
||||
|
@ -199,7 +202,19 @@ in rec {
|
|||
# A list of all occurring addresses.
|
||||
usedAddresses =
|
||||
concatMap (n: self.nodes.${n}.config.extra.wireguard.${wgName}.addresses) associatedNodes
|
||||
++ flatten (concatMap (n: attrValues self.nodes.${n}.config.extra.wireguard.${wgName}.server.externalPeers) associatedNodes);
|
||||
++ flatten (concatMap (n: map (net.cidr.make 128) (attrValues self.nodes.${n}.config.extra.wireguard.${wgName}.server.externalPeers)) associatedNodes);
|
||||
|
||||
# The cidrv4 and cidrv6 of the network spanned by all participating peer addresses.
|
||||
networkAddresses = net.cidr.coerce usedAddresses;
|
||||
|
||||
# Appends / replaces the correct cidr length to the argument,
|
||||
# so that the resulting address is in the cidr.
|
||||
toNetworkAddr = addr: let
|
||||
relevantNetworkAddr =
|
||||
if net.ip.isv6 addr
|
||||
then networkAddresses.cidrv6
|
||||
else networkAddresses.cidrv4;
|
||||
in "${net.cidr.ip addr}/${toString (net.cidr.length relevantNetworkAddr)}";
|
||||
|
||||
# Creates a script that when executed outputs a wg-quick compatible configuration
|
||||
# file for use with external peers. This is a script so we can access secrets without
|
||||
|
@ -208,6 +223,7 @@ in rec {
|
|||
pkgs = self.pkgs.${system};
|
||||
snCfg = self.nodes.${serverNode}.config.extra.wireguard.${wgName};
|
||||
peerName = externalPeerName extPeer;
|
||||
addresses = map toNetworkAddr snCfg.server.externalPeers.${extPeer};
|
||||
in
|
||||
pkgs.writeShellScript "create-wg-conf-${wgName}-${serverNode}-${extPeer}" ''
|
||||
privKey=$(${pkgs.rage}/bin/rage -d ${rageDecryptArgs} ${escapeShellArg (peerPrivateKeyPath peerName)}) \
|
||||
|
@ -217,7 +233,7 @@ in rec {
|
|||
|
||||
cat <<EOF
|
||||
[Interface]
|
||||
Address = ${concatStringsSep ", " snCfg.server.externalPeers.${extPeer}}
|
||||
Address = ${concatStringsSep ", " addresses}
|
||||
PrivateKey = $privKey
|
||||
|
||||
[Peer]
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
age-encryption.org/v1
|
||||
-> X25519 whbY47wmwEeXqdKJ7MwjiyAIDpj+fruueMmPTEgnJgY
|
||||
Z3QdAcWt5mkB3eWZeNkq0eq+UJ5DjL98uciSXb91pVg
|
||||
-> piv-p256 xqSe8Q AxUBFcdy+TQ/aXS8/1dZWQxbHUbPdjdm6RcM3vyj1qxB
|
||||
huH3sE7CutLMnL2AA7riZLG2q7vfKHq1yw1cCWIUcGo
|
||||
-> _-~<XC-grease 6~]V 3\ 3l4
|
||||
VdckN3SwUIKhL7vUKNG8p3cfd64n+Ac
|
||||
--- qCoQNOQPvZlq2nU8hwmpk9zGRJe5VLK5/t6DHyQ3omw
|
||||
SÎÁÁÁăç×<,Ě�ĐË?în•S@s¦†9_ëż2@ŐĆq=‡Q
!JÚĘĘLfťśGlÔa?śŁ-ćj+š†3xf€~PxŕOÄ\É:Ć
|
|
@ -0,0 +1 @@
|
|||
ledSlUTiISwDaIZpR1tiWpK0ZQsPOYExCZCAGY5rAC8=
|
9
secrets/wireguard/ward-local-vms/keys/ward.age
Normal file
9
secrets/wireguard/ward-local-vms/keys/ward.age
Normal file
|
@ -0,0 +1,9 @@
|
|||
age-encryption.org/v1
|
||||
-> X25519 Zfuwveyf86nRchq2VM9pUX2GpEJ7fOCD8S/ZpgnohBo
|
||||
cTqLLXd0WDjeUw8v3Zi7tEu8AuHqGMouNNVMBvDSz/s
|
||||
-> piv-p256 xqSe8Q AhkBYH9xbuiZzDEEPZKdI+b8cRBwpFynKCcG27IRcxeP
|
||||
d7JvnhavlhklbmkUna76PL6E+oVVNl8AQs+Y2XgWOLM
|
||||
-> #+BWuCW-grease -y#r [YV T?;fL)t^ lrGksIs
|
||||
PWmuTyDWS1KmdmgKW3B7ITyE6Yl/Vb2cTggzNr2rDQ
|
||||
--- xHLh9TYKLUEcU+rYSNyUomo0H9bNx92gC1To/qTAav8
|
||||
iEN¸ÖdÝcˆ ç§úMf›×'
ª>Æ:û‚;Ý—Ûm¤x0•v'YY(d¹ñV·¦]…¾r”PVÏŠdÉj,N¦r&¬€”C·
|
1
secrets/wireguard/ward-local-vms/keys/ward.pub
Normal file
1
secrets/wireguard/ward-local-vms/keys/ward.pub
Normal file
|
@ -0,0 +1 @@
|
|||
E5VkPLuSW3IJ1fK3FerHCfPc6xyTzD7q8D3AATmWME0=
|
|
@ -0,0 +1,10 @@
|
|||
age-encryption.org/v1
|
||||
-> X25519 W2AeVTtVkO93zSxX59GwhBy5NwRacz6w0dEk5JptS0Q
|
||||
QZfGRkvYZjvWoK64RwH/D1pSm+Q5Z/bWa+wCiStim80
|
||||
-> piv-p256 xqSe8Q A5ODsP5r/eJxRYohpCeC/os0qx+HITx9coafiXkO5aCY
|
||||
Lfzy5uPK315poUK59pDa9UsyjzY0bf94BvpJQC4qAEQ
|
||||
-> mF-grease d w /I6vG!UZ 1fNC
|
||||
QAvTqQEf64QZ9WPtav9CjSYIx8UjIHOMdaPyzKG8OaYa6d8QsrTog1OP7sqJemmE
|
||||
+1gSHFORe7ofpxrzCFE
|
||||
--- vbL5PR2z5571aWqnQ6+6Vk8Ni11SDvWtH8dl8i3Z44k
|
||||
Hl-bS_ Ş/¶ŔŢ*B+f_şÁíĚąß娛Yř/_„ߡϾDC\I!{ć˛Ď[ŠY±ÎpęÇä¬^Z©ÂGÁ@ZE)¦Nr·ŃÇ
|
Loading…
Add table
Add a link
Reference in a new issue