wip
This commit is contained in:
parent
c51d226f89
commit
49d2572998
12 changed files with 550 additions and 4 deletions
3
bundles/systemd-networkd/files/resolv.conf
Normal file
3
bundles/systemd-networkd/files/resolv.conf
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
% for nameserver in sorted(node.metadata.get('nameservers', {'9.9.9.10', '2620:fe::10'})):
|
||||||
|
nameserver ${nameserver}
|
||||||
|
% endfor
|
50
bundles/systemd-networkd/files/template-iface-nodhcp.network
Normal file
50
bundles/systemd-networkd/files/template-iface-nodhcp.network
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<%
|
||||||
|
from ipaddress import ip_network
|
||||||
|
%>\
|
||||||
|
[Match]
|
||||||
|
Name=${interface}
|
||||||
|
|
||||||
|
% for addr in sorted(config.get('ips', set())):
|
||||||
|
[Address]
|
||||||
|
<%
|
||||||
|
if '/' in addr:
|
||||||
|
ip, prefix = addr.split('/')
|
||||||
|
else:
|
||||||
|
ip = addr
|
||||||
|
prefix = '32'
|
||||||
|
%>\
|
||||||
|
Address=${ip}/${prefix}
|
||||||
|
|
||||||
|
% endfor
|
||||||
|
% for route, rconfig in sorted(config.get('routes', {}).items()):
|
||||||
|
[Route]
|
||||||
|
% if 'via' in rconfig:
|
||||||
|
Gateway=${rconfig['via']}
|
||||||
|
% endif
|
||||||
|
Destination=${route}
|
||||||
|
GatewayOnlink=yes
|
||||||
|
|
||||||
|
% endfor
|
||||||
|
% if 'gateway4' in config:
|
||||||
|
[Route]
|
||||||
|
Gateway=${config['gateway4']}
|
||||||
|
GatewayOnlink=yes
|
||||||
|
|
||||||
|
% endif
|
||||||
|
% if 'gateway6' in config:
|
||||||
|
[Route]
|
||||||
|
Gateway=${config['gateway6']}
|
||||||
|
GatewayOnlink=yes
|
||||||
|
|
||||||
|
% endif
|
||||||
|
[Network]
|
||||||
|
DHCP=no
|
||||||
|
IPv6AcceptRA=no
|
||||||
|
|
||||||
|
% if config.get('forwarding', False):
|
||||||
|
IPForward=yes
|
||||||
|
%endif
|
||||||
|
|
||||||
|
% for vlan in sorted(config.get('vlans', set())):
|
||||||
|
VLAN=${interface}.${vlan}
|
||||||
|
% endfor
|
142
bundles/systemd-networkd/items.py
Normal file
142
bundles/systemd-networkd/items.py
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
assert node.has_bundle('systemd')
|
||||||
|
|
||||||
|
from bundlewrap.exceptions import BundleError
|
||||||
|
|
||||||
|
|
||||||
|
files = {
|
||||||
|
'/etc/network/interfaces': {
|
||||||
|
'delete': True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.metadata.get('systemd-networkd/enable-resolved', False):
|
||||||
|
symlinks['/etc/resolv.conf'] = {
|
||||||
|
'target': '/run/systemd/resolve/stub-resolv.conf',
|
||||||
|
}
|
||||||
|
svc_systemd['systemd-resolved'] = {}
|
||||||
|
else:
|
||||||
|
files['/etc/resolv.conf'] = {
|
||||||
|
'content_type': 'mako',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
directories = {
|
||||||
|
'/etc/systemd/network': {
|
||||||
|
'purge': True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mac_host_prefix = '%04x' % (node.magic_number % 65534)
|
||||||
|
generated_mac = f'52:54:00:{mac_host_prefix[0:2]}:{mac_host_prefix[2:4]}:{{}}'
|
||||||
|
|
||||||
|
# Don't use .get() here. We might end up with a node without a network
|
||||||
|
# config!
|
||||||
|
for interface, config in node.metadata['interfaces'].items():
|
||||||
|
if config.get('dhcp', False):
|
||||||
|
if 'vlans' in config:
|
||||||
|
raise BundleError(f'{node.name} interface {interface} cannot use vlans and dhcp!')
|
||||||
|
template = 'template-iface-dhcp.network'
|
||||||
|
else:
|
||||||
|
template = 'template-iface-nodhcp.network'
|
||||||
|
|
||||||
|
if '.' in interface:
|
||||||
|
vlan_id = int(interface.split('.')[1])
|
||||||
|
vlan_hex = '%02x' % (vlan_id % 255)
|
||||||
|
files['/etc/systemd/network/60-iface-{}.netdev'.format(interface)] = {
|
||||||
|
'source': 'template-iface-vlan.netdev',
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'interface': interface,
|
||||||
|
'vlan': vlan_id,
|
||||||
|
'mac': generated_mac.format(vlan_hex)
|
||||||
|
},
|
||||||
|
'needed_by': {
|
||||||
|
'svc_systemd:systemd-networkd',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:systemd-networkd:restart',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
weight = 61
|
||||||
|
else:
|
||||||
|
weight = 50
|
||||||
|
|
||||||
|
if not config.get('ignore', False):
|
||||||
|
files['/etc/systemd/network/{}-iface-{}.network'.format(weight, interface)] = {
|
||||||
|
'source': template,
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'interface': interface,
|
||||||
|
'config': config,
|
||||||
|
},
|
||||||
|
'needed_by': {
|
||||||
|
'svc_systemd:systemd-networkd',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:systemd-networkd:restart',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for bond, config in node.metadata.get('systemd-networkd/bonds', {}).items():
|
||||||
|
files['/etc/systemd/network/20-bond-{}.netdev'.format(bond)] = {
|
||||||
|
'source': 'template-bond.netdev',
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'bond': bond,
|
||||||
|
'mode': config.get('mode', '802.3ad'),
|
||||||
|
'prio': config.get('priority', '32768'),
|
||||||
|
},
|
||||||
|
'needed_by': {
|
||||||
|
'svc_systemd:systemd-networkd',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:systemd-networkd:restart',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
files['/etc/systemd/network/21-bond-{}.network'.format(bond)] = {
|
||||||
|
'source': 'template-bond.network',
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'bond': bond,
|
||||||
|
'match': config['match'],
|
||||||
|
},
|
||||||
|
'needed_by': {
|
||||||
|
'svc_systemd:systemd-networkd',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:systemd-networkd:restart',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for brname, config in node.metadata.get('systemd-networkd/bridges', {}).items():
|
||||||
|
files['/etc/systemd/network/30-bridge-{}.netdev'.format(brname)] = {
|
||||||
|
'source': 'template-bridge.netdev',
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'bridge': brname,
|
||||||
|
},
|
||||||
|
'needed_by': {
|
||||||
|
'svc_systemd:systemd-networkd',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:systemd-networkd:restart',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
files['/etc/systemd/network/31-bridge-{}.network'.format(brname)] = {
|
||||||
|
'source': 'template-bridge.network',
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'bridge': brname,
|
||||||
|
'match': config['match'],
|
||||||
|
},
|
||||||
|
'needed_by': {
|
||||||
|
'svc_systemd:systemd-networkd',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:systemd-networkd:restart',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
svc_systemd = {
|
||||||
|
'systemd-networkd': {},
|
||||||
|
}
|
29
bundles/systemd-networkd/metadata.py
Normal file
29
bundles/systemd-networkd/metadata.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
defaults = {
|
||||||
|
'apt': {
|
||||||
|
'packages': {
|
||||||
|
'resolvconf': {
|
||||||
|
'installed': False,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'interfaces',
|
||||||
|
)
|
||||||
|
def add_vlan_infos_to_interface(metadata):
|
||||||
|
interfaces = {}
|
||||||
|
|
||||||
|
for iface in metadata.get('interfaces', {}):
|
||||||
|
if not '.' in iface:
|
||||||
|
continue
|
||||||
|
|
||||||
|
interface,vlan = iface.split('.')
|
||||||
|
|
||||||
|
interfaces.setdefault(interface, {}).setdefault('vlans', set())
|
||||||
|
interfaces[interface]['vlans'].add(vlan)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'interfaces': interfaces,
|
||||||
|
}
|
25
bundles/wireguard/files/wg0.netdev
Normal file
25
bundles/wireguard/files/wg0.netdev
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
[NetDev]
|
||||||
|
Name=wg0
|
||||||
|
Kind=wireguard
|
||||||
|
Description=WireGuard server
|
||||||
|
|
||||||
|
[WireGuard]
|
||||||
|
PrivateKey=${privatekey}
|
||||||
|
ListenPort=51820
|
||||||
|
|
||||||
|
% for peer, config in sorted(peers.items()):
|
||||||
|
# Peer ${peer}
|
||||||
|
[WireGuardPeer]
|
||||||
|
PublicKey=${config['pubkey']}
|
||||||
|
% if len(peers) == 1: # FIXME
|
||||||
|
AllowedIPs=${network}
|
||||||
|
% else:
|
||||||
|
AllowedIPs=${','.join(sorted(config['ips']))}
|
||||||
|
% endif
|
||||||
|
PresharedKey=${config['psk']}
|
||||||
|
% if 'endpoint' in config:
|
||||||
|
Endpoint=${config['endpoint']}
|
||||||
|
% endif
|
||||||
|
PersistentKeepalive=30
|
||||||
|
|
||||||
|
% endfor
|
21
bundles/wireguard/items.py
Normal file
21
bundles/wireguard/items.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from ipaddress import ip_network
|
||||||
|
|
||||||
|
repo.libs.tools.require_bundle(node, 'systemd-networkd')
|
||||||
|
|
||||||
|
network = ip_network(node.metadata['wireguard']['my_ip'], strict=False)
|
||||||
|
|
||||||
|
files = {
|
||||||
|
'/etc/systemd/network/wg0.netdev': {
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'network': f'{network.network_address}/{network.prefixlen}',
|
||||||
|
**node.metadata['wireguard'],
|
||||||
|
},
|
||||||
|
'needs': {
|
||||||
|
'pkg_apt:wireguard',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:systemd-networkd:restart',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
140
bundles/wireguard/metadata.py
Normal file
140
bundles/wireguard/metadata.py
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
from ipaddress import ip_network
|
||||||
|
|
||||||
|
from bundlewrap.exceptions import NoSuchNode
|
||||||
|
from bundlewrap.metadata import atomic
|
||||||
|
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
'apt': {
|
||||||
|
'packages': {
|
||||||
|
'wireguard': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'wireguard': {
|
||||||
|
'privatekey': repo.libs.keys.gen_privkey(repo, f'{node.name} wireguard privatekey'),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'wireguard/peers',
|
||||||
|
)
|
||||||
|
def peer_psks(metadata):
|
||||||
|
peers = {}
|
||||||
|
|
||||||
|
for peer_name in metadata.get('wireguard/peers', {}):
|
||||||
|
peers[peer_name] = {}
|
||||||
|
|
||||||
|
if node.name < peer_name:
|
||||||
|
peers[peer_name] = {
|
||||||
|
'psk': repo.vault.random_bytes_as_base64_for(f'{node.name} wireguard {peer_name}'),
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
peers[peer_name] = {
|
||||||
|
'psk': repo.vault.random_bytes_as_base64_for(f'{peer_name} wireguard {node.name}'),
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'wireguard': {
|
||||||
|
'peers': peers,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'wireguard/peers',
|
||||||
|
)
|
||||||
|
def peer_pubkeys(metadata):
|
||||||
|
peers = {}
|
||||||
|
|
||||||
|
for peer_name in metadata.get('wireguard/peers', {}):
|
||||||
|
try:
|
||||||
|
rnode = repo.get_node(peer_name)
|
||||||
|
except NoSuchNode:
|
||||||
|
continue
|
||||||
|
|
||||||
|
peers[peer_name] = {
|
||||||
|
'pubkey': repo.libs.keys.get_pubkey_from_privkey(
|
||||||
|
repo,
|
||||||
|
f'{rnode.name} wireguard pubkey',
|
||||||
|
rnode.metadata.get('wireguard/privatekey'),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'wireguard': {
|
||||||
|
'peers': peers,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'wireguard/peers',
|
||||||
|
)
|
||||||
|
def peer_ips_and_endpoints(metadata):
|
||||||
|
peers = {}
|
||||||
|
|
||||||
|
for peer_name in metadata.get('wireguard/peers', {}):
|
||||||
|
try:
|
||||||
|
rnode = repo.get_node(peer_name)
|
||||||
|
except NoSuchNode:
|
||||||
|
continue
|
||||||
|
|
||||||
|
ips = rnode.metadata.get('wireguard/subnets', set())
|
||||||
|
ips.add(rnode.metadata.get('wireguard/my_ip').split('/')[0])
|
||||||
|
ips = repo.libs.tools.remove_more_specific_subnets(ips)
|
||||||
|
|
||||||
|
peers[rnode.name] = {
|
||||||
|
'endpoint': '{}:51820'.format(rnode.metadata.get('wireguard/external_hostname', rnode.hostname)),
|
||||||
|
'ips': ips,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'wireguard': {
|
||||||
|
'peers': peers,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'interfaces/wg0/ips',
|
||||||
|
)
|
||||||
|
def interface_ips(metadata):
|
||||||
|
return {
|
||||||
|
'interfaces': {
|
||||||
|
'wg0': {
|
||||||
|
'ips': {
|
||||||
|
metadata.get('wireguard/my_ip'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'interfaces/wg0/routes',
|
||||||
|
)
|
||||||
|
def routes(metadata):
|
||||||
|
network = ip_network(metadata.get('wireguard/my_ip'), strict=False)
|
||||||
|
ips = {
|
||||||
|
f'{network.network_address}/{network.prefixlen}',
|
||||||
|
}
|
||||||
|
routes = {}
|
||||||
|
|
||||||
|
for _, peer_config in metadata.get('wireguard/peers', {}).items():
|
||||||
|
for ip in peer_config['ips']:
|
||||||
|
ips.add(ip)
|
||||||
|
|
||||||
|
if '0.0.0.0/0' in ips:
|
||||||
|
ips.remove('0.0.0.0/0')
|
||||||
|
|
||||||
|
for ip in repo.libs.tools.remove_more_specific_subnets(ips):
|
||||||
|
routes[ip] = {}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'interfaces': {
|
||||||
|
'wg0': {
|
||||||
|
'routes': routes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
'bundles': [
|
'bundles': [
|
||||||
'apt',
|
'apt',
|
||||||
'systemd',
|
'systemd',
|
||||||
|
'systemd-networkd',
|
||||||
],
|
],
|
||||||
'os': 'debian',
|
'os': 'debian',
|
||||||
'pip_command': 'pip3',
|
'pip_command': 'pip3',
|
||||||
|
|
15
libs/keys.py
Normal file
15
libs/keys.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import base64
|
||||||
|
from nacl.public import PrivateKey
|
||||||
|
from nacl.encoding import Base64Encoder
|
||||||
|
from bundlewrap.utils import Fault
|
||||||
|
|
||||||
|
def gen_privkey(repo, identifier):
|
||||||
|
return repo.vault.random_bytes_as_base64_for(identifier)
|
||||||
|
|
||||||
|
def get_pubkey_from_privkey(repo, identifier, privkey):
|
||||||
|
# FIXME this assumes the privkey is always a base64 encoded string
|
||||||
|
def derive_pubkey():
|
||||||
|
pub_key = PrivateKey(base64.b64decode(str(privkey))).public_key
|
||||||
|
return pub_key.encode(encoder=Base64Encoder).decode('ascii')
|
||||||
|
|
||||||
|
return Fault(f'pubkey from privkey {identifier}', derive_pubkey)
|
88
libs/tools.py
Normal file
88
libs/tools.py
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
from ipaddress import ip_address, ip_network, IPv4Address, IPv4Network
|
||||||
|
|
||||||
|
from bundlewrap.exceptions import NoSuchGroup, NoSuchNode, BundleError
|
||||||
|
from bundlewrap.utils.text import bold, red
|
||||||
|
from bundlewrap.utils.ui import io
|
||||||
|
|
||||||
|
def resolve_identifier(repo, identifier):
|
||||||
|
"""
|
||||||
|
Try to resolve an identifier (group or node). Return a set of ip
|
||||||
|
addresses valid for this identifier.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
nodes = {repo.get_node(identifier)}
|
||||||
|
except NoSuchNode:
|
||||||
|
try:
|
||||||
|
nodes = repo.nodes_in_group(identifier)
|
||||||
|
except NoSuchGroup:
|
||||||
|
try:
|
||||||
|
ip = ip_network(identifier)
|
||||||
|
|
||||||
|
if isinstance(ip, IPv4Network):
|
||||||
|
return {'ipv4': {ip}, 'ipv6': set()}
|
||||||
|
else:
|
||||||
|
return {'ipv4': set(), 'ipv6': {ip}}
|
||||||
|
except Exception as e:
|
||||||
|
io.stderr('{x} {t} Exception while resolving "{i}": {e}'.format(
|
||||||
|
x=red('✘'),
|
||||||
|
t=bold('libs.tools.resolve_identifier'),
|
||||||
|
i=identifier,
|
||||||
|
e=str(e),
|
||||||
|
))
|
||||||
|
raise
|
||||||
|
|
||||||
|
found_ips = set()
|
||||||
|
for node in nodes:
|
||||||
|
for interface, config in node.metadata.get('interfaces', {}).items():
|
||||||
|
for ip in config.get('ips', set()):
|
||||||
|
if '/' in ip:
|
||||||
|
found_ips.add(ip_address(ip.split('/')[0]))
|
||||||
|
else:
|
||||||
|
found_ips.add(ip_address(ip))
|
||||||
|
|
||||||
|
if node.metadata.get('external_ipv4', None):
|
||||||
|
found_ips.add(ip_address(node.metadata.get('external_ipv4')))
|
||||||
|
|
||||||
|
ip_dict = {
|
||||||
|
'ipv4': set(),
|
||||||
|
'ipv6': set(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for ip in found_ips:
|
||||||
|
if isinstance(ip, IPv4Address):
|
||||||
|
ip_dict['ipv4'].add(ip)
|
||||||
|
else:
|
||||||
|
ip_dict['ipv6'].add(ip)
|
||||||
|
|
||||||
|
return ip_dict
|
||||||
|
|
||||||
|
|
||||||
|
def remove_more_specific_subnets(input_subnets) -> list:
|
||||||
|
final_subnets = []
|
||||||
|
|
||||||
|
for subnet in sorted(input_subnets):
|
||||||
|
source = ip_network(subnet)
|
||||||
|
|
||||||
|
if not source in final_subnets:
|
||||||
|
subnet_found = False
|
||||||
|
|
||||||
|
for dest_subnet in final_subnets:
|
||||||
|
if source.subnet_of(dest_subnet):
|
||||||
|
subnet_found = True
|
||||||
|
|
||||||
|
if not subnet_found:
|
||||||
|
final_subnets.append(source)
|
||||||
|
|
||||||
|
out = []
|
||||||
|
for net in final_subnets:
|
||||||
|
out.append(str(net))
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def require_bundle(node, bundle, hint=''):
|
||||||
|
# It's considered bad style to use assert statements outside of tests.
|
||||||
|
# That's why this little helper function exists, so we have an easy
|
||||||
|
# way of defining bundle requirements in other bundles.
|
||||||
|
if not node.has_bundle(bundle):
|
||||||
|
raise BundleError(f'{node.name} requires bundle {bundle}, but wasn\'t found! {hint}')
|
|
@ -1,17 +1,32 @@
|
||||||
{
|
{
|
||||||
'hostname': '10.0.0.2',
|
'hostname': '10.0.0.2',
|
||||||
'bundles': [
|
|
||||||
'gitea',
|
|
||||||
'postgresql',
|
|
||||||
],
|
|
||||||
'groups': [
|
'groups': [
|
||||||
'debian-10',
|
'debian-10',
|
||||||
],
|
],
|
||||||
|
'bundles': [
|
||||||
|
'gitea',
|
||||||
|
'postgresql',
|
||||||
|
'wireguard',
|
||||||
|
],
|
||||||
'metadata': {
|
'metadata': {
|
||||||
|
'interfaces': {
|
||||||
|
'enp1s0f0': {
|
||||||
|
'ips': {
|
||||||
|
'10.0.0.2/24',
|
||||||
|
},
|
||||||
|
'gateway4': '10.0.0.1',
|
||||||
|
},
|
||||||
|
},
|
||||||
'gitea': {
|
'gitea': {
|
||||||
'version': '1.14.2',
|
'version': '1.14.2',
|
||||||
'sha256': '0d11d87ce60d5d98e22fc52f2c8c6ba2b54b14f9c26c767a46bf102c381ad128',
|
'sha256': '0d11d87ce60d5d98e22fc52f2c8c6ba2b54b14f9c26c767a46bf102c381ad128',
|
||||||
'domain': 'git.sublimity.de',
|
'domain': 'git.sublimity.de',
|
||||||
},
|
},
|
||||||
|
'wireguard': {
|
||||||
|
'my_ip': '172.19.136.1/22',
|
||||||
|
'peers': {
|
||||||
|
'htz.mails': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,20 @@
|
||||||
'webserver',
|
'webserver',
|
||||||
],
|
],
|
||||||
'bundles': [
|
'bundles': [
|
||||||
|
'wireguard',
|
||||||
'zfs',
|
'zfs',
|
||||||
],
|
],
|
||||||
'metadata': {
|
'metadata': {
|
||||||
|
'interfaces': {
|
||||||
|
'eth0': {
|
||||||
|
'ips': {
|
||||||
|
'162.55.188.157',
|
||||||
|
'2a01:4f8:1c1c:4121::/64',
|
||||||
|
},
|
||||||
|
'gateway4': '172.31.1.1',
|
||||||
|
'gateway6': 'fe80::1',
|
||||||
|
},
|
||||||
|
},
|
||||||
'nginx': {
|
'nginx': {
|
||||||
'vhosts': {
|
'vhosts': {
|
||||||
'nextcloud': {
|
'nextcloud': {
|
||||||
|
@ -38,5 +49,11 @@
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'wireguard': {
|
||||||
|
'my_ip': '172.19.136.2/22',
|
||||||
|
'peers': {
|
||||||
|
'home.server': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue