initial commit
This commit is contained in:
commit
35a1d52840
20 changed files with 238 additions and 0 deletions
24
.editorconfig
Normal file
24
.editorconfig
Normal file
|
@ -0,0 +1,24 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.yaml]
|
||||
indent_size = 2
|
||||
|
||||
[*.toml]
|
||||
indent_size = 2
|
||||
|
||||
# possibly sql dumps
|
||||
[*.sql]
|
||||
indent_size = unset
|
||||
|
||||
# bundlewrap encrypted files
|
||||
[*.vault]
|
||||
end_of_line = unset
|
||||
insert_final_newline = unset
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
.secrets.cfg*
|
||||
__pycache__
|
||||
*.swp
|
1
bundles/apt
Symbolic link
1
bundles/apt
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../bundlewrap/bundles/apt
|
1
bundles/basic
Symbolic link
1
bundles/basic
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../bundlewrap/bundles/basic
|
1
bundles/nftables
Symbolic link
1
bundles/nftables
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../bundlewrap/bundles/nftables
|
1
bundles/openssh
Symbolic link
1
bundles/openssh
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../bundlewrap/bundles/openssh
|
1
bundles/sudo
Symbolic link
1
bundles/sudo
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../bundlewrap/bundles/sudo
|
1
bundles/sysctl
Symbolic link
1
bundles/sysctl
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../bundlewrap/bundles/sysctl
|
1
bundles/systemd
Symbolic link
1
bundles/systemd
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../bundlewrap/bundles/systemd
|
1
bundles/systemd-networkd
Symbolic link
1
bundles/systemd-networkd
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../bundlewrap/bundles/systemd-networkd
|
1
bundles/users
Symbolic link
1
bundles/users
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../bundlewrap/bundles/users
|
7
groups.py
Normal file
7
groups.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from os.path import join
|
||||
from pathlib import Path
|
||||
|
||||
groups = {}
|
||||
for group in Path(join(repo_path, "groups")).rglob("*.py"):
|
||||
with open(group, 'r') as f:
|
||||
exec(f.read())
|
8
groups/all.py
Normal file
8
groups/all.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
groups['all'] = {
|
||||
'member_patterns': {
|
||||
r".*",
|
||||
},
|
||||
'subgroups': {
|
||||
'linux',
|
||||
},
|
||||
}
|
42
groups/os.py
Normal file
42
groups/os.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
groups['linux'] = {
|
||||
'subgroups': {
|
||||
'debian',
|
||||
},
|
||||
'bundles': {
|
||||
'basic',
|
||||
#'cron',
|
||||
'nftables',
|
||||
'openssh',
|
||||
#'postfix',
|
||||
#'sshmon',
|
||||
'sudo',
|
||||
'sysctl',
|
||||
'systemd',
|
||||
'systemd-networkd',
|
||||
#'telegraf',
|
||||
'users',
|
||||
},
|
||||
'metadata': {
|
||||
'apt': {
|
||||
'unattended-upgrades': {
|
||||
'mail': libs.defaults.hostmaster_email,
|
||||
},
|
||||
},
|
||||
},
|
||||
'pip_command': 'pip3',
|
||||
}
|
||||
|
||||
groups['debian'] = {
|
||||
'subgroups': {
|
||||
'debian-bullseye',
|
||||
},
|
||||
'bundles': {
|
||||
'apt',
|
||||
#'backup-client',
|
||||
},
|
||||
'os': 'debian',
|
||||
}
|
||||
|
||||
groups['debian-bullseye'] = {
|
||||
'os_version': (11,)
|
||||
}
|
9
libs/defaults.py
Normal file
9
libs/defaults.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
hostmaster_email = 'hostmaster@kunbox.net'
|
||||
|
||||
influxdb_bucket = 'encrypt$gAAAAABgg9iMnq0nKpODMiMN4NtUw231iqpbyDXV-O8epOAGDSL4jcf3CaSa2bLZzH2fJFaKWjW-dpVd384x6KqSQU19XpfsWA=='
|
||||
influxdb_org = 'encrypt$gAAAAABgg9hyjz4XtvG8NBw9uYxiumS3v7YKIrtc9tTTABg1f9R22gzn55q8ULP9X3wlsPMUQs_DH7CgGv9neYmvVAriRoyd8g=='
|
||||
influxdb_token = 'encrypt$gAAAAABgg9Ag632Xyuc6SWXaR1uH2tLOChmVKAoBIikhjntSSD2qJFL_eouVQGXCLH2HEuSbSdEXcTPn2qmhOiA9jmFdoDSbVbQUsp0EID1wLsWYG_Um2KOxZSF-tn9eDZlgShQYySjzO3nQRmdlJpVLUnGHsiwv_sHD2FstXGpfzTPZq5_egUqEc0K2X-aN2J6BTYc2fZAN'
|
||||
influxdb_url = 'https://influxdb.kunsmann.eu/'
|
||||
|
||||
security_email = f'mailto:{hostmaster_email}'
|
||||
security_lang = {'en', 'de'}
|
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}')
|
17
nodes.py
Normal file
17
nodes.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
from json import dumps as json_dumps
|
||||
from os.path import join
|
||||
from pathlib import Path
|
||||
|
||||
import bwpass
|
||||
from bundlewrap.metadata import atomic
|
||||
|
||||
for node in Path(join(repo_path, "nodes")).rglob("*.py"):
|
||||
with open(node, 'r') as f:
|
||||
exec(f.read())
|
||||
|
||||
for name, data in nodes.items():
|
||||
if 'hostname' not in data.keys():
|
||||
data['hostname'] = '.'.join(reversed(name.split('.'))) + '.kunbox.net'
|
||||
|
||||
if 'hostname' not in data['metadata'].keys():
|
||||
data['metadata']['hostname'] = '.'.join(reversed(name.split('.'))) + '.kunbox.net'
|
11
nodes/qzwi.toml
Normal file
11
nodes/qzwi.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
hostname = "2a00:f820:528::4"
|
||||
bundles = []
|
||||
groups = [
|
||||
"debian-bullseye",
|
||||
]
|
||||
|
||||
[metadata.interfaces.enp1s0]
|
||||
ips = [
|
||||
"2a00:f820:528::4",
|
||||
]
|
||||
gateway6 = "2a00:f820:528::1"
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
|
@ -0,0 +1 @@
|
|||
bundlewrap>=4.12.0
|
19
users.json
Normal file
19
users.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"autojenkins": {
|
||||
"ssh_pubkey": [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHZnYhsdtGUYJiFcvfqTLljGkInnFTOoDF/WZniLtPjH"
|
||||
]
|
||||
},
|
||||
"kunsi": {
|
||||
"ssh_pubkey": [
|
||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC+ja1z5VRQzaKCCePsUM14qMr9QR94qlWc7Je5Poki9UmC1t/TyxRVzcCBL1ZdIfBGx6QKtfkEbvhgb3nxVt3PvXjoJrc6wwGLmNrVsU6B88y35g7nzupQiPKYJwkNzJ9j6Dmkgj1F5Q+aY2SitDaX6vqICLJ4Al/ZFw2IQxVJfC7JXRJ9jRMG5o9gWoE3gWDYEAmw+HU2mNzyeuaD12qJw9DHUimAlgkOWzll3gh9WclsYnnXGrCCn5fyHFUCJl+XXAIy519z7YTpKih02rsIOw5dnaGClBZD/YQu2ZKVFZiwIVH7aBiqHOmtgRyWTQgjbh/fMpIN0ar2f/iZsWYUjd6et48TOmXZYIPCQ5FivXNvxt9oo1XZfq76UHBwlmypLJIWROMbz375n2M6hr3hECuxuPjKEUXAv05KiC1aJ4xc6pFoVhqwAR99hvHw5U4o7/ko2NVjNpTu6Jr5DT5VaQLIdDDjC/93kUjMpdD/8P72bEn7454+WexU6OE6uvNiHj1fetrptr2UAuzVfnCoaV8pBqY7X95gk+lnSENdpr8ltJYMg8s0Z7Pzz0OxsZtzzDY5VmWfC9TCdJkN5lT8IbnaixsYlWdjQl1lMmZGElmelfU3K7YQLAbZiHmHKe4hTl9ZoCcWdTQ3d4y2t1DBos+N2HZNdtFCyOS8esDdMw== cardno:000609506971"
|
||||
],
|
||||
"is_admin": true
|
||||
},
|
||||
"rullmann": {
|
||||
"ssh_pubkey": [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP/0k9XHd05jVY2/obSXFSFbahX8uRnKon5ki5uD/W6Y Rico Ullmann // private // ed25519"
|
||||
],
|
||||
"is_admin": true
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue