aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ansible/ansible.cfg5
-rw-r--r--ansible/connection_plugins/lxc_ssh.py1259
-rw-r--r--ansible/group_vars/all/bird.yml3
-rw-r--r--ansible/group_vars/all/ipam.yml37
-rw-r--r--ansible/host_vars/hash/roa-server.vault.yml19
-rw-r--r--ansible/inventory12
-rw-r--r--ansible/plays/roa-server.yml25
-rw-r--r--ansible/plays/templates/roa-server/docker-compose.yml14
-rw-r--r--ansible/prometheus/deploy-config.yml19
-rw-r--r--ansible/prometheus/files/conflatorio/prometheus.yml25
-rw-r--r--ansible/wg0/files/coregonus/etc/wireguard/public-wg0.key1
-rw-r--r--ansible/wg0/group_vars/all/wireguard_wg0.yml7
-rw-r--r--ansible/wg0/wireguard-wg0-terraform.yml3
-rw-r--r--bin/requirements.txt2
-rw-r--r--sops.yml8
-rw-r--r--terraform/conflatorio-docker/main.tf8
-rw-r--r--terraform/conflatorio-docker/network.tf18
-rw-r--r--terraform/conflatorio-docker/traefik.tf8
-rw-r--r--terraform/conflatorio-prometheus/.terraform.lock.hcl104
-rw-r--r--terraform/conflatorio-prometheus/backend.tf12
-rw-r--r--terraform/conflatorio-prometheus/main.tf34
-rw-r--r--terraform/conflatorio-prometheus/prometheus.tf66
-rw-r--r--terraform/conflatorio-prometheus/terragrunt.hcl3
-rw-r--r--terraform/dns/main.tf2
-rw-r--r--terraform/dns/trygvis.tf76
-rw-r--r--terraform/dns/vpn-cname.tf17
-rw-r--r--terraform/dns/vpn.tf36
-rw-r--r--terraform/grafana/grafana.tf4
-rw-r--r--terraform/grafana/main.tf4
-rw-r--r--terraform/terragrunt.hcl2
-rw-r--r--terraform/unifi-controller/main.tf4
-rw-r--r--terraform/unifi-controller/mongo.tf5
-rw-r--r--terraform/unifi-controller/unifi.tf3
-rw-r--r--tnet/README.md8
-rw-r--r--tnet/files/akili/bird-tnet-pre.conf21
-rw-r--r--tnet/files/akili/bird-tnet.conf22
-rw-r--r--tnet/files/astyanax/bird-tnet-pre.conf21
-rw-r--r--tnet/files/astyanax/bird-tnet.conf22
-rw-r--r--tnet/files/conflatorio/bird-tnet-pre.conf20
-rw-r--r--tnet/files/conflatorio/bird-tnet.conf48
-rw-r--r--tnet/files/coregonus/bird-tnet-pre.conf20
-rw-r--r--tnet/files/coregonus/bird-tnet.conf43
-rw-r--r--tnet/files/hash/bird-tnet-pre.conf21
-rw-r--r--tnet/files/hash/bird-tnet.conf28
-rw-r--r--tnet/files/knot/bird-tnet-pre.conf21
-rw-r--r--tnet/files/knot/bird-tnet.conf79
-rw-r--r--tnet/files/lhn2pi/bird-tnet-pre.conf21
-rw-r--r--tnet/files/lhn2pi/bird-tnet.conf32
-rw-r--r--tnet/files/node1/bird-tnet-pre.conf21
-rw-r--r--tnet/files/node1/bird-tnet.conf22
-rw-r--r--tnet/files/node2/bird-tnet-pre.conf21
-rw-r--r--tnet/files/node2/bird-tnet.conf22
-rw-r--r--tnet/host_vars/conflatorio/bird.yml5
-rw-r--r--tnet/host_vars/conflatorio/wg.yml7
-rw-r--r--tnet/host_vars/coregonus/bird.yml4
-rw-r--r--tnet/host_vars/coregonus/wg.yml5
-rw-r--r--tnet/host_vars/hash/bird.yml3
-rw-r--r--tnet/host_vars/hash/wg.yml4
-rw-r--r--tnet/host_vars/knot/bird.yml16
-rw-r--r--tnet/host_vars/knot/wg.yml14
-rw-r--r--tnet/host_vars/kv24ix/wg.yml1
-rw-r--r--tnet/host_vars/lhn2pi/bird.yml6
-rw-r--r--tnet/keys/wg-conflatorio-hash.pub1
-rw-r--r--tnet/keys/wg-conflatorio-hash.sops.key28
-rw-r--r--tnet/keys/wg-conflatorio-knot.pub1
-rw-r--r--tnet/keys/wg-conflatorio-knot.sops.key28
-rw-r--r--tnet/keys/wg-coregonus-knot.pub1
-rw-r--r--tnet/keys/wg-coregonus-knot.sops.key28
-rw-r--r--tnet/keys/wg-hash-conflatorio.pub1
-rw-r--r--tnet/keys/wg-hash-conflatorio.sops.key28
-rw-r--r--tnet/keys/wg-knot-conflatorio.pub1
-rw-r--r--tnet/keys/wg-knot-conflatorio.sops.key28
-rw-r--r--tnet/keys/wg-knot-coregonus.pub1
-rw-r--r--tnet/keys/wg-knot-coregonus.sops.key28
-rw-r--r--tnet/keys/wg-knot-rtdbts_l1.pub1
-rw-r--r--tnet/keys/wg-knot-rtdbts_l1.sops.key28
-rw-r--r--tnet/keys/wg-routedbits_lon1-knot.pub1
-rw-r--r--tnet/keys/wg-rtdbts_l1-knot.pub1
-rw-r--r--tnet/templates/bird-tnet-pre.conf.j221
-rw-r--r--tnet/templates/bird-tnet.conf.j263
-rw-r--r--tnet/wg-keys-genkey.yml9
-rw-r--r--tnet/wg-links-link.yml17
82 files changed, 1319 insertions, 1419 deletions
diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg
index 6da8010..6f2b86b 100644
--- a/ansible/ansible.cfg
+++ b/ansible/ansible.cfg
@@ -1,6 +1,5 @@
[defaults]
become_method = sudo
-connection_plugins = ./connection_plugins
inventory = ./inventory
#,./inventory-terraform
nocows = True
@@ -8,3 +7,7 @@ stdout_callback = debug
vault_password_file = ./.vault-password
roles_path = roles:thirdparty
retry_files_enabled = False
+
+[ssh_connection]
+pipelining = True
+ssh_args = -o ControlMaster=auto -o ControlPersist=1200
diff --git a/ansible/connection_plugins/lxc_ssh.py b/ansible/connection_plugins/lxc_ssh.py
deleted file mode 100644
index 2bb5352..0000000
--- a/ansible/connection_plugins/lxc_ssh.py
+++ /dev/null
@@ -1,1259 +0,0 @@
-# Copyright 2016 Pierre Chifflier <pollux@wzdftpd.net>
-#
-# SSH + lxc-attach connection module for Ansible 2.0
-#
-# Adapted from ansible/plugins/connection/ssh.py
-# Forked from https://github.com/chifflier/ansible-lxc-ssh
-# Hosted on https://github.com/andreasscherbaum/ansible-lxc-ssh
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-import errno
-import fcntl
-import hashlib
-import os
-import pipes
-import pty
-import shlex
-import subprocess
-import sys
-from distutils.version import LooseVersion
-
-from ansible.release import __version__ as ansible_version
-if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- from functools import wraps
-from ansible import constants as C
-if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- from ansible.compat.six import text_type, binary_type
- from ansible.errors import AnsibleConnectionFailure, AnsibleError
- from ansible.plugins.connection import ConnectionBase
-if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
- from ansible.errors import AnsibleOptionsError
- from ansible.compat import selectors
- from ansible.module_utils.six import PY3, text_type, binary_type
- if LooseVersion(ansible_version) < LooseVersion('2.4.0.0'):
- from ansible.compat.six.moves import shlex_quote
- else:
- from ansible.module_utils.six.moves import shlex_quote
- from ansible.module_utils._text import to_bytes, to_native, to_text
- if LooseVersion(ansible_version) >= LooseVersion('2.4.0.0'):
- from ansible.module_utils.parsing.convert_bool import BOOLEANS, boolean
- from ansible.plugins.connection import ConnectionBase, BUFSIZE
-from ansible.utils.path import unfrackpath, makedirs_safe
-
-if LooseVersion(ansible_version) >= LooseVersion('2.2.0.0'):
- from ansible.module_utils._text import to_bytes, to_text as to_unicode, to_native as to_str
-else:
- from ansible.utils.unicode import to_bytes, to_unicode, to_str
-
-try:
- from __main__ import display
-except ImportError:
- from ansible.utils.display import Display
- display = Display()
-
-if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- import select
-
-
-# only used from Ansible version 2.3 on forward
-class AnsibleControlPersistBrokenPipeError(AnsibleError):
- ''' ControlPersist broken pipe '''
- pass
-
-
-def _ssh_retry(func):
- """
- Decorator to retry ssh/scp/sftp in the case of a connection failure
-
- Will retry if:
- * an exception is caught
- * ssh returns 255
- Will not retry if
- * remaining_tries is <2
- * retries limit reached
- """
- @wraps(func)
- def wrapped(self, *args, **kwargs):
- remaining_tries = int(C.ANSIBLE_SSH_RETRIES) + 1
- cmd_summary = "%s..." % args[0]
- for attempt in range(remaining_tries):
- cmd = args[0]
- if attempt != 0 and self._play_context.password and isinstance(cmd, list):
- # If this is a retry, the fd/pipe for sshpass is closed, and we need a new one
- self.sshpass_pipe = os.pipe()
- cmd[1] = b'-d' + to_bytes(self.sshpass_pipe[0], nonstring='simplerepr', errors='surrogate_or_strict')
-
- try:
- try:
- return_tuple = func(self, *args, **kwargs)
- display.vvv(return_tuple, host=self.host)
- # 0 = success
- # 1-254 = remote command return code
- # 255 = failure from the ssh command itself
- except (AnsibleControlPersistBrokenPipeError) as e:
- # Retry one more time because of the ControlPersist broken pipe (see #16731)
- display.vvv(u"RETRYING BECAUSE OF CONTROLPERSIST BROKEN PIPE")
- return_tuple = func(self, *args, **kwargs)
-
- if return_tuple[0] != 255:
- break
- else:
- raise AnsibleConnectionFailure("Failed to connect to the host via ssh: %s" % to_native(return_tuple[2]))
- except (AnsibleConnectionFailure, Exception) as e:
- if attempt == remaining_tries - 1:
- raise
- else:
- pause = 2 ** attempt - 1
- if pause > 30:
- pause = 30
-
- if isinstance(e, AnsibleConnectionFailure):
- msg = "ssh_retry: attempt: %d, ssh return code is 255. cmd (%s), pausing for %d seconds" % (attempt, cmd_summary, pause)
- else:
- msg = "ssh_retry: attempt: %d, caught exception(%s) from cmd (%s), pausing for %d seconds" % (attempt, e, cmd_summary, pause)
-
- display.vv(msg, host=self.host)
-
- time.sleep(pause)
- continue
-
- return return_tuple
- return wrapped
-
-
-class Connection(ConnectionBase):
- ''' ssh+lxc_attach connection '''
- transport = 'lxc_ssh'
-
- def __init__(self, play_context, new_stdin, *args, **kwargs):
- #print args
- #print kwargs
- super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
- self.host = self._play_context.remote_addr
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- self.port = self._play_context.port
- self.user = self._play_context.remote_user
- self.control_path = C.ANSIBLE_SSH_CONTROL_PATH
- self.control_path_dir = C.ANSIBLE_SSH_CONTROL_PATH_DIR
- self.lxc_version = None
-
- # LXC v1 uses 'lxc-info', 'lxc-attach' and so on
- # LXC v2 uses just 'lxc'
- (returncode2, stdout2, stderr2) = self._exec_command("which lxc", None, False)
- (returncode1, stdout1, stderr1) = self._exec_command("which lxc-info", None, False)
- if (returncode2 == 0):
- self.lxc_version = 2
- display.vvv('LXC v2')
- elif (returncode1 == 0):
- self.lxc_version = 1
- display.vvv('LXC v1')
- else:
- raise AnsibleConnectionFailure('Cannot identify LXC version')
- sys.exit(1)
-
-
- # The connection is created by running ssh/scp/sftp from the exec_command,
- # put_file, and fetch_file methods, so we don't need to do any connection
- # management here.
- def _connect(self):
- ''' connect to the lxc; nothing to do here '''
- display.vvv('XXX connect')
- super(Connection, self)._connect()
- #self.container_name = self.ssh._play_context.remote_addr
- self.container_name = self._play_context.ssh_extra_args # XXX
- #self.container = None
-
-
- # only used from Ansible version 2.3 on forward
- @staticmethod
- def _create_control_path(host, port, user, connection=None):
- '''Make a hash for the controlpath based on con attributes'''
- pstring = '%s-%s-%s' % (host, port, user)
- if connection:
- pstring += '-%s' % connection
- m = hashlib.sha1()
- m.update(to_bytes(pstring))
- digest = m.hexdigest()
- cpath = '%(directory)s/' + digest[:10]
- return cpath
-
-
- @staticmethod
- def _persistence_controls(b_command):
- '''
- Takes a command array and scans it for ControlPersist and ControlPath
- settings and returns two booleans indicating whether either was found.
- This could be smarter, e.g. returning false if ControlPersist is 'no',
- but for now we do it simple way.
- '''
-
- controlpersist = False
- controlpath = False
-
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- for arg in b_command:
- if 'controlpersist' in arg.lower():
- controlpersist = True
- elif 'controlpath' in arg.lower():
- controlpath = True
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- for b_arg in (a.lower() for a in b_command):
- if b'controlpersist' in b_arg:
- controlpersist = True
- elif b'controlpath' in b_arg:
- controlpath = True
-
- return controlpersist, controlpath
-
-
- @staticmethod
- def _split_args(argstring):
- """
- Takes a string like '-o Foo=1 -o Bar="foo bar"' and returns a
- list ['-o', 'Foo=1', '-o', 'Bar=foo bar'] that can be added to
- the argument list. The list will not contain any empty elements.
- """
- return [to_unicode(x.strip()) for x in shlex.split(to_bytes(argstring)) if x.strip()]
-
-
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- def _add_args(self, explanation, args):
- """
- Adds the given args to self._command and displays a caller-supplied
- explanation of why they were added.
- """
- self._command += args
- display.vvvvv('SSH: ' + explanation + ': (%s)' % ')('.join(args), host=self._play_context.remote_addr)
-
-
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- def _add_args(self, b_command, b_args, explanation):
- """
- Adds arguments to the ssh command and displays a caller-supplied explanation of why.
- :arg b_command: A list containing the command to add the new arguments to.
- This list will be modified by this method.
- :arg b_args: An iterable of new arguments to add. This iterable is used
- more than once so it must be persistent (ie: a list is okay but a
- StringIO would not)
- :arg explanation: A text string containing explaining why the arguments
- were added. It will be displayed with a high enough verbosity.
- .. note:: This function does its work via side-effect. The b_command list has the new arguments appended.
- """
- display.vvvvv(u'SSH: %s: (%s)' % (explanation, ')('.join(to_text(a) for a in b_args)), host=self._play_context.remote_addr)
- b_command += b_args
-
-
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- def _build_command(self, binary, *other_args):
- self._command = []
- self._command += [binary]
- self._command += ['-C']
- if self._play_context.verbosity > 3:
- self._command += ['-vvv']
- elif binary == 'ssh':
- # Older versions of ssh (e.g. in RHEL 6) don't accept sftp -q.
- self._command += ['-q']
- # Next, we add [ssh_connection]ssh_args from ansible.cfg.
- if self._play_context.ssh_args:
- args = self._split_args(self._play_context.ssh_args)
- self._add_args("ansible.cfg set ssh_args", args)
- # Now we add various arguments controlled by configuration file settings
- # (e.g. host_key_checking) or inventory variables (ansible_ssh_port) or
- # a combination thereof.
- if not C.HOST_KEY_CHECKING:
- self._add_args(
- "ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled",
- ("-o", "StrictHostKeyChecking=no")
- )
- if self._play_context.port is not None:
- self._add_args(
- "ANSIBLE_REMOTE_PORT/remote_port/ansible_port set",
- ("-o", "Port={0}".format(self._play_context.port))
- )
- key = self._play_context.private_key_file
- if key:
- self._add_args(
- "ANSIBLE_PRIVATE_KEY_FILE/private_key_file/ansible_ssh_private_key_file set",
- ("-o", "IdentityFile=\"{0}\"".format(os.path.expanduser(key)))
- )
- if not self._play_context.password:
- self._add_args(
- "ansible_password/ansible_ssh_pass not set", (
- "-o", "KbdInteractiveAuthentication=no",
- "-o", "PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey",
- "-o", "PasswordAuthentication=no"
- )
- )
- user = self._play_context.remote_user
- if user:
- self._add_args(
- "ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set",
- ("-o", "User={0}".format(to_bytes(self._play_context.remote_user)))
- )
- self._add_args(
- "ANSIBLE_TIMEOUT/timeout set",
- ("-o", "ConnectTimeout={0}".format(self._play_context.timeout))
- )
- # Check if ControlPersist is enabled and add a ControlPath if one hasn't
- # already been set.
- controlpersist, controlpath = self._persistence_controls(self._command)
- if controlpersist:
- self._persistent = True
- if not controlpath:
- cpdir = unfrackpath('$HOME/.ansible/cp')
- display.vv(str(C.ANSIBLE_SSH_CONTROL_PATH))
- # The directory must exist and be writable.
- makedirs_safe(cpdir, 0o700)
- if not os.access(cpdir, os.W_OK):
- raise AnsibleError("Cannot write to ControlPath %s" % cpdir)
- args = ("-o", "ControlPath={0}".format(
- to_bytes(C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=cpdir)))
- )
- self._add_args("found only ControlPersist; added ControlPath", args)
- ## Finally, we add any caller-supplied extras.
- if other_args:
- self._command += other_args
- return self._command
-
-
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- def _build_command(self, binary, *other_args):
- b_command = []
- if binary == 'ssh':
- b_command += [to_bytes(self._play_context.ssh_executable, errors='surrogate_or_strict')]
- else:
- b_command += [to_bytes(binary, errors='surrogate_or_strict')]
- if self._play_context.verbosity > 3:
- b_command.append(b'-vvv')
- # Next, we add [ssh_connection]ssh_args from ansible.cfg.
- #
- if self._play_context.ssh_args:
- b_args = [to_bytes(a, errors='surrogate_or_strict') for a in
- self._split_args(self._play_context.ssh_args)]
- self._add_args(b_command, b_args, u"ansible.cfg set ssh_args")
-
- # Now we add various arguments controlled by configuration file settings
- # (e.g. host_key_checking) or inventory variables (ansible_ssh_port) or
- # a combination thereof.
- if not C.HOST_KEY_CHECKING:
- b_args = (b"-o", b"StrictHostKeyChecking=no")
- self._add_args(b_command, b_args, u"ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled")
- if self._play_context.port is not None:
- b_args = (b"-o", b"Port=" + to_bytes(self._play_context.port, nonstring='simplerepr', errors='surrogate_or_strict'))
- self._add_args(b_command, b_args, u"ANSIBLE_REMOTE_PORT/remote_port/ansible_port set")
- key = self._play_context.private_key_file
- if key:
- b_args = (b"-o", b'IdentityFile="' + to_bytes(os.path.expanduser(key), errors='surrogate_or_strict') + b'"')
- self._add_args(b_command, b_args, u"ANSIBLE_PRIVATE_KEY_FILE/private_key_file/ansible_ssh_private_key_file set")
- if not self._play_context.password:
- self._add_args(
- b_command, (
- b"-o", b"KbdInteractiveAuthentication=no",
- b"-o", b"PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey",
- b"-o", b"PasswordAuthentication=no"
- ),
- u"ansible_password/ansible_ssh_pass not set"
- )
- user = self._play_context.remote_user
- if user:
- self._add_args(
- b_command,
- (b"-o", b"User=" + to_bytes(self._play_context.remote_user, errors='surrogate_or_strict')),
- u"ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set"
- )
- self._add_args(
- b_command,
- (b"-o", b"ConnectTimeout=" + to_bytes(self._play_context.timeout, errors='surrogate_or_strict', nonstring='simplerepr')),
- u"ANSIBLE_TIMEOUT/timeout set"
- )
- # Check if ControlPersist is enabled and add a ControlPath if one hasn't
- # already been set.
- controlpersist, controlpath = self._persistence_controls(b_command)
- if controlpersist:
- self._persistent = True
- if not controlpath:
- cpdir = unfrackpath(self.control_path_dir)
- b_cpdir = to_bytes(cpdir, errors='surrogate_or_strict')
- # The directory must exist and be writable.
- makedirs_safe(b_cpdir, 0o700)
- if not os.access(b_cpdir, os.W_OK):
- raise AnsibleError("Cannot write to ControlPath %s" % to_native(cpdir))
-
- if not self.control_path:
- self.control_path = self._create_control_path(
- self.host,
- self.port,
- self.user
- )
- b_args = (b"-o", b"ControlPath=" + to_bytes(self.control_path % dict(directory=cpdir), errors='surrogate_or_strict'))
- self._add_args(b_command, b_args, u"found only ControlPersist; added ControlPath")
-
- # Finally, we add any caller-supplied extras.
- if other_args:
- b_command += [to_bytes(a) for a in other_args]
-
- return b_command
-
-
- def _send_initial_data(self, fh, in_data):
- '''
- Writes initial data to the stdin filehandle of the subprocess and closes
- it. (The handle must be closed; otherwise, for example, "sftp -b -" will
- just hang forever waiting for more commands.)
- '''
-
- display.debug('Sending initial data')
-
- try:
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- fh.write(in_data)
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- fh.write(to_bytes(in_data))
- fh.close()
- except (OSError, IOError):
- raise AnsibleConnectionFailure('SSH Error: data could not be sent to remote host "%s". Make sure this host can be reached over ssh' % self.host)
-
- display.debug('Sent initial data (%d bytes)' % len(in_data))
-
-
- # Used by _run() to kill processes on failures
- @staticmethod
- def _terminate_process(p):
- """ Terminate a process, ignoring errors """
- try:
- p.terminate()
- except (OSError, IOError):
- pass
-
-
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- # This is separate from _run() because we need to do the same thing for stdout
- # and stderr.
- def _examine_output(self, source, state, chunk, sudoable):
- '''
- Takes a string, extracts complete lines from it, tests to see if they
- are a prompt, error message, etc., and sets appropriate flags in self.
- Prompt and success lines are removed.
-
- Returns the processed (i.e. possibly-edited) output and the unprocessed
- remainder (to be processed with the next chunk) as strings.
- '''
-
- output = []
- for l in chunk.splitlines(True):
- suppress_output = False
-
- #display.debug("Examining line (source=%s, state=%s): '%s'" % (source, state, l.rstrip('\r\n')))
- if self._play_context.prompt and self.check_password_prompt(l):
- display.debug("become_prompt: (source=%s, state=%s): '%s'" % (source, state, l.rstrip('\r\n')))
- self._flags['become_prompt'] = True
- suppress_output = True
- elif self._play_context.success_key and self.check_become_success(l):
- display.debug("become_success: (source=%s, state=%s): '%s'" % (source, state, l.rstrip('\r\n')))
- self._flags['become_success'] = True
- suppress_output = True
- elif sudoable and self.check_incorrect_password(l):
- display.debug("become_error: (source=%s, state=%s): '%s'" % (source, state, l.rstrip('\r\n')))
- self._flags['become_error'] = True
- elif sudoable and self.check_missing_password(l):
- display.debug("become_nopasswd_error: (source=%s, state=%s): '%s'" % (source, state, l.rstrip('\r\n')))
- self._flags['become_nopasswd_error'] = True
-
- if not suppress_output:
- output.append(l)
-
- # The chunk we read was most likely a series of complete lines, but just
- # in case the last line was incomplete (and not a prompt, which we would
- # have removed from the output), we retain it to be processed with the
- # next chunk.
-
- remainder = ''
- if output and not output[-1].endswith('\n'):
- remainder = output[-1]
- output = output[:-1]
-
- return ''.join(output), remainder
-
-
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- # This is separate from _run() because we need to do the same thing for stdout
- # and stderr.
- def _examine_output(self, source, state, b_chunk, sudoable):
- '''
- Takes a string, extracts complete lines from it, tests to see if they
- are a prompt, error message, etc., and sets appropriate flags in self.
- Prompt and success lines are removed.
- Returns the processed (i.e. possibly-edited) output and the unprocessed
- remainder (to be processed with the next chunk) as strings.
- '''
-
- output = []
- for b_line in b_chunk.splitlines(True):
- display_line = to_text(b_line).rstrip('\r\n')
- suppress_output = False
-
- # display.debug("Examining line (source=%s, state=%s): '%s'" % (source, state, display_line))
- if self._play_context.prompt and self.check_password_prompt(b_line):
- display.debug("become_prompt: (source=%s, state=%s): '%s'" % (source, state, display_line))
- self._flags['become_prompt'] = True
- suppress_output = True
- elif self._play_context.success_key and self.check_become_success(b_line):
- display.debug("become_success: (source=%s, state=%s): '%s'" % (source, state, display_line))
- self._flags['become_success'] = True
- suppress_output = True
- elif sudoable and self.check_incorrect_password(b_line):
- display.debug("become_error: (source=%s, state=%s): '%s'" % (source, state, display_line))
- self._flags['become_error'] = True
- elif sudoable and self.check_missing_password(b_line):
- display.debug("become_nopasswd_error: (source=%s, state=%s): '%s'" % (source, state, display_line))
- self._flags['become_nopasswd_error'] = True
-
- if not suppress_output:
- output.append(b_line)
-
- # The chunk we read was most likely a series of complete lines, but just
- # in case the last line was incomplete (and not a prompt, which we would
- # have removed from the output), we retain it to be processed with the
- # next chunk.
-
- remainder = b''
- if output and not output[-1].endswith(b'\n'):
- remainder = output[-1]
- output = output[:-1]
-
- return b''.join(output), remainder
-
-
- # only used from Ansible version 2.3 on forward
- def _bare_run(self, cmd, in_data, sudoable=True, checkrc=True):
- '''
- Starts the command and communicates with it until it ends.
- '''
-
- display_cmd = list(map(shlex_quote, map(to_text, cmd)))
- display.vvv(u'SSH: EXEC {0}'.format(u' '.join(display_cmd)), host=self.host)
-
- # Start the given command. If we don't need to pipeline data, we can try
- # to use a pseudo-tty (ssh will have been invoked with -tt). If we are
- # pipelining data, or can't create a pty, we fall back to using plain
- # old pipes.
-
- p = None
-
- if isinstance(cmd, (text_type, binary_type)):
- cmd = to_bytes(cmd)
- else:
- cmd = map(to_bytes, cmd)
-
- if not in_data:
- try:
- # Make sure stdin is a proper pty to avoid tcgetattr errors
- master, slave = pty.openpty()
- if PY3 and self._play_context.password:
- p = subprocess.Popen(cmd, stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE, pass_fds=self.sshpass_pipe)
- else:
- p = subprocess.Popen(cmd, stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdin = os.fdopen(master, 'wb', 0)
- os.close(slave)
- except (OSError, IOError):
- p = None
-
- if not p:
- if PY3 and self._play_context.password:
- p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, pass_fds=self.sshpass_pipe)
- else:
- p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdin = p.stdin
-
- # If we are using SSH password authentication, write the password into
- # the pipe we opened in _build_command.
-
- if self._play_context.password:
- os.close(self.sshpass_pipe[0])
- try:
- os.write(self.sshpass_pipe[1], to_bytes(self._play_context.password) + b'\n')
- except OSError as e:
- # Ignore broken pipe errors if the sshpass process has exited.
- if e.errno != errno.EPIPE or p.poll() is None:
- raise
- os.close(self.sshpass_pipe[1])
-
- #
- # SSH state machine
- #
-
- # Now we read and accumulate output from the running process until it
- # exits. Depending on the circumstances, we may also need to write an
- # escalation password and/or pipelined input to the process.
-
- states = [
- 'awaiting_prompt', 'awaiting_escalation', 'ready_to_send', 'awaiting_exit'
- ]
-
- # Are we requesting privilege escalation? Right now, we may be invoked
- # to execute sftp/scp with sudoable=True, but we can request escalation
- # only when using ssh. Otherwise we can send initial data straightaway.
-
- state = states.index('ready_to_send')
- if b'ssh' in cmd:
- if self._play_context.prompt:
- # We're requesting escalation with a password, so we have to
- # wait for a password prompt.
- state = states.index('awaiting_prompt')
- display.debug(u'Initial state: %s: %s' % (states[state], self._play_context.prompt))
- elif self._play_context.become and self._play_context.success_key:
- # We're requesting escalation without a password, so we have to
- # detect success/failure before sending any initial data.
- state = states.index('awaiting_escalation')
- display.debug(u'Initial state: %s: %s' % (states[state], self._play_context.success_key))
-
- # We store accumulated stdout and stderr output from the process here,
- # but strip any privilege escalation prompt/confirmation lines first.
- # Output is accumulated into tmp_*, complete lines are extracted into
- # an array, then checked and removed or copied to stdout or stderr. We
- # set any flags based on examining the output in self._flags.
-
- b_stdout = b_stderr = b''
- b_tmp_stdout = b_tmp_stderr = b''
-
- self._flags = dict(
- become_prompt=False, become_success=False,
- become_error=False, become_nopasswd_error=False
- )
-
- # select timeout should be longer than the connect timeout, otherwise
- # they will race each other when we can't connect, and the connect
- # timeout usually fails
- timeout = 2 + self._play_context.timeout
- for fd in (p.stdout, p.stderr):
- fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
-
- # TODO: bcoca would like to use SelectSelector() when open
- # filehandles is low, then switch to more efficient ones when higher.
- # select is faster when filehandles is low.
- selector = selectors.DefaultSelector()
- selector.register(p.stdout, selectors.EVENT_READ)
- selector.register(p.stderr, selectors.EVENT_READ)
-
- # If we can send initial data without waiting for anything, we do so
- # before we start polling
- if states[state] == 'ready_to_send' and in_data:
- self._send_initial_data(stdin, in_data)
- state += 1
-
- try:
- while True:
- poll = p.poll()
- events = selector.select(timeout)
-
- # We pay attention to timeouts only while negotiating a prompt.
-
- if not events:
- # We timed out
- if state <= states.index('awaiting_escalation'):
- # If the process has already exited, then it's not really a
- # timeout; we'll let the normal error handling deal with it.
- if poll is not None:
- break
- self._terminate_process(p)
- raise AnsibleError('Timeout (%ds) waiting for privilege escalation prompt: %s' % (timeout, to_native(b_stdout)))
-
- # Read whatever output is available on stdout and stderr, and stop
- # listening to the pipe if it's been closed.
-
- for key, event in events:
- if key.fileobj == p.stdout:
- b_chunk = p.stdout.read()
- if b_chunk == b'':
- # stdout has been closed, stop watching it
- selector.unregister(p.stdout)
- # When ssh has ControlMaster (+ControlPath/Persist) enabled, the
- # first connection goes into the background and we never see EOF
- # on stderr. If we see EOF on stdout, lower the select timeout
- # to reduce the time wasted selecting on stderr if we observe
- # that the process has not yet existed after this EOF. Otherwise
- # we may spend a long timeout period waiting for an EOF that is
- # not going to arrive until the persisted connection closes.
- timeout = 1
- b_tmp_stdout += b_chunk
- display.debug("stdout chunk (state=%s):\n>>>%s<<<\n" % (state, to_text(b_chunk)))
- elif key.fileobj == p.stderr:
- b_chunk = p.stderr.read()
- if b_chunk == b'':
- # stderr has been closed, stop watching it
- selector.unregister(p.stderr)
- b_tmp_stderr += b_chunk
- display.debug("stderr chunk (state=%s):\n>>>%s<<<\n" % (state, to_text(b_chunk)))
-
- # We examine the output line-by-line until we have negotiated any
- # privilege escalation prompt and subsequent success/error message.
- # Afterwards, we can accumulate output without looking at it.
-
- if state < states.index('ready_to_send'):
- if b_tmp_stdout:
- b_output, b_unprocessed = self._examine_output('stdout', states[state], b_tmp_stdout, sudoable)
- b_stdout += b_output
- b_tmp_stdout = b_unprocessed
-
- if b_tmp_stderr:
- b_output, b_unprocessed = self._examine_output('stderr', states[state], b_tmp_stderr, sudoable)
- b_stderr += b_output
- b_tmp_stderr = b_unprocessed
- else:
- b_stdout += b_tmp_stdout
- b_stderr += b_tmp_stderr
- b_tmp_stdout = b_tmp_stderr = b''
-
- # If we see a privilege escalation prompt, we send the password.
- # (If we're expecting a prompt but the escalation succeeds, we
- # didn't need the password and can carry on regardless.)
-
- if states[state] == 'awaiting_prompt':
- if self._flags['become_prompt']:
- display.debug('Sending become_pass in response to prompt')
- stdin.write(to_bytes(self._play_context.become_pass) + b'\n')
- self._flags['become_prompt'] = False
- state += 1
- elif self._flags['become_success']:
- state += 1
-
- # We've requested escalation (with or without a password), now we
- # wait for an error message or a successful escalation.
-
- if states[state] == 'awaiting_escalation':
- if self._flags['become_success']:
- display.debug('Escalation succeeded')
- self._flags['become_success'] = False
- state += 1
- elif self._flags['become_error']:
- display.debug('Escalation failed')
- self._terminate_process(p)
- self._flags['become_error'] = False
- raise AnsibleError('Incorrect %s password' % self._play_context.become_method)
- elif self._flags['become_nopasswd_error']:
- display.debug('Escalation requires password')
- self._terminate_process(p)
- self._flags['become_nopasswd_error'] = False
- raise AnsibleError('Missing %s password' % self._play_context.become_method)
- elif self._flags['become_prompt']:
- # This shouldn't happen, because we should see the "Sorry,
- # try again" message first.
- display.debug('Escalation prompt repeated')
- self._terminate_process(p)
- self._flags['become_prompt'] = False
- raise AnsibleError('Incorrect %s password' % self._play_context.become_method)
-
- # Once we're sure that the privilege escalation prompt, if any, has
- # been dealt with, we can send any initial data and start waiting
- # for output.
-
- if states[state] == 'ready_to_send':
- if in_data:
- self._send_initial_data(stdin, in_data)
- state += 1
-
- # Now we're awaiting_exit: has the child process exited? If it has,
- # and we've read all available output from it, we're done.
-
- if poll is not None:
- if not selector.get_map() or not events:
- break
- # We should not see further writes to the stdout/stderr file
- # descriptors after the process has closed, set the select
- # timeout to gather any last writes we may have missed.
- timeout = 0
- continue
-
- # If the process has not yet exited, but we've already read EOF from
- # its stdout and stderr (and thus no longer watching any file
- # descriptors), we can just wait for it to exit.
-
- elif not selector.get_map():
- p.wait()
- break
-
- # Otherwise there may still be outstanding data to read.
- finally:
- selector.close()
- # close stdin after process is terminated and stdout/stderr are read
- # completely (see also issue #848)
- stdin.close()
-
- if C.HOST_KEY_CHECKING:
- if cmd[0] == b"sshpass" and p.returncode == 6:
- raise AnsibleError('Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support '
- 'this. Please add this host\'s fingerprint to your known_hosts file to manage this host.')
-
- controlpersisterror = b'Bad configuration option: ControlPersist' in b_stderr or b'unknown configuration option: ControlPersist' in b_stderr
- if p.returncode != 0 and controlpersisterror:
- raise AnsibleError('using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" '
- '(or ssh_args in [ssh_connection] section of the config file) before running again')
-
- # If we find a broken pipe because of ControlPersist timeout expiring (see #16731),
- # we raise a special exception so that we can retry a connection.
- controlpersist_broken_pipe = b'mux_client_hello_exchange: write packet: Broken pipe' in b_stderr
- if p.returncode == 255 and controlpersist_broken_pipe:
- raise AnsibleControlPersistBrokenPipeError('SSH Error: data could not be sent because of ControlPersist broken pipe.')
-
- if p.returncode == 255 and in_data and checkrc:
- raise AnsibleConnectionFailure('SSH Error: data could not be sent to remote host "%s". Make sure this host can be reached over ssh' % self.host)
-
- return (p.returncode, b_stdout, b_stderr)
-
-
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- @_ssh_retry
- def _run(self, cmd, in_data, sudoable=True, checkrc=True):
- """Wrapper around _bare_run that retries the connection
- """
- return self._bare_run(cmd, in_data, sudoable, checkrc)
-
-
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- def _run(self, cmd, in_data, sudoable=True):
- '''
- Starts the command and communicates with it until it ends.
- '''
-
- display_cmd = map(to_unicode, map(pipes.quote, cmd))
- display.vvv(u'SSH: EXEC {0}'.format(u' '.join(display_cmd)), host=self.host)
-
- # Start the given command. If we don't need to pipeline data, we can try
- # to use a pseudo-tty (ssh will have been invoked with -tt). If we are
- # pipelining data, or can't create a pty, we fall back to using plain
- # old pipes.
-
- p = None
-
- if isinstance(cmd, (text_type, binary_type)):
- cmd = to_bytes(cmd)
- else:
- cmd = map(to_bytes, cmd)
-
- if not in_data:
- try:
- # Make sure stdin is a proper pty to avoid tcgetattr errors
- master, slave = pty.openpty()
- p = subprocess.Popen(cmd, stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdin = os.fdopen(master, 'w', 0)
- os.close(slave)
- except (OSError, IOError):
- p = None
-
- if not p:
- p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdin = p.stdin
-
- # If we are using SSH password authentication, write the password into
- # the pipe we opened in _build_command.
-
- if self._play_context.password:
- os.close(self.sshpass_pipe[0])
- os.write(self.sshpass_pipe[1], "{0}\n".format(to_bytes(self._play_context.password)))
- os.close(self.sshpass_pipe[1])
-
- ## SSH state machine
- #
- # Now we read and accumulate output from the running process until it
- # exits. Depending on the circumstances, we may also need to write an
- # escalation password and/or pipelined input to the process.
-
- states = [
- 'awaiting_prompt', 'awaiting_escalation', 'ready_to_send', 'awaiting_exit'
- ]
-
- # Are we requesting privilege escalation? Right now, we may be invoked
- # to execute sftp/scp with sudoable=True, but we can request escalation
- # only when using ssh. Otherwise we can send initial data straightaway.
-
- state = states.index('ready_to_send')
- if b'ssh' in cmd:
- if self._play_context.prompt:
- # We're requesting escalation with a password, so we have to
- # wait for a password prompt.
- state = states.index('awaiting_prompt')
- display.debug('Initial state: %s: %s' % (states[state], self._play_context.prompt))
- elif self._play_context.become and self._play_context.success_key:
- # We're requesting escalation without a password, so we have to
- # detect success/failure before sending any initial data.
- state = states.index('awaiting_escalation')
- display.debug('Initial state: %s: %s' % (states[state], self._play_context.success_key))
-
- # We store accumulated stdout and stderr output from the process here,
- # but strip any privilege escalation prompt/confirmation lines first.
- # Output is accumulated into tmp_*, complete lines are extracted into
- # an array, then checked and removed or copied to stdout or stderr. We
- # set any flags based on examining the output in self._flags.
-
- stdout = stderr = ''
- tmp_stdout = tmp_stderr = ''
-
- self._flags = dict(
- become_prompt=False, become_success=False,
- become_error=False, become_nopasswd_error=False
- )
-
- # select timeout should be longer than the connect timeout, otherwise
- # they will race each other when we can't connect, and the connect
- # timeout usually fails
- timeout = 2 + self._play_context.timeout
- rpipes = [p.stdout, p.stderr]
- for fd in rpipes:
- fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
-
- # If we can send initial data without waiting for anything, we do so
- # before we call select.
-
- if states[state] == 'ready_to_send' and in_data:
- self._send_initial_data(stdin, in_data)
- state += 1
-
- while True:
- rfd, wfd, efd = select.select(rpipes, [], [], timeout)
-
- # We pay attention to timeouts only while negotiating a prompt.
-
- if not rfd:
- if state <= states.index('awaiting_escalation'):
- # If the process has already exited, then it's not really a
- # timeout; we'll let the normal error handling deal with it.
- if p.poll() is not None:
- break
- self._terminate_process(p)
- raise AnsibleError('Timeout (%ds) waiting for privilege escalation prompt: %s' % (timeout, stdout))
-
- # Read whatever output is available on stdout and stderr, and stop
- # listening to the pipe if it's been closed.
-
- if p.stdout in rfd:
- chunk = p.stdout.read()
- if chunk == '':
- rpipes.remove(p.stdout)
- tmp_stdout += chunk
- display.debug("stdout chunk (state=%s):\n>>>%s<<<\n" % (state, chunk))
-
- if p.stderr in rfd:
- chunk = p.stderr.read()
- if chunk == '':
- rpipes.remove(p.stderr)
- tmp_stderr += chunk
- display.debug("stderr chunk (state=%s):\n>>>%s<<<\n" % (state, chunk))
-
- # We examine the output line-by-line until we have negotiated any
- # privilege escalation prompt and subsequent success/error message.
- # Afterwards, we can accumulate output without looking at it.
-
- if state < states.index('ready_to_send'):
- if tmp_stdout:
- output, unprocessed = self._examine_output('stdout', states[state], tmp_stdout, sudoable)
- stdout += output
- tmp_stdout = unprocessed
-
- if tmp_stderr:
- output, unprocessed = self._examine_output('stderr', states[state], tmp_stderr, sudoable)
- stderr += output
- tmp_stderr = unprocessed
- else:
- stdout += tmp_stdout
- stderr += tmp_stderr
- tmp_stdout = tmp_stderr = ''
-
- # If we see a privilege escalation prompt, we send the password.
- # (If we're expecting a prompt but the escalation succeeds, we
- # didn't need the password and can carry on regardless.)
-
- if states[state] == 'awaiting_prompt':
- if self._flags['become_prompt']:
- display.debug('Sending become_pass in response to prompt')
- stdin.write('{0}\n'.format(to_bytes(self._play_context.become_pass )))
- self._flags['become_prompt'] = False
- state += 1
- elif self._flags['become_success']:
- state += 1
-
- # We've requested escalation (with or without a password), now we
- # wait for an error message or a successful escalation.
-
- if states[state] == 'awaiting_escalation':
- if self._flags['become_success']:
- display.debug('Escalation succeeded')
- self._flags['become_success'] = False
- state += 1
- elif self._flags['become_error']:
- display.debug('Escalation failed')
- self._terminate_process(p)
- self._flags['become_error'] = False
- raise AnsibleError('Incorrect %s password' % self._play_context.become_method)
- elif self._flags['become_nopasswd_error']:
- display.debug('Escalation requires password')
- self._terminate_process(p)
- self._flags['become_nopasswd_error'] = False
- raise AnsibleError('Missing %s password' % self._play_context.become_method)
- elif self._flags['become_prompt']:
- # This shouldn't happen, because we should see the "Sorry,
- # try again" message first.
- display.debug('Escalation prompt repeated')
- self._terminate_process(p)
- self._flags['become_prompt'] = False
- raise AnsibleError('Incorrect %s password' % self._play_context.become_method)
-
- # Once we're sure that the privilege escalation prompt, if any, has
- # been dealt with, we can send any initial data and start waiting
- # for output.
-
- if states[state] == 'ready_to_send':
- if in_data:
- self._send_initial_data(stdin, in_data)
- state += 1
-
- # Now we're awaiting_exit: has the child process exited? If it has,
- # and we've read all available output from it, we're done.
-
- if p.poll() is not None:
- if not rpipes or not rfd:
- break
-
- # When ssh has ControlMaster (+ControlPath/Persist) enabled, the
- # first connection goes into the background and we never see EOF
- # on stderr. If we see EOF on stdout and the process has exited,
- # we're probably done. We call select again with a zero timeout,
- # just to make certain we don't miss anything that may have been
- # written to stderr between the time we called select() and when
- # we learned that the process had finished.
-
- if p.stdout not in rpipes:
- timeout = 0
- continue
-
- # If the process has not yet exited, but we've already read EOF from
- # its stdout and stderr (and thus removed both from rpipes), we can
- # just wait for it to exit.
-
- elif not rpipes:
- p.wait()
- break
-
- # Otherwise there may still be outstanding data to read.
-
- # close stdin after process is terminated and stdout/stderr are read
- # completely (see also issue #848)
- stdin.close()
-
- if C.HOST_KEY_CHECKING:
- if cmd[0] == b"sshpass" and p.returncode == 6:
- raise AnsibleError('Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host\'s fingerprint to your known_hosts file to manage this host.')
-
- controlpersisterror = 'Bad configuration option: ControlPersist' in stderr or 'unknown configuration option: ControlPersist' in stderr
- if p.returncode != 0 and controlpersisterror:
- raise AnsibleError('using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ssh_args in [ssh_connection] section of the config file) before running again')
-
- if p.returncode == 255 and in_data:
- raise AnsibleConnectionFailure('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')
-
- return (p.returncode, stdout, stderr)
-
-
- def _exec_command(self, cmd, in_data=None, sudoable=True):
- ''' run a command on the remote host '''
-
- super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
-
- display.vvv(u"ESTABLISH SSH CONNECTION FOR USER: {0}".format(self._play_context.remote_user), host=self._play_context.remote_addr)
-
- # we can only use tty when we are not pipelining the modules. piping
- # data into /usr/bin/python inside a tty automatically invokes the
- # python interactive-mode but the modules are not compatible with the
- # interactive-mode ("unexpected indent" mainly because of empty lines)
-
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- ssh_executable = self._play_context.ssh_executable
- if in_data:
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- cmd = self._build_command('ssh', self.host, cmd)
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- cmd = self._build_command(ssh_executable, self.host, cmd)
- else:
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- cmd = self._build_command('ssh', '-tt', self.host, cmd)
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- cmd = self._build_command(ssh_executable, '-tt', self.host, cmd)
-
- (returncode, stdout, stderr) = self._run(cmd, in_data, sudoable=sudoable)
-
- return (returncode, stdout, stderr)
-
-
- def dir_print(self,obj):
- for attr_name in dir(obj):
- try:
- attr_value = getattr(obj, attr_name)
- print(attr_name, attr_value, callable(attr_value))
- except:
- pass
-
-
- #
- # Main public methods
- #
- def exec_command(self, cmd, in_data=None, sudoable=False):
- ''' run a command on the chroot '''
- display.vvv('XXX exec_command: %s' % cmd)
- super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
-
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- ssh_executable = self._play_context.ssh_executable
- ##print dir(self)
- ##print dir(self._play_context)
- ##print self._play_context._attributes
- #self.dir_print(self._play_context)
- #vm = self._play_context.get_ds()
- #print( vm )
- #raise "blah"
- h = self.container_name
- if (self.lxc_version == 2):
- lxc_cmd = 'sudo -i lxc exec %s --mode=non-interactive -- /bin/sh -c %s' \
- % (pipes.quote(h),
- pipes.quote(cmd))
- elif (self.lxc_version == 1):
- lxc_cmd = 'sudo -i lxc-attach --name %s -- /bin/sh -c %s' \
- % (pipes.quote(h),
- pipes.quote(cmd))
- if in_data:
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- cmd = self._build_command('ssh', self.host, lxc_cmd)
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- cmd = self._build_command(ssh_executable, self.host, lxc_cmd)
- else:
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- cmd = self._build_command('ssh', '-tt', self.host, lxc_cmd)
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- cmd = self._build_command(ssh_executable, '-tt', self.host, lxc_cmd)
- #self.ssh.exec_command(lxc_cmd,in_data,sudoable)
- (returncode, stdout, stderr) = self._run(cmd, in_data, sudoable=sudoable)
- return (returncode, stdout, stderr)
-
-
- def put_file(self, in_path, out_path):
- ''' transfer a file from local to lxc '''
- super(Connection, self).put_file(in_path, out_path)
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- display.vvv('XXX put_file %s %s' % (in_path,out_path))
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self.host)
- ssh_executable = self._play_context.ssh_executable
-
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- if not os.path.exists(in_path):
- raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path)
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- if not os.path.exists(to_bytes(in_path, errors='surrogate_or_strict')):
- raise AnsibleFileNotFound("file or module does not exist: {0}".format(to_native(in_path)))
-
- with open(in_path,'r') as in_f:
- in_data = in_f.read()
- cmd = ('cat > %s; echo -n done' % pipes.quote(out_path))
- h = self.container_name
- if (self.lxc_version == 2):
- lxc_cmd = 'sudo lxc exec %s --mode=non-interactive -- /bin/sh -c %s' \
- % (pipes.quote(h),
- pipes.quote(cmd))
- elif (self.lxc_version == 1):
- lxc_cmd = 'sudo lxc-attach --name %s -- /bin/sh -c %s' \
- % (pipes.quote(h),
- pipes.quote(cmd))
- if in_data:
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- cmd = self._build_command('ssh', self.host, lxc_cmd)
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- cmd = self._build_command(ssh_executable, self.host, lxc_cmd)
- else:
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- cmd = self._build_command('ssh', '-tt', self.host, lxc_cmd)
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- cmd = self._build_command(ssh_executable, '-tt', self.host, lxc_cmd)
- #self.ssh.exec_command(lxc_cmd,in_data,sudoable)
- (returncode, stdout, stderr) = self._run(cmd, in_data, sudoable=False)
- return (returncode, stdout, stderr)
-
-
- def fetch_file(self, in_path, out_path):
- ''' fetch a file from lxc to local '''
- super(Connection, self).fetch_file(in_path, out_path)
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- display.vvv('XXX fetch_file %s %s' % (in_path,out_path))
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path), host=self.host)
- ssh_executable = self._play_context.ssh_executable
-
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- cmd = ('cat %s' % pipes.quote(in_path))
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- cmd = ('cat < %s' % pipes.quote(in_path))
- h = self.container_name
- if (self.lxc_version == 2):
- lxc_cmd = 'sudo lxc exec %s --mode=non-interactive -- /bin/sh -c %s' \
- % (pipes.quote(h),
- pipes.quote(cmd))
- elif (self.lxc_version == 1):
- lxc_cmd = 'sudo lxc-attach --name %s -- /bin/sh -c %s' \
- % (pipes.quote(h),
- pipes.quote(cmd))
-
- if LooseVersion(ansible_version) < LooseVersion('2.3.0.0'):
- in_data = None
- if in_data:
- cmd = self._build_command('ssh', self.host, lxc_cmd)
- else:
- cmd = self._build_command('ssh', '-tt', self.host, lxc_cmd)
- (returncode, stdout, stderr) = self._run(cmd, in_data, sudoable=False)
- if returncode != 0:
- raise AnsibleError("failed to transfer file from {0}:\n{1}\n{2}".format(in_path, stdout, stderr))
- with open(out_path,'w') as out_f:
- out_f.write(stdout)
-
- if LooseVersion(ansible_version) >= LooseVersion('2.3.0.0'):
- cmd = self._build_command(ssh_executable, self.host, lxc_cmd)
- (returncode, stdout, stderr) = self._run(cmd, None, sudoable=False)
-
- if returncode != 0:
- raise AnsibleError("failed to transfer file from {0}:\n{1}\n{2}".format(in_path, stdout, stderr))
- with open(out_path,'w') as out_f:
- out_f.write(stdout)
-
- return (returncode, stdout, stderr)
-
-
- # only used from Ansible version 2.3 on forward
- def reset(self):
- # If we have a persistent ssh connection (ControlPersist), we can ask it to stop listening.
- cmd = self._build_command(self._play_context.ssh_executable, '-O', 'stop', self.host)
- controlpersist, controlpath = self._persistence_controls(cmd)
- if controlpersist:
- display.vvv(u'sending stop: %s' % cmd)
- p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout, stderr = p.communicate()
- status_code = p.wait()
- if status_code != 0:
- raise AnsibleError("Cannot reset connection:\n%s" % stderr)
- self.close()
-
-
- def close(self):
- ''' terminate the connection; nothing to do here '''
- display.vvv('XXX close')
- super(Connection, self).close()
- #self.ssh.close()
- self._connected = False
diff --git a/ansible/group_vars/all/bird.yml b/ansible/group_vars/all/bird.yml
new file mode 100644
index 0000000..dce5afa
--- /dev/null
+++ b/ansible/group_vars/all/bird.yml
@@ -0,0 +1,3 @@
+# which version of bird is used, 0-padded with 3 digits
+# 2.15 => 2015
+birdv: 0
diff --git a/ansible/group_vars/all/ipam.yml b/ansible/group_vars/all/ipam.yml
new file mode 100644
index 0000000..2f9bed1
--- /dev/null
+++ b/ansible/group_vars/all/ipam.yml
@@ -0,0 +1,37 @@
+# Netmasks for prefixes:
+# 48: ffff:ffff:ffff:0000::
+# 52: ffff:ffff:ffff:f000::
+# 56: ffff:ffff:ffff:ff00::
+# 60: ffff:ffff:ffff:fff0::
+# 64: ffff:ffff:ffff:ffff::
+ipam6:
+ networks:
+ bitraf_dn42:
+ range: "fdb1:4242:3538:::/48"
+ tnet_dn42:
+ range: "fdb1:4242:3538:2000::/52"
+ conflatorio_dn42:
+ description: Internal network on host
+ range: "fdb1:4242:3538:2001::/64"
+ hosts:
+ - conflatorio-ix: "fdb1:4242:3538:2001::ffff/64"
+ conflatorio_docker:
+ range: "fdb1:4242:3538:2001:1001::/112"
+ node1_dn42:
+ range: "fdb1:4242:3538:2002::/64"
+ node2_dn42:
+ range: "fdb1:4242:3538:2003::/64"
+ knot_dn42:
+ range: "fdb1:4242:3538:2004::/64"
+ hosts:
+ - knot: "fdb1:4242:3538:2004::ffff/64"
+ coregonus_dn42:
+ range: "fdb1:4242:3538:2005::/64"
+ hosts:
+ - coregonus-ix: "fdb1:4242:3538:2005::ffff/64"
+ coregonus_docker:
+ range: "fdb1:4242:3538:2005:df01:676a:ec28:0a00/120"
+ kv24_dn42:
+ range: "fdb1:4242:3538:2006::/64"
+ hosts:
+ - kv24ix: "fdb1:4242:3538:2006::ffff/64"
diff --git a/ansible/host_vars/hash/roa-server.vault.yml b/ansible/host_vars/hash/roa-server.vault.yml
new file mode 100644
index 0000000..a750fb2
--- /dev/null
+++ b/ansible/host_vars/hash/roa-server.vault.yml
@@ -0,0 +1,19 @@
+$ANSIBLE_VAULT;1.1;AES256
+38363463316565643131623966623232623833613832383566353166636462613237396635396239
+3832343533663432353731353231313732386662333035330a363464616131316264613331383333
+31353331336166313361623833343135653761653133623931396464383436633132393963303462
+3630653434643266610a613130653961636362313065353833613036623239333635643164333266
+64373064363563666435383062626139356630643163386134366133333933383939343265646365
+33323165353331656232303133613263346530376333336565393235393564373562613732323766
+32613534306565386135303263383561316230303434656664323635666463663062313661343338
+39313535393964383232643337666364343763623964303130343631393964633330303038666364
+64346362343066643566333030313232396334643139613066336332633466663466663530346339
+39613430303461326431663832386537643061313961663332356661663535306266323064313634
+62393663373364336239626233396336636232376532343732616432343031653361383734333235
+31343032396532313531396135376263373163396634626166363366663365653562613130313839
+65656136633965643035353234333037663363616366323830333265616236613761323836303461
+39656237343561646166616265383630366432333631303938393938346232613039373735356333
+36626537353564353662616566643635336464336432636464616663336661373965323035326232
+34373831613465313161343132383036666338303166626639646539303438376335323261356532
+34346535656462646562333332393561656262656631303465346330643934343039663762396563
+3437326539616661643163396461663930376232396136333634
diff --git a/ansible/inventory b/ansible/inventory
index 4e2d0b2..a21cbc9 100644
--- a/ansible/inventory
+++ b/ansible/inventory
@@ -33,8 +33,8 @@ all:
ansible_host: 192.168.10.202
babypi:
ansible_host: 192.168.10.159
- astyanax:
- ansible_host: astyanax.vpn.trygvis.io
+ # astyanax:
+ # ansible_host: astyanax.vpn.trygvis.io
sweetzpot-mobile:
ansible_host: 192.168.10.123
sweetzpot-macos:
@@ -44,6 +44,8 @@ all:
ansible_host: lhn2pi.vpn.trygvis.io
lhn2ix:
kv24ix:
+ coregonus:
+ ansible_host: 192.168.10.190
node1:
ansible_host: 9859f51e-1e3e-4c05-a826-b7fbe18d91be.pub.instances.scw.cloud
@@ -148,10 +150,12 @@ all:
android-trygvis:
arius:
astyanax:
+ state: absent
babypi:
birgitte:
biwia:
conflatorio:
+ coregonus:
hash:
knot:
kv24ix:
@@ -173,6 +177,8 @@ all:
hosts:
akili:
astyanax:
+ conflatorio:
+ coregonus:
hash:
knot:
kv24ix:
@@ -185,6 +191,8 @@ all:
hosts:
akili:
astyanax:
+ conflatorio:
+ coregonus:
hash:
knot:
lhn2pi:
diff --git a/ansible/plays/roa-server.yml b/ansible/plays/roa-server.yml
new file mode 100644
index 0000000..c662640
--- /dev/null
+++ b/ansible/plays/roa-server.yml
@@ -0,0 +1,25 @@
+- hosts:
+ - hash
+ tasks:
+ - name: mkdir /etc/docker-service/roa-server
+ become: true
+ file:
+ path: /etc/docker-service/roa-server
+ state: directory
+ mode: 0700
+ - name: Install /etc/docker-service/roa-server/private.pem
+ become: true
+ copy:
+ dest: /etc/docker-service/roa-server/private.pem
+ content: "{{ roa_server.private }}"
+ owner: root
+ group: root
+ mode: 0444
+
+ - import_role:
+ name: docker-service
+ vars:
+ service: roa-server
+ template: templates/roa-server/docker-compose.yml
+# systemd_enabled: no
+# systemd_state: stopped
diff --git a/ansible/plays/templates/roa-server/docker-compose.yml b/ansible/plays/templates/roa-server/docker-compose.yml
new file mode 100644
index 0000000..c11933c
--- /dev/null
+++ b/ansible/plays/templates/roa-server/docker-compose.yml
@@ -0,0 +1,14 @@
+version: "3"
+services:
+ stayrtr:
+ image: rpki/stayrtr:latest # no tagged images are available :(
+ volumes:
+ - /etc/docker-service/roa-server/id_ecdsa:/id_ecdsa:ro
+ ports:
+ - 8022:8022
+ command:
+ - -bind=
+ - -ssh.bind=:8022
+ - -ssh.key=/id_ecdsa
+ - -checktime=false
+ - -cache=https://dn42.burble.com/roa/dn42_roa_46.json
diff --git a/ansible/prometheus/deploy-config.yml b/ansible/prometheus/deploy-config.yml
new file mode 100644
index 0000000..472d05c
--- /dev/null
+++ b/ansible/prometheus/deploy-config.yml
@@ -0,0 +1,19 @@
+- hosts:
+ - conflatorio
+ tasks:
+ - become: yes
+ file:
+ path: /etc/docker-service/prometheus
+ state: directory
+ owner: root
+ group: root
+
+ - become: yes
+ notify: reload prometheus
+ copy:
+ dest: /etc/docker-service/prometheus/prometheus.yml
+ src: "{{ inventory_hostname }}/prometheus.yml"
+
+ handlers:
+ - name: reload prometheus
+ shell: docker kill --signal HUP prometheus
diff --git a/ansible/prometheus/files/conflatorio/prometheus.yml b/ansible/prometheus/files/conflatorio/prometheus.yml
new file mode 100644
index 0000000..9fc1316
--- /dev/null
+++ b/ansible/prometheus/files/conflatorio/prometheus.yml
@@ -0,0 +1,25 @@
+global:
+ scrape_interval: 15s
+ evaluation_interval: 15s
+
+rule_files:
+ # - "first.rules"
+ # - "second.rules"
+
+scrape_configs:
+ - job_name: prometheus
+ static_configs:
+ - targets: ['localhost:9090']
+
+ - job_name: node
+ static_configs:
+ - targets:
+ - "knot.vpn.trygvis.io:9100"
+ - "hash.vpn.trygvis.io:9323"
+ - "conflatorio.vpn.trygvis.io:9100"
+
+ - job_name: bird
+ static_configs:
+ - targets:
+ - "knot.vpn.trygvis.io:9324"
+ - "conflatorio.vpn.trygvis.io:9324"
diff --git a/ansible/wg0/files/coregonus/etc/wireguard/public-wg0.key b/ansible/wg0/files/coregonus/etc/wireguard/public-wg0.key
new file mode 100644
index 0000000..16f44f9
--- /dev/null
+++ b/ansible/wg0/files/coregonus/etc/wireguard/public-wg0.key
@@ -0,0 +1 @@
+M1qJnHL6GD19On7y11uVF9m5J2noqspbfgZRmmEnwkc=
diff --git a/ansible/wg0/group_vars/all/wireguard_wg0.yml b/ansible/wg0/group_vars/all/wireguard_wg0.yml
index 3a8099c..109de3d 100644
--- a/ansible/wg0/group_vars/all/wireguard_wg0.yml
+++ b/ansible/wg0/group_vars/all/wireguard_wg0.yml
@@ -16,7 +16,7 @@ wireguard_wg0:
ipv4: 192.168.60.2
ipv6: fdf3:aad9:a885:0b3a::2
conflatorio:
- state: absent
+ state: present
ipv6: fdf3:aad9:a885:0b3a::3
arius:
state: present
@@ -33,7 +33,7 @@ wireguard_wg0:
state: present
ipv6: fdf3:aad9:a885:0b3a::9
astyanax:
- state: present
+ state: absent
ipv6: fdf3:aad9:a885:0b3a::10
allowed_ips:
- fdf3:aad9:a885:ba65::/64
@@ -66,3 +66,6 @@ wireguard_wg0:
biwia:
state: present
ipv6: fdf3:aad9:a885:0b3a::17
+ coregonus:
+ state: present
+ ipv6: fdf3:aad9:a885:0b3a::18
diff --git a/ansible/wg0/wireguard-wg0-terraform.yml b/ansible/wg0/wireguard-wg0-terraform.yml
index 33b4b47..c4c809c 100644
--- a/ansible/wg0/wireguard-wg0-terraform.yml
+++ b/ansible/wg0/wireguard-wg0-terraform.yml
@@ -7,11 +7,12 @@
content: |
# Generated from ansible data
{% for host, data in wireguard_wg0.hosts.items() %}
+ {% if data.state | default("present") == "present" %}
resource "linode_domain_record" "vpn-{{ host }}" {
domain_id = linode_domain.root.id
name = "{{ host }}.vpn"
record_type = "AAAA"
target = "{{ data.ipv6 }}"
}
+ {% endif %}
{% endfor %}
-
diff --git a/bin/requirements.txt b/bin/requirements.txt
index 8a3e290..26faaf7 100644
--- a/bin/requirements.txt
+++ b/bin/requirements.txt
@@ -1,2 +1,2 @@
-ansible==8.4.0
+ansible==10.3.0
gns3fy==0.8.0
diff --git a/sops.yml b/sops.yml
index 03226ab..571a434 100644
--- a/sops.yml
+++ b/sops.yml
@@ -1,5 +1,5 @@
-#ENC[AES256_GCM,data:KE8haaNoCU7koejXB4F+UvE=,iv:M6s1LQBOlM97GAtZOGw7cnDcQZD/q4rNrEDF1FocxGs=,tag:mQszvgw+WNcEt9Czi+8hjg==,type:comment]
-linode_token: ENC[AES256_GCM,data:OaLHFMUozNiWb/YA+Nja7plMvHfRBbvr3UMrt+hGl88F7eDe5CLkEfkeNNRHcUy1lxNhX1j4YlVhBGxdTA2PoQ==,iv:gz31tnelnCg7Yw1CoHCrSaNXnlehnx4TWFHJq0VCc3g=,tag:sdeiTbUAkTCVAeyw78DIVA==,type:str]
+#ENC[AES256_GCM,data:VXrX0NUIHcFjmxHLuYzz9ekkR7N2IW/CF6a9U0dk/cvgtwoNLA==,iv:NIpefl6uO7c7ESxgCHXe3Y2x4cf9nLPjwDJo28xt5SY=,tag:U59KOg8Ny+O33Lf63Zjo1w==,type:comment]
+linode_token: ENC[AES256_GCM,data:PeLIxcZ5mQMnp1LZy4saSUWIpCxrGm+3/6PssmIE9yO81x2HcGrgxO0CNl1feOtPrI1PVcAfFnFlpSetELLZlg==,iv:ETBKZgmFdIHoUROHVUzhxRoLS2uIuGR0SXZ96C9FhDk=,tag:pzuS8RLQf1A5ctmrOanVgA==,type:str]
knot_pdb_terraform_password: ENC[AES256_GCM,data:cu5aUZAVrmtzgBB2hGfBkd+TU4vB0cWnBNluTHptyV0YvZuq,iv:HT4Cmr9huuylVt2vwFcrWUlBmDE6V3n0bXq/telJNBM=,tag:2RSvWnAAM5seHv12HyDprA==,type:str]
sops:
kms: []
@@ -34,8 +34,8 @@ sops:
a1E2c3VEaWR0K3U4dnpqdm5RU0VCZUkKiOtFMhim7qAe4kDU2gijcCChesM0qAGk
Z2xNVfBy4HH58cgWrtCQ6PRvULwAQ6Bgq59iZ7H/C2IFVqVfliajmw==
-----END AGE ENCRYPTED FILE-----
- lastmodified: "2023-10-23T13:22:29Z"
- mac: ENC[AES256_GCM,data:XkWZD0Whj/5Zd/dGC20UyQxvvkrca6Ox58L2cXzLAgum/lYj6Q+GdRIIApz7Iwmj8ZkX4I8+jrF9epozJwS4ZiYW6qsmcNzpt3F3oiwYqe8OcLfOpdSVdy5QekiNtweqO9zTAO14hVbz+QYkTnCBqc8tBF2BFVxek6j8KKSbTTM=,iv:O8AU9xhhnfJ36NBfJkdB6YVtmL/sEXRfVrMBpCV5ufc=,tag:/g/I6C2t4+QWUfFXDbblKQ==,type:str]
+ lastmodified: "2024-08-21T18:05:07Z"
+ mac: ENC[AES256_GCM,data:Kxa9SCKy0pLCgqGd7f+xFbQz3Cpf9EfDYP1fwPiIweHhw8iFEeaI7WZCb9zXjsky1tuQ0nbJMHfVQaPSqLC+ACyrBioXIBjgITAfEg3xtpRYiSQRFVBtGA7HpEAKWeFquzTvBR/EAoDuEvFTkrup3JSE8sM3bWKVb2dy1uRyBIc=,iv:O5LO1TFJLlFdCOGWWk5xJlQtVF1+sZTCH2DUKQdvQGo=,tag:0USQg2+EYUVG3+FsjilssQ==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.7.3
diff --git a/terraform/conflatorio-docker/main.tf b/terraform/conflatorio-docker/main.tf
index 8a01be6..e7b11ad 100644
--- a/terraform/conflatorio-docker/main.tf
+++ b/terraform/conflatorio-docker/main.tf
@@ -22,6 +22,14 @@ data "sops_file_entry" "linode_token" {
data_key = "linode_token"
}
+locals {
+ public_ip = "fdb1:4242:3538:2001::ffff"
+ network_addr = "fdb1:4242:3538:2001:1001::"
+ network_range = 112
+ private_network_addr = "fdb1:4242:3538:2001:1002::"
+ private_network_range = 112
+}
+
output "foo" {
value = "foo!"
}
diff --git a/terraform/conflatorio-docker/network.tf b/terraform/conflatorio-docker/network.tf
index 32e1bfb..8a839f5 100644
--- a/terraform/conflatorio-docker/network.tf
+++ b/terraform/conflatorio-docker/network.tf
@@ -4,6 +4,22 @@ resource "docker_network" "public" {
ipv6 = true
ipam_config {
- subnet = "fdf3:aad9:a885:77dd:bbbb::/120"
+ subnet = "${local.network_addr}/${local.network_range}"
+ }
+
+ ipam_config {
+ gateway = "172.22.0.1"
+ subnet = "172.22.0.0/16"
+ }
+}
+
+# Internal shared network
+resource "docker_network" "private" {
+ name = "private"
+
+ ipv6 = true
+
+ ipam_config {
+ subnet = "${local.private_network_addr}/${local.private_network_range}"
}
}
diff --git a/terraform/conflatorio-docker/traefik.tf b/terraform/conflatorio-docker/traefik.tf
index d15ac5c..cb5f2a0 100644
--- a/terraform/conflatorio-docker/traefik.tf
+++ b/terraform/conflatorio-docker/traefik.tf
@@ -12,6 +12,8 @@ resource "docker_container" "traefik" {
privileged = false
must_run = false
+ network_mode = "bridge"
+
networks_advanced {
name = docker_network.traefik.name
}
@@ -23,20 +25,20 @@ resource "docker_container" "traefik" {
ports {
internal = 80
external = 80
- ip = "fdf3:aad9:a885:77dd::2"
+ ip = "${local.public_ip}"
}
ports {
internal = 443
external = 443
- ip = "fdf3:aad9:a885:77dd::2"
+ ip = "${local.public_ip}"
}
# for buildfarm-server
ports {
internal = 8980
external = 8980
- ip = "fdf3:aad9:a885:77dd::2"
+ ip = "${local.public_ip}"
}
command = [
diff --git a/terraform/conflatorio-prometheus/.terraform.lock.hcl b/terraform/conflatorio-prometheus/.terraform.lock.hcl
new file mode 100644
index 0000000..9e1ccff
--- /dev/null
+++ b/terraform/conflatorio-prometheus/.terraform.lock.hcl
@@ -0,0 +1,104 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/cyrilgdn/postgresql" {
+ version = "1.21.0"
+ constraints = "1.21.0"
+ hashes = [
+ "h1:v7X6z6j8Uo07+QJPuO3EVM8N1uy6t2k+1GiRGioOPGc=",
+ "zh:17e3d204dabc116276c763bb0cd159aa315789d3b0bcd3b8aede935509960ab6",
+ "zh:1a7e5ac1921afdb3b12a49714c5f446a7604bfa1eb7bd9c123d607f8cbda45e4",
+ "zh:24a880623e30928ee866c84016b1db4e0458764c7a547b808e2d398e90456d42",
+ "zh:255c6162d35ace6a313a50c4ceb5452bd5582d7bb097a44e75ac4901e635ca13",
+ "zh:281ab48b69d0852b5138fe5ea2301ff7fdff30748f1f7878ac837c71622d3f7b",
+ "zh:3d4e0ae2809e743272e5d2640b64354c48140e225c2ba6f1a211700ea70e0754",
+ "zh:4f4df290e3ff626d8b274c624852d21d194a397a7f580ebe0cbf0ff64dd8fa31",
+ "zh:5997ce8f7cbcd7ff5a443d037b83857b17b64be928e9d9338dd494466733df60",
+ "zh:a05f0b65b0abf4488cdaf7b239206940940be77fd51f458f2a0986c6a17436aa",
+ "zh:aeb6c6da639abb6126f38be90a7bc428f925461bf599388ff092e059e0bb1a94",
+ "zh:d30bb053b6000c32cc8d03da231c30eaecddd926200adf2e9ad9c0186c2ad1ad",
+ "zh:d978827683b324c75141fa80ebc28dcaf181acd0be0a47b1e5f9579a72a08151",
+ "zh:f51fae9206361cbe865e30b06d106270d6acf7ece0550953b0d6b55afe6be9ba",
+ "zh:fa49a2702c529865c20f57185d6dd41072fdd9a13ac1a49e30eb88605c31af7a",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/null" {
+ version = "3.2.2"
+ hashes = [
+ "h1:zT1ZbegaAYHwQa+QwIFugArWikRJI9dqohj8xb0GY88=",
+ "zh:3248aae6a2198f3ec8394218d05bd5e42be59f43a3a7c0b71c66ec0df08b69e7",
+ "zh:32b1aaa1c3013d33c245493f4a65465eab9436b454d250102729321a44c8ab9a",
+ "zh:38eff7e470acb48f66380a73a5c7cdd76cc9b9c9ba9a7249c7991488abe22fe3",
+ "zh:4c2f1faee67af104f5f9e711c4574ff4d298afaa8a420680b0cb55d7bbc65606",
+ "zh:544b33b757c0b954dbb87db83a5ad921edd61f02f1dc86c6186a5ea86465b546",
+ "zh:696cf785090e1e8cf1587499516b0494f47413b43cb99877ad97f5d0de3dc539",
+ "zh:6e301f34757b5d265ae44467d95306d61bef5e41930be1365f5a8dcf80f59452",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:913a929070c819e59e94bb37a2a253c228f83921136ff4a7aa1a178c7cce5422",
+ "zh:aa9015926cd152425dbf86d1abdbc74bfe0e1ba3d26b3db35051d7b9ca9f72ae",
+ "zh:bb04798b016e1e1d49bcc76d62c53b56c88c63d6f2dfe38821afef17c416a0e1",
+ "zh:c23084e1b23577de22603cff752e59128d83cfecc2e6819edadd8cf7a10af11e",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+ version = "3.5.1"
+ constraints = "3.5.1"
+ hashes = [
+ "h1:VSnd9ZIPyfKHOObuQCaKfnjIHRtR7qTw19Rz8tJxm+k=",
+ "zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64",
+ "zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d",
+ "zh:4d2b219d09abf3b1bb4df93d399ed156cadd61f44ad3baf5cf2954df2fba0831",
+ "zh:6130bdde527587bbe2dcaa7150363e96dbc5250ea20154176d82bc69df5d4ce3",
+ "zh:6cc326cd4000f724d3086ee05587e7710f032f94fc9af35e96a386a1c6f2214f",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:b6d88e1d28cf2dfa24e9fdcc3efc77adcdc1c3c3b5c7ce503a423efbdd6de57b",
+ "zh:ba74c592622ecbcef9dc2a4d81ed321c4e44cddf7da799faa324da9bf52a22b2",
+ "zh:c7c5cde98fe4ef1143bd1b3ec5dc04baf0d4cc3ca2c5c7d40d17c0e9b2076865",
+ "zh:dac4bad52c940cd0dfc27893507c1e92393846b024c5a9db159a93c534a3da03",
+ "zh:de8febe2a2acd9ac454b844a4106ed295ae9520ef54dc8ed2faf29f12716b602",
+ "zh:eab0d0495e7e711cca367f7d4df6e322e6c562fc52151ec931176115b83ed014",
+ ]
+}
+
+provider "registry.terraform.io/kreuzwerker/docker" {
+ version = "2.24.0"
+ constraints = "2.24.0"
+ hashes = [
+ "h1:1z0/qA77T3PS/1m4vRO8UgWjHjk5/v+f3JfGbMyzX18=",
+ "zh:181fefd55c8eb75efe9815c43fdd76422b57951ef53b5d5f19273a00fdf0e2e2",
+ "zh:2ec84e029d169f188be2addf7f45c2555f226f67d4b6fb66c1749ed5b2c4a76a",
+ "zh:6f5cf945148485f57b919d31a30f1a5a93d45f4e8edfdb0b80b22258d51795d8",
+ "zh:8d00c2c459a48453f52a00a8d1ffdb7bcf72fe4b3b09ffcfd52218c4646fa7fa",
+ "zh:9bd6e06601e0a972b9ce01150e32e76b76b4caf1d9798daf4cf16d06e2a8d4a3",
+ "zh:af72591132dc8cd338f293e458403851e6b8a6ac4c4d25a3268940f9763df7aa",
+ "zh:c4a47c5c7ad2ff1fc5212e69c5ef837a127346264e46ce7b5d13362545e4aa70",
+ "zh:c6d68f33efcd3372331ed0d58ec49e8b01ddc132934b14d2d45977076950e4b3",
+ "zh:db228855ae7235095d367f3597719747e5be0dd9ce2206ea02062560b518c08a",
+ "zh:e8d6ce89642925f2e813d0b829bd5562582de37eaa39351e231ab474383e703a",
+ "zh:ec83d8c86a918d25eb824cc99f98924ef8949eb69aa40cb5ff2db24369e52d9c",
+ "zh:ee0032d3d86adeeca7fdd4922bb8db87dbb5cd0093c054ff8efe2260de0b624c",
+ "zh:f033b70f342f32eeb98c213e6fc7098d7afd22b3146a5cb6173c128b0e86d732",
+ "zh:f1bc3a2c4f152f8adc9a1f9c852496232ef31073b149945756c13bc9688cf08b",
+ ]
+}
+
+provider "registry.terraform.io/lokkersp/sops" {
+ version = "0.6.10"
+ constraints = "0.6.10"
+ hashes = [
+ "h1:atU8NIBxpNTWY+qBubvEOfjOn4K1aCDoq1iUFocgIHQ=",
+ "zh:0f053a26392a581b1f1ce6316cb7ed8ec4cc75e7f5f1cf7cfd45050b6b3c87ea",
+ "zh:207bb96c4471fce9aeb1b3c217d772692c3d865d294cf4d2501dad41de36a15e",
+ "zh:28506e8f1f3b9eaa95d99043440328044ee6340143535e5751538328a529d001",
+ "zh:3cae3bcea9e35fdc5b3f2af1b4580cd625c996448ad0c676c772260e46b25289",
+ "zh:3e44daaf82986c2b0028aeb17b867f3c68ed5dd8ac8625ba0406cf2a5fd3d92e",
+ "zh:457fb8ca2e677af24f9a4bdd8b613b1d7b604ad7133541657e5757c19268da71",
+ "zh:473d727c228f021a3df8cc8dcc6231ad7f90ed63f9e47c36b597d591e76228da",
+ "zh:48c4c1df39fd76ec8bd5fe9ac70cdc0927ac8be95582dbe46458b3442ce0fcd9",
+ "zh:728b19cb5c07e5e9d8b78fd94cc57d4c13582ecd24b7eb7c4cc2bf73b12fe4d1",
+ "zh:c51ed9af591779bb0910b82addeebb10f53428b994f8db653dd1dedcec60916c",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ ]
+}
diff --git a/terraform/conflatorio-prometheus/backend.tf b/terraform/conflatorio-prometheus/backend.tf
new file mode 100644
index 0000000..9f2eed0
--- /dev/null
+++ b/terraform/conflatorio-prometheus/backend.tf
@@ -0,0 +1,12 @@
+# Generated by Terragrunt. Sig: nIlQXj57tbuaRZEa
+terraform {
+ backend "s3" {
+ bucket = "terraform-a6726272-73ff-11ed-8bdd-c79eb8376e05"
+ key = "conflatorio-prometheus/terraform.tfstate"
+ skip_region_validation = true
+ skip_credentials_validation = true
+ skip_metadata_api_check = true
+ region = "eu-central-1"
+ endpoint = "eu-central-1.linodeobjects.com"
+ }
+}
diff --git a/terraform/conflatorio-prometheus/main.tf b/terraform/conflatorio-prometheus/main.tf
new file mode 100644
index 0000000..f5c5a7f
--- /dev/null
+++ b/terraform/conflatorio-prometheus/main.tf
@@ -0,0 +1,34 @@
+terraform {
+ required_version = "~> 1.3.5"
+
+ required_providers {
+ docker = {
+ source = "kreuzwerker/docker"
+ version = "2.24.0"
+ }
+ postgresql = {
+ source = "cyrilgdn/postgresql"
+ version = "1.21.0"
+ }
+ random = {
+ source = "hashicorp/random"
+ version = "3.5.1"
+ }
+ sops = {
+ source = "lokkersp/sops"
+ version = "0.6.10"
+ }
+ }
+}
+
+provider "docker" {
+ host = "ssh://conflatorio.vpn.trygvis.io"
+}
+
+data "docker_network" "traefik" {
+ name = "traefik"
+}
+
+data "docker_network" "private" {
+ name = "private"
+}
diff --git a/terraform/conflatorio-prometheus/prometheus.tf b/terraform/conflatorio-prometheus/prometheus.tf
new file mode 100644
index 0000000..04dd406
--- /dev/null
+++ b/terraform/conflatorio-prometheus/prometheus.tf
@@ -0,0 +1,66 @@
+resource "docker_image" "prometheus" {
+ name = "prom/prometheus:v2.53.2"
+}
+
+resource "docker_volume" "prometheus" {
+ name = "prometheus"
+}
+
+resource "docker_container" "prometheus" {
+ image = docker_image.prometheus.image_id
+ name = "prometheus"
+ must_run = true
+
+ env = [
+ ]
+
+ networks_advanced {
+ name = data.docker_network.private.name
+ }
+
+ # networks_advanced {
+ # name = data.docker_network.traefik.name
+ # }
+
+ # dynamic "labels" {
+ # for_each = [
+ # { label = "traefik.enable", value = "true" },
+ # { label = "traefik.docker.network", value = data.docker_network.traefik.name },
+ # { label = "traefik.http.routers.prometheus.rule", value = "Host(`prometheus.trygvis.io`)" },
+ # { label = "traefik.http.routers.prometheus.entrypoints", value = "websecure" },
+ # { label = "traefik.http.routers.prometheus.tls.certresolver", value = "linode" },
+ # ]
+ # content {
+ # label = labels.value["label"]
+ # value = labels.value["value"]
+ # }
+ # }
+
+ mounts {
+ source = "${local.path}"
+ target = "/etc/prometheus"
+ type = "bind"
+ }
+
+ volumes {
+ volume_name = docker_volume.prometheus.name
+ read_only = false
+ container_path = "/prometheus"
+ }
+
+ depends_on = [ null_resource.mkdir ]
+}
+
+locals {
+ path = "/etc/docker-service/prometheus"
+}
+
+resource "null_resource" "mkdir" {
+ triggers = {
+ path = local.path
+ }
+
+ provisioner "local-exec" {
+ command = "ssh conflatorio.vpn.trygvis.io sudo mkdir -p ${local.path}"
+ }
+}
diff --git a/terraform/conflatorio-prometheus/terragrunt.hcl b/terraform/conflatorio-prometheus/terragrunt.hcl
new file mode 100644
index 0000000..e147285
--- /dev/null
+++ b/terraform/conflatorio-prometheus/terragrunt.hcl
@@ -0,0 +1,3 @@
+include "root" {
+ path = find_in_parent_folders()
+}
diff --git a/terraform/dns/main.tf b/terraform/dns/main.tf
index c67944e..753ef75 100644
--- a/terraform/dns/main.tf
+++ b/terraform/dns/main.tf
@@ -14,7 +14,7 @@ terraform {
required_providers {
linode = {
version = "2.7.1"
- source = "linode/linode"
+ source = "linode/linode"
}
}
}
diff --git a/terraform/dns/trygvis.tf b/terraform/dns/trygvis.tf
index 01b6cec..608dd3e 100644
--- a/terraform/dns/trygvis.tf
+++ b/terraform/dns/trygvis.tf
@@ -17,6 +17,22 @@ resource "linode_domain_record" "root-a" {
target = "176.58.112.84"
}
+resource "linode_domain_record" "root-mx" {
+ domain_id = linode_domain.root.id
+ name = ""
+ record_type = "MX"
+ target = "in1-smtp.messagingengine.com"
+ priority = 10
+}
+
+resource "linode_domain_record" "root-mx2" {
+ domain_id = linode_domain.root.id
+ name = ""
+ record_type = "MX"
+ target = "in2-smtp.messagingengine.com"
+ priority = 20
+}
+
resource "linode_domain_record" "root-txt-google" {
domain_id = linode_domain.root.id
name = ""
@@ -39,6 +55,52 @@ resource "linode_domain_record" "root-txt-keybase" {
target = "keybase-site-verification=gcoO7zav4G2IK5KQdrWOgz_PD9wpZhz-0afIb1Kodrk"
}
+resource "linode_domain_record" "root-txt-fastmail-dkim" {
+ count = 3
+ domain_id = linode_domain.root.id
+ name = format("fm%d._domainkey", count.index + 1)
+ record_type = "CNAME"
+ target = format("fm%d.trygvis.io.dkim.fmhosted.com", count.index + 1)
+}
+
+resource "linode_domain_record" "root-txt-fastmail-spf" {
+ domain_id = linode_domain.root.id
+ name = ""
+ record_type = "TXT"
+ target = "v=spf1 include:spf.messagingengine.com ?all"
+}
+
+resource "linode_domain_record" "root-txt-fastmail-dmark" {
+ domain_id = linode_domain.root.id
+ name = "_dmarc"
+ record_type = "TXT"
+ target = "v=DMARC1; p=none;"
+}
+
+resource "linode_domain_record" "root-txt-fastmail-srv" {
+ domain_id = linode_domain.root.id
+ record_type = "SRV"
+ service = each.key
+ priority = each.value.priority
+ weight = each.value.weight
+ port = each.value.port
+ target = each.value.target
+
+ for_each = tomap({
+ submission = { priority = 0, weight = 0, port = 0, target = "." },
+ imap = { priority = 0, weight = 0, port = 0, target = "." },
+ submissions = { priority = 0, weight = 1, port = 465, target = "smtp.fastmail.com" },
+ imaps = { priority = 0, weight = 1, port = 993, target = "imap.fastmail.com" },
+ jmap = { priority = 0, weight = 1, port = 443, target = "api.fastmail.com" },
+ autodiscover = { priority = 0, weight = 1, port = 443, target = "autodiscover.fastmail.com" },
+ autodiscover = { priority = 0, weight = 1, port = 443, target = "autodiscover.fastmail.com" },
+ carddav = { priority = 0, weight = 0, port = 0, target = "." },
+ carddavs = { priority = 0, weight = 1, port = 443, target = "carddav.fastmail.com" },
+ caldav = { priority = 0, weight = 0, port = 0, target = "." },
+ caldavs = { priority = 0, weight = 1, port = 443, target = "caldav.fastmail.com" },
+ })
+}
+
resource "linode_domain_record" "root-cname-ses-1" {
domain_id = linode_domain.root.id
name = "k5o5gjadej2kkfncu36i3ef5gt473sxy._domainkey"
@@ -53,13 +115,6 @@ resource "linode_domain_record" "root-cname-ses-2" {
target = "imtuzw2lnfktlc7uongw433qbwjxxatg.dkim.amazonses.com"
}
-resource "linode_domain_record" "dlock" {
- domain_id = linode_domain.root.id
- name = "dlock"
- record_type = "A"
- target = "35.205.192.14"
-}
-
resource "linode_domain_record" "hash" {
domain_id = linode_domain.root.id
name = "hash"
@@ -81,6 +136,13 @@ resource "linode_domain_record" "numquam" {
target = "163.172.160.56"
}
+resource "linode_domain_record" "lon1_dn42" {
+ domain_id = linode_domain.root.id
+ name = "lon1.dn42"
+ record_type = "CNAME"
+ target = "knot.inamo.no"
+}
+
# Aliases for trygvis.io
resource "linode_domain_record" "mw" {
domain_id = linode_domain.root.id
diff --git a/terraform/dns/vpn-cname.tf b/terraform/dns/vpn-cname.tf
index bbd411a..7a9fba4 100644
--- a/terraform/dns/vpn-cname.tf
+++ b/terraform/dns/vpn-cname.tf
@@ -1,22 +1,29 @@
-resource "linode_domain_record" "vpn-conflatorio" {
+#resource "linode_domain_record" "vpn-conflatorio" {
+# domain_id = linode_domain.root.id
+# name = "conflatorio.vpn"
+# record_type = "AAAA"
+# target = "fdf3:aad9:a885:77dd::2"
+#}
+
+resource "linode_domain_record" "net-conflatorio" {
domain_id = linode_domain.root.id
- name = "conflatorio.vpn"
+ name = "conflatorio.net"
record_type = "AAAA"
- target = "fdf3:aad9:a885:77dd::2"
+ target = "fdb1:4242:3538:2001::ffff"
}
resource "linode_domain_record" "vpn-unifi" {
domain_id = linode_domain.root.id
name = "unifi.vpn"
record_type = "CNAME"
- target = "${linode_domain_record.vpn-conflatorio.name}.trygvis.io"
+ target = "${linode_domain_record.net-conflatorio.name}.trygvis.io"
}
resource "linode_domain_record" "vpn-grafana" {
domain_id = linode_domain.root.id
name = "grafana.vpn"
record_type = "CNAME"
- target = "${linode_domain_record.vpn-conflatorio.name}.trygvis.io"
+ target = "${linode_domain_record.net-conflatorio.name}.trygvis.io"
}
resource "linode_domain_record" "vpn-influxdb" {
diff --git a/terraform/dns/vpn.tf b/terraform/dns/vpn.tf
index d73d01e..58efa5c 100644
--- a/terraform/dns/vpn.tf
+++ b/terraform/dns/vpn.tf
@@ -5,11 +5,11 @@ resource "linode_domain_record" "vpn-knot" {
record_type = "AAAA"
target = "fdf3:aad9:a885:0b3a::1"
}
-resource "linode_domain_record" "vpn-birgitte" {
+resource "linode_domain_record" "vpn-conflatorio" {
domain_id = linode_domain.root.id
- name = "birgitte.vpn"
+ name = "conflatorio.vpn"
record_type = "AAAA"
- target = "fdf3:aad9:a885:0b3a::2"
+ target = "fdf3:aad9:a885:0b3a::3"
}
resource "linode_domain_record" "vpn-arius" {
domain_id = linode_domain.root.id
@@ -23,36 +23,18 @@ resource "linode_domain_record" "vpn-akili" {
record_type = "AAAA"
target = "fdf3:aad9:a885:0b3a::7"
}
-resource "linode_domain_record" "vpn-malabaricus" {
- domain_id = linode_domain.root.id
- name = "malabaricus.vpn"
- record_type = "AAAA"
- target = "fdf3:aad9:a885:0b3a::8"
-}
resource "linode_domain_record" "vpn-sweetzpot-mobile" {
domain_id = linode_domain.root.id
name = "sweetzpot-mobile.vpn"
record_type = "AAAA"
target = "fdf3:aad9:a885:0b3a::9"
}
-resource "linode_domain_record" "vpn-astyanax" {
- domain_id = linode_domain.root.id
- name = "astyanax.vpn"
- record_type = "AAAA"
- target = "fdf3:aad9:a885:0b3a::10"
-}
resource "linode_domain_record" "vpn-sweetzpot-macos" {
domain_id = linode_domain.root.id
name = "sweetzpot-macos.vpn"
record_type = "AAAA"
target = "fdf3:aad9:a885:0b3a::11"
}
-resource "linode_domain_record" "vpn-android-trygvis" {
- domain_id = linode_domain.root.id
- name = "android-trygvis.vpn"
- record_type = "AAAA"
- target = "fdf3:aad9:a885:0b3a::12"
-}
resource "linode_domain_record" "vpn-hash" {
domain_id = linode_domain.root.id
name = "hash.vpn"
@@ -71,9 +53,21 @@ resource "linode_domain_record" "vpn-lhn2ix" {
record_type = "AAAA"
target = "fdf3:aad9:a885:0b3a::15"
}
+resource "linode_domain_record" "vpn-kv24ix" {
+ domain_id = linode_domain.root.id
+ name = "kv24ix.vpn"
+ record_type = "AAAA"
+ target = "fdf3:aad9:a885:0b3a::16"
+}
resource "linode_domain_record" "vpn-biwia" {
domain_id = linode_domain.root.id
name = "biwia.vpn"
record_type = "AAAA"
target = "fdf3:aad9:a885:0b3a::17"
}
+resource "linode_domain_record" "vpn-coregonus" {
+ domain_id = linode_domain.root.id
+ name = "coregonus.vpn"
+ record_type = "AAAA"
+ target = "fdf3:aad9:a885:0b3a::18"
+}
diff --git a/terraform/grafana/grafana.tf b/terraform/grafana/grafana.tf
index 6d75da3..7cda977 100644
--- a/terraform/grafana/grafana.tf
+++ b/terraform/grafana/grafana.tf
@@ -12,12 +12,14 @@ resource "docker_container" "grafana" {
privileged = false
must_run = true
+ network_mode = "bridge"
+
networks_advanced {
name = data.docker_network.traefik.name
}
networks_advanced {
- name = data.docker_network.public.name
+ name = data.docker_network.private.name
}
dynamic "labels" {
diff --git a/terraform/grafana/main.tf b/terraform/grafana/main.tf
index fa225ab..cb9b920 100644
--- a/terraform/grafana/main.tf
+++ b/terraform/grafana/main.tf
@@ -45,3 +45,7 @@ data "docker_network" "traefik" {
data "docker_network" "public" {
name = "public"
}
+
+data "docker_network" "private" {
+ name = "private"
+}
diff --git a/terraform/terragrunt.hcl b/terraform/terragrunt.hcl
index e7e5f6a..382cf17 100644
--- a/terraform/terragrunt.hcl
+++ b/terraform/terragrunt.hcl
@@ -1,7 +1,7 @@
generate "backend" {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
- contents = <<EOF
+ contents = <<EOF
terraform {
backend "s3" {
bucket = "terraform-a6726272-73ff-11ed-8bdd-c79eb8376e05"
diff --git a/terraform/unifi-controller/main.tf b/terraform/unifi-controller/main.tf
index f5f7b0a..55c133c 100644
--- a/terraform/unifi-controller/main.tf
+++ b/terraform/unifi-controller/main.tf
@@ -28,8 +28,10 @@ provider "docker" {
locals {
domain_name = "unifi.vpn.trygvis.io"
+ public_ip = "fdb1:4242:3538:2001::ffff"
+
docker_image_controller = "lscr.io/linuxserver/unifi-controller:8.0.24-mongoless"
- docker_image_mongo = "mongo:7.0"
+ docker_image_mongo = "mongo:7.0"
mongo_database = "unifi"
mongo_username = "unifi"
diff --git a/terraform/unifi-controller/mongo.tf b/terraform/unifi-controller/mongo.tf
index 98b4e36..2b83691 100644
--- a/terraform/unifi-controller/mongo.tf
+++ b/terraform/unifi-controller/mongo.tf
@@ -24,15 +24,18 @@ resource "docker_container" "unifi-mongo" {
name = docker_network.unifi.name
}
+ network_mode = "bridge"
+
volumes {
volume_name = docker_volume.unifi-mongo.name
+ read_only = false
container_path = "/data/db"
}
}
output "mongo_init_js" {
sensitive = true
- value = <<-EOF
+ value = <<-EOF
db.getSiblingDB("${local.mongo_database}").
createUser({
user: "${local.mongo_database}",
diff --git a/terraform/unifi-controller/unifi.tf b/terraform/unifi-controller/unifi.tf
index 8e6c7d7..4b0f1c6 100644
--- a/terraform/unifi-controller/unifi.tf
+++ b/terraform/unifi-controller/unifi.tf
@@ -52,12 +52,13 @@ resource "docker_container" "unifi-controller" {
internal = ports.value["port"]
external = ports.value["port"]
protocol = ports.value["proto"]
- ip = "fdf3:aad9:a885:77dd::2"
+ ip = local.public_ip
}
}
volumes {
volume_name = docker_volume.unifi-controller.name
+ read_only = false
container_path = "/config"
}
diff --git a/tnet/README.md b/tnet/README.md
new file mode 100644
index 0000000..d65106e
--- /dev/null
+++ b/tnet/README.md
@@ -0,0 +1,8 @@
+Generating link-local ULA address:
+
+ echo fe80:$(uuid -v4|cut -c1-4):$(uuid -v4|cut -c1-4):$(uuid -v4|cut -c1-4):$(uuid -v4|cut -c1-4):$(uuid -v4|cut -c1-4):$(uuid -v4|cut -c1-4):$(uuid -v4|cut -c1-4)
+
+Generating Wireguard link keys:
+
+ from=conflatorio to=knot; wg genkey | tee keys/wg-$from-$to.sops.key | wg pubkey > keys/wg-$from-$to.pub; sops -e -i keys/wg-$from-$to.sops.key
+
diff --git a/tnet/files/akili/bird-tnet-pre.conf b/tnet/files/akili/bird-tnet-pre.conf
index 7994dfe..74c981d 100644
--- a/tnet/files/akili/bird-tnet-pre.conf
+++ b/tnet/files/akili/bird-tnet-pre.conf
@@ -1,7 +1,20 @@
-define tnet = fdb1:4242:3538::/48;
-define tnet_router = fdb1:4242:3538:ffff::/64;
+define tnet = fdb1:4242:3538:2000::/52;
-function is_tnet() # -> bool
+function is_tnet()
{
- return net ~ tnet && ! (net ~ tnet_router);
+ return net ~ tnet;
+}
+
+roa6 table dn42_roa;
+
+protocol static {
+ roa6 { table dn42_roa; };
+ include "/etc/bird/dn42_roa_bird2_6.conf";
+};
+
+function dn42_is_valid_network()
+{
+ return net ~ [
+ fd00::/8{44,64} # ULA address space as per RFC 4193
+ ];
}
diff --git a/tnet/files/akili/bird-tnet.conf b/tnet/files/akili/bird-tnet.conf
index f9b9d08..24c9b8e 100644
--- a/tnet/files/akili/bird-tnet.conf
+++ b/tnet/files/akili/bird-tnet.conf
@@ -1,3 +1,9 @@
+# Set to true if this peer is directly connected to a dn42 peer
+define is_dn42_peer = true;
+# If we are connected directly to dn42, we don't want the dn42 routes from others
+define import_dn42 = !is_dn42_peer;
+define export_dn42 = is_dn42_peer;
+
template bgp tnet_tpl {
local as 4242423538;
neighbor internal;
@@ -10,19 +16,23 @@ template bgp tnet_tpl {
next hop self;
import filter {
if is_tnet() then {
- print proto, ": import accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if import_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": import reject, reason=not tnet";
}
- print proto, ": import reject, reason=not tnet"; reject;
};
# newer bird's only
# import keep filtered;
export filter {
if is_tnet() then {
- print proto, ": export accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) export accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if export_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": export reject, reason=not tnet";
}
- print proto, ": export reject, reason=not tnet"; reject;
};
};
}
diff --git a/tnet/files/astyanax/bird-tnet-pre.conf b/tnet/files/astyanax/bird-tnet-pre.conf
index 7994dfe..74c981d 100644
--- a/tnet/files/astyanax/bird-tnet-pre.conf
+++ b/tnet/files/astyanax/bird-tnet-pre.conf
@@ -1,7 +1,20 @@
-define tnet = fdb1:4242:3538::/48;
-define tnet_router = fdb1:4242:3538:ffff::/64;
+define tnet = fdb1:4242:3538:2000::/52;
-function is_tnet() # -> bool
+function is_tnet()
{
- return net ~ tnet && ! (net ~ tnet_router);
+ return net ~ tnet;
+}
+
+roa6 table dn42_roa;
+
+protocol static {
+ roa6 { table dn42_roa; };
+ include "/etc/bird/dn42_roa_bird2_6.conf";
+};
+
+function dn42_is_valid_network()
+{
+ return net ~ [
+ fd00::/8{44,64} # ULA address space as per RFC 4193
+ ];
}
diff --git a/tnet/files/astyanax/bird-tnet.conf b/tnet/files/astyanax/bird-tnet.conf
index d697e54..3dbf4c9 100644
--- a/tnet/files/astyanax/bird-tnet.conf
+++ b/tnet/files/astyanax/bird-tnet.conf
@@ -1,3 +1,9 @@
+# Set to true if this peer is directly connected to a dn42 peer
+define is_dn42_peer = true;
+# If we are connected directly to dn42, we don't want the dn42 routes from others
+define import_dn42 = !is_dn42_peer;
+define export_dn42 = is_dn42_peer;
+
template bgp tnet_tpl {
local as 4242423538;
neighbor internal;
@@ -10,19 +16,23 @@ template bgp tnet_tpl {
next hop self;
import filter {
if is_tnet() then {
- print proto, ": import accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if import_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": import reject, reason=not tnet";
}
- print proto, ": import reject, reason=not tnet"; reject;
};
# newer bird's only
# import keep filtered;
export filter {
if is_tnet() then {
- print proto, ": export accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) export accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if export_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": export reject, reason=not tnet";
}
- print proto, ": export reject, reason=not tnet"; reject;
};
};
}
diff --git a/tnet/files/conflatorio/bird-tnet-pre.conf b/tnet/files/conflatorio/bird-tnet-pre.conf
new file mode 100644
index 0000000..d60e8df
--- /dev/null
+++ b/tnet/files/conflatorio/bird-tnet-pre.conf
@@ -0,0 +1,20 @@
+define tnet = fdb1:4242:3538:2000::/52;
+
+function is_tnet() -> bool
+{
+ return net ~ tnet;
+}
+
+roa6 table dn42_roa;
+
+protocol static {
+ roa6 { table dn42_roa; };
+ include "/etc/bird/dn42_roa_bird2_6.conf";
+};
+
+function dn42_is_valid_network() -> bool
+{
+ return net ~ [
+ fd00::/8{44,64} # ULA address space as per RFC 4193
+ ];
+}
diff --git a/tnet/files/conflatorio/bird-tnet.conf b/tnet/files/conflatorio/bird-tnet.conf
new file mode 100644
index 0000000..02780a6
--- /dev/null
+++ b/tnet/files/conflatorio/bird-tnet.conf
@@ -0,0 +1,48 @@
+# Set to true if this peer is directly connected to a dn42 peer
+define is_dn42_peer = true;
+# If we are connected directly to dn42, we don't want the dn42 routes from others
+define import_dn42 = !is_dn42_peer;
+define export_dn42 = is_dn42_peer;
+
+template bgp tnet_tpl {
+ local as 4242423538;
+ neighbor internal;
+
+ direct;
+
+ password "trygvis";
+
+ ipv6 {
+ next hop self;
+ import filter {
+ if is_tnet() then {
+ accept proto, ": (tnet) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if import_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": import reject, reason=not tnet";
+ }
+ };
+ # newer bird's only
+ # import keep filtered;
+ export filter {
+ if is_tnet() then {
+ accept proto, ": (tnet) export accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if export_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": export reject, reason=not tnet";
+ }
+ };
+ };
+}
+
+protocol bgp tnet_hash from tnet_tpl {
+ neighbor fe80:4540:476c:d432:2f32:818b:811b:bb61;
+ interface "tnet-hash";
+}
+
+protocol bgp tnet_knot from tnet_tpl {
+ neighbor fe80:47fc:0660:b91f:1063:a6ae:46bb:7589;
+ interface "tnet-knot";
+}
diff --git a/tnet/files/coregonus/bird-tnet-pre.conf b/tnet/files/coregonus/bird-tnet-pre.conf
new file mode 100644
index 0000000..d60e8df
--- /dev/null
+++ b/tnet/files/coregonus/bird-tnet-pre.conf
@@ -0,0 +1,20 @@
+define tnet = fdb1:4242:3538:2000::/52;
+
+function is_tnet() -> bool
+{
+ return net ~ tnet;
+}
+
+roa6 table dn42_roa;
+
+protocol static {
+ roa6 { table dn42_roa; };
+ include "/etc/bird/dn42_roa_bird2_6.conf";
+};
+
+function dn42_is_valid_network() -> bool
+{
+ return net ~ [
+ fd00::/8{44,64} # ULA address space as per RFC 4193
+ ];
+}
diff --git a/tnet/files/coregonus/bird-tnet.conf b/tnet/files/coregonus/bird-tnet.conf
new file mode 100644
index 0000000..95ede41
--- /dev/null
+++ b/tnet/files/coregonus/bird-tnet.conf
@@ -0,0 +1,43 @@
+# Set to true if this peer is directly connected to a dn42 peer
+define is_dn42_peer = true;
+# If we are connected directly to dn42, we don't want the dn42 routes from others
+define import_dn42 = !is_dn42_peer;
+define export_dn42 = is_dn42_peer;
+
+template bgp tnet_tpl {
+ local as 4242423538;
+ neighbor internal;
+
+ direct;
+
+ password "trygvis";
+
+ ipv6 {
+ next hop self;
+ import filter {
+ if is_tnet() then {
+ accept proto, ": (tnet) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if import_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": import reject, reason=not tnet";
+ }
+ };
+ # newer bird's only
+ # import keep filtered;
+ export filter {
+ if is_tnet() then {
+ accept proto, ": (tnet) export accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if export_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": export reject, reason=not tnet";
+ }
+ };
+ };
+}
+
+protocol bgp tnet_knot from tnet_tpl {
+ neighbor fe80:ba82:77f0:f96d:7a85:a7fa:ef6f:37d2;
+ interface "tnet-knot";
+}
diff --git a/tnet/files/hash/bird-tnet-pre.conf b/tnet/files/hash/bird-tnet-pre.conf
index 7994dfe..74c981d 100644
--- a/tnet/files/hash/bird-tnet-pre.conf
+++ b/tnet/files/hash/bird-tnet-pre.conf
@@ -1,7 +1,20 @@
-define tnet = fdb1:4242:3538::/48;
-define tnet_router = fdb1:4242:3538:ffff::/64;
+define tnet = fdb1:4242:3538:2000::/52;
-function is_tnet() # -> bool
+function is_tnet()
{
- return net ~ tnet && ! (net ~ tnet_router);
+ return net ~ tnet;
+}
+
+roa6 table dn42_roa;
+
+protocol static {
+ roa6 { table dn42_roa; };
+ include "/etc/bird/dn42_roa_bird2_6.conf";
+};
+
+function dn42_is_valid_network()
+{
+ return net ~ [
+ fd00::/8{44,64} # ULA address space as per RFC 4193
+ ];
}
diff --git a/tnet/files/hash/bird-tnet.conf b/tnet/files/hash/bird-tnet.conf
index 16ce2cc..5ac9690 100644
--- a/tnet/files/hash/bird-tnet.conf
+++ b/tnet/files/hash/bird-tnet.conf
@@ -1,3 +1,9 @@
+# Set to true if this peer is directly connected to a dn42 peer
+define is_dn42_peer = true;
+# If we are connected directly to dn42, we don't want the dn42 routes from others
+define import_dn42 = !is_dn42_peer;
+define export_dn42 = is_dn42_peer;
+
template bgp tnet_tpl {
local as 4242423538;
neighbor internal;
@@ -10,26 +16,30 @@ template bgp tnet_tpl {
next hop self;
import filter {
if is_tnet() then {
- print proto, ": import accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if import_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": import reject, reason=not tnet";
}
- print proto, ": import reject, reason=not tnet"; reject;
};
# newer bird's only
# import keep filtered;
export filter {
if is_tnet() then {
- print proto, ": export accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) export accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if export_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": export reject, reason=not tnet";
}
- print proto, ": export reject, reason=not tnet"; reject;
};
};
}
-protocol bgp tnet_astyanax from tnet_tpl {
- neighbor fe80:a0fd:89e4:42c6:f617:7398:abf4:b517;
- interface "tnet-astyanax";
+protocol bgp tnet_conflatorio from tnet_tpl {
+ neighbor fe80:4540:476c:d432:2f32:818b:811b:bb60;
+ interface "tnet-confltrio";
rr client;
}
diff --git a/tnet/files/knot/bird-tnet-pre.conf b/tnet/files/knot/bird-tnet-pre.conf
index 7994dfe..d60e8df 100644
--- a/tnet/files/knot/bird-tnet-pre.conf
+++ b/tnet/files/knot/bird-tnet-pre.conf
@@ -1,7 +1,20 @@
-define tnet = fdb1:4242:3538::/48;
-define tnet_router = fdb1:4242:3538:ffff::/64;
+define tnet = fdb1:4242:3538:2000::/52;
-function is_tnet() # -> bool
+function is_tnet() -> bool
{
- return net ~ tnet && ! (net ~ tnet_router);
+ return net ~ tnet;
+}
+
+roa6 table dn42_roa;
+
+protocol static {
+ roa6 { table dn42_roa; };
+ include "/etc/bird/dn42_roa_bird2_6.conf";
+};
+
+function dn42_is_valid_network() -> bool
+{
+ return net ~ [
+ fd00::/8{44,64} # ULA address space as per RFC 4193
+ ];
}
diff --git a/tnet/files/knot/bird-tnet.conf b/tnet/files/knot/bird-tnet.conf
index fcecc19..e774e31 100644
--- a/tnet/files/knot/bird-tnet.conf
+++ b/tnet/files/knot/bird-tnet.conf
@@ -1,3 +1,9 @@
+# Set to true if this peer is directly connected to a dn42 peer
+define is_dn42_peer = true;
+# If we are connected directly to dn42, we don't want the dn42 routes from others
+define import_dn42 = !is_dn42_peer;
+define export_dn42 = is_dn42_peer;
+
template bgp tnet_tpl {
local as 4242423538;
neighbor internal;
@@ -10,23 +16,41 @@ template bgp tnet_tpl {
next hop self;
import filter {
if is_tnet() then {
- print proto, ": import accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if import_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": import reject, reason=not tnet";
}
- print proto, ": import reject, reason=not tnet"; reject;
};
# newer bird's only
# import keep filtered;
export filter {
if is_tnet() then {
- print proto, ": export accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) export accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if export_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": export reject, reason=not tnet";
}
- print proto, ": export reject, reason=not tnet"; reject;
};
};
}
+protocol bgp tnet_conflatorio from tnet_tpl {
+ neighbor fe80:47fc:660:b91f:1063:a6ae:46bb:7588;
+ interface "tnet-confltrio";
+
+ rr client;
+}
+
+protocol bgp tnet_coregonus from tnet_tpl {
+ neighbor fe80:ba82:77f0:f96d:7a85:a7fa:ef6f:37d3;
+ interface "tnet-coregonus";
+
+ rr client;
+}
+
protocol bgp tnet_hash from tnet_tpl {
neighbor fe80:3b20:4cb0:5315:22a:c7de:a45b:8a7d;
interface "tnet-hash";
@@ -34,6 +58,20 @@ protocol bgp tnet_hash from tnet_tpl {
rr client;
}
+protocol bgp tnet_kv24ix from tnet_tpl {
+ neighbor fe80:fef1:078a:5b64:efd3:ae7b:d286:d7cf;
+ interface "tnet-kv24ix";
+
+ rr client;
+}
+
+protocol bgp tnet_lhn2pi from tnet_tpl {
+ neighbor fdb1:4242:3538:ffff:374e:2c7d:319e:e527;
+ interface "tnet-lhn2pi";
+
+ rr client;
+}
+
protocol bgp tnet_node1 from tnet_tpl {
neighbor fe80:58eb:3930:1815:2a6d:8918:70c9:96f3;
interface "tnet-node1";
@@ -47,3 +85,32 @@ protocol bgp tnet_node2 from tnet_tpl {
rr client;
}
+
+protocol bgp routedbits_lon1 {
+ local as 4242423538;
+ neighbor fe80::207;
+ neighbor as 4242420207;
+ interface "tnet-rtdbts_l1";
+
+ ipv6 {
+ import filter {
+ if dn42_is_valid_network() && (net !~ tnet) then {
+ # Check when unknown or invalid according to ROA
+ if (roa_check(dn42_roa, net, bgp_path.last) = ROA_VALID) then {
+ accept;
+ } else {
+ reject proto, "[dn42] ROA check failed for ", net, " ASN ", bgp_path.last;
+ }
+ } else {
+ reject proto, "[dn42] invalid dn42 network ", net, " ASN ", bgp_path.last;
+ }
+ };
+ export filter {
+ if net ~ tnet then {
+ accept proto, "[dn42] accepting export tnet: ", net;
+ } else {
+ reject proto, "[dn42] rejecting export: ", net;
+ }
+ };
+ };
+}
diff --git a/tnet/files/lhn2pi/bird-tnet-pre.conf b/tnet/files/lhn2pi/bird-tnet-pre.conf
index 7994dfe..74c981d 100644
--- a/tnet/files/lhn2pi/bird-tnet-pre.conf
+++ b/tnet/files/lhn2pi/bird-tnet-pre.conf
@@ -1,7 +1,20 @@
-define tnet = fdb1:4242:3538::/48;
-define tnet_router = fdb1:4242:3538:ffff::/64;
+define tnet = fdb1:4242:3538:2000::/52;
-function is_tnet() # -> bool
+function is_tnet()
{
- return net ~ tnet && ! (net ~ tnet_router);
+ return net ~ tnet;
+}
+
+roa6 table dn42_roa;
+
+protocol static {
+ roa6 { table dn42_roa; };
+ include "/etc/bird/dn42_roa_bird2_6.conf";
+};
+
+function dn42_is_valid_network()
+{
+ return net ~ [
+ fd00::/8{44,64} # ULA address space as per RFC 4193
+ ];
}
diff --git a/tnet/files/lhn2pi/bird-tnet.conf b/tnet/files/lhn2pi/bird-tnet.conf
index 864ad0b..a4498cd 100644
--- a/tnet/files/lhn2pi/bird-tnet.conf
+++ b/tnet/files/lhn2pi/bird-tnet.conf
@@ -1,3 +1,9 @@
+# Set to true if this peer is directly connected to a dn42 peer
+define is_dn42_peer = true;
+# If we are connected directly to dn42, we don't want the dn42 routes from others
+define import_dn42 = !is_dn42_peer;
+define export_dn42 = is_dn42_peer;
+
template bgp tnet_tpl {
local as 4242423538;
neighbor internal;
@@ -10,29 +16,23 @@ template bgp tnet_tpl {
next hop self;
import filter {
if is_tnet() then {
- print proto, ": import accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if import_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": import reject, reason=not tnet";
}
- print proto, ": import reject, reason=not tnet"; reject;
};
# newer bird's only
# import keep filtered;
export filter {
if is_tnet() then {
- print proto, ": export accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) export accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if export_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": export reject, reason=not tnet";
}
- print proto, ": export reject, reason=not tnet"; reject;
};
};
}
-
-protocol bgp tnet_hash from tnet_tpl {
- neighbor fe80:6195:1d43:9655:35f7:9dba:798c:26b8;
- interface "tnet-hash";
-}
-
-protocol bgp tnet_knot from tnet_tpl {
- neighbor fdb1:4242:3538:ffff:374e:2c7d:319e:e526;
- interface "tnet-knot";
-}
diff --git a/tnet/files/node1/bird-tnet-pre.conf b/tnet/files/node1/bird-tnet-pre.conf
index 7994dfe..74c981d 100644
--- a/tnet/files/node1/bird-tnet-pre.conf
+++ b/tnet/files/node1/bird-tnet-pre.conf
@@ -1,7 +1,20 @@
-define tnet = fdb1:4242:3538::/48;
-define tnet_router = fdb1:4242:3538:ffff::/64;
+define tnet = fdb1:4242:3538:2000::/52;
-function is_tnet() # -> bool
+function is_tnet()
{
- return net ~ tnet && ! (net ~ tnet_router);
+ return net ~ tnet;
+}
+
+roa6 table dn42_roa;
+
+protocol static {
+ roa6 { table dn42_roa; };
+ include "/etc/bird/dn42_roa_bird2_6.conf";
+};
+
+function dn42_is_valid_network()
+{
+ return net ~ [
+ fd00::/8{44,64} # ULA address space as per RFC 4193
+ ];
}
diff --git a/tnet/files/node1/bird-tnet.conf b/tnet/files/node1/bird-tnet.conf
index 88bd6f8..6449582 100644
--- a/tnet/files/node1/bird-tnet.conf
+++ b/tnet/files/node1/bird-tnet.conf
@@ -1,3 +1,9 @@
+# Set to true if this peer is directly connected to a dn42 peer
+define is_dn42_peer = true;
+# If we are connected directly to dn42, we don't want the dn42 routes from others
+define import_dn42 = !is_dn42_peer;
+define export_dn42 = is_dn42_peer;
+
template bgp tnet_tpl {
local as 4242423538;
neighbor internal;
@@ -10,19 +16,23 @@ template bgp tnet_tpl {
next hop self;
import filter {
if is_tnet() then {
- print proto, ": import accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if import_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": import reject, reason=not tnet";
}
- print proto, ": import reject, reason=not tnet"; reject;
};
# newer bird's only
# import keep filtered;
export filter {
if is_tnet() then {
- print proto, ": export accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) export accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if export_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": export reject, reason=not tnet";
}
- print proto, ": export reject, reason=not tnet"; reject;
};
};
}
diff --git a/tnet/files/node2/bird-tnet-pre.conf b/tnet/files/node2/bird-tnet-pre.conf
index 7994dfe..74c981d 100644
--- a/tnet/files/node2/bird-tnet-pre.conf
+++ b/tnet/files/node2/bird-tnet-pre.conf
@@ -1,7 +1,20 @@
-define tnet = fdb1:4242:3538::/48;
-define tnet_router = fdb1:4242:3538:ffff::/64;
+define tnet = fdb1:4242:3538:2000::/52;
-function is_tnet() # -> bool
+function is_tnet()
{
- return net ~ tnet && ! (net ~ tnet_router);
+ return net ~ tnet;
+}
+
+roa6 table dn42_roa;
+
+protocol static {
+ roa6 { table dn42_roa; };
+ include "/etc/bird/dn42_roa_bird2_6.conf";
+};
+
+function dn42_is_valid_network()
+{
+ return net ~ [
+ fd00::/8{44,64} # ULA address space as per RFC 4193
+ ];
}
diff --git a/tnet/files/node2/bird-tnet.conf b/tnet/files/node2/bird-tnet.conf
index 99dfc5e..b9a2294 100644
--- a/tnet/files/node2/bird-tnet.conf
+++ b/tnet/files/node2/bird-tnet.conf
@@ -1,3 +1,9 @@
+# Set to true if this peer is directly connected to a dn42 peer
+define is_dn42_peer = true;
+# If we are connected directly to dn42, we don't want the dn42 routes from others
+define import_dn42 = !is_dn42_peer;
+define export_dn42 = is_dn42_peer;
+
template bgp tnet_tpl {
local as 4242423538;
neighbor internal;
@@ -10,19 +16,23 @@ template bgp tnet_tpl {
next hop self;
import filter {
if is_tnet() then {
- print proto, ": import accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if import_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": import reject, reason=not tnet";
}
- print proto, ": import reject, reason=not tnet"; reject;
};
# newer bird's only
# import keep filtered;
export filter {
if is_tnet() then {
- print proto, ": export accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) export accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if export_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": export reject, reason=not tnet";
}
- print proto, ": export reject, reason=not tnet"; reject;
};
};
}
diff --git a/tnet/host_vars/conflatorio/bird.yml b/tnet/host_vars/conflatorio/bird.yml
new file mode 100644
index 0000000..a976306
--- /dev/null
+++ b/tnet/host_vars/conflatorio/bird.yml
@@ -0,0 +1,5 @@
+tnet_bird_peers:
+ hash:
+ knot:
+
+birdv: 2015
diff --git a/tnet/host_vars/conflatorio/wg.yml b/tnet/host_vars/conflatorio/wg.yml
new file mode 100644
index 0000000..087441b
--- /dev/null
+++ b/tnet/host_vars/conflatorio/wg.yml
@@ -0,0 +1,7 @@
+tnet_wg:
+ knot:
+ endpoint: knot.inamo.no:51010
+ address: fe80:47fc:660:b91f:1063:a6ae:46bb:7588
+ hash:
+ endpoint: hash.trygvis.io:51007
+ address: fe80:4540:476c:d432:2f32:818b:811b:bb60
diff --git a/tnet/host_vars/coregonus/bird.yml b/tnet/host_vars/coregonus/bird.yml
new file mode 100644
index 0000000..816b95a
--- /dev/null
+++ b/tnet/host_vars/coregonus/bird.yml
@@ -0,0 +1,4 @@
+tnet_bird_peers:
+ knot:
+
+birdv: 2015
diff --git a/tnet/host_vars/coregonus/wg.yml b/tnet/host_vars/coregonus/wg.yml
new file mode 100644
index 0000000..0d80a18
--- /dev/null
+++ b/tnet/host_vars/coregonus/wg.yml
@@ -0,0 +1,5 @@
+tnet_wg:
+ knot:
+ endpoint: knot.inamo.no:51011
+ address: fe80:ba82:77f0:f96d:7a85:a7fa:ef6f:37d3
+
diff --git a/tnet/host_vars/hash/bird.yml b/tnet/host_vars/hash/bird.yml
index 17cb4cd..663f8e1 100644
--- a/tnet/host_vars/hash/bird.yml
+++ b/tnet/host_vars/hash/bird.yml
@@ -1,6 +1,7 @@
tnet_bird_peers:
- astyanax:
+ conflatorio:
rr_client: true
+ interface: tnet-confltrio
knot:
rr_client: true
node1:
diff --git a/tnet/host_vars/hash/wg.yml b/tnet/host_vars/hash/wg.yml
index c7d9363..5754f57 100644
--- a/tnet/host_vars/hash/wg.yml
+++ b/tnet/host_vars/hash/wg.yml
@@ -19,3 +19,7 @@ tnet_wg:
node2:
port: 51006
address: fe80:a7a6:c1a8:c261:232e:7d67:fc27:7c8c
+ conflatorio:
+ if_name: confltrio
+ port: 51007
+ address: fe80:4540:476c:d432:2f32:818b:811b:bb61
diff --git a/tnet/host_vars/knot/bird.yml b/tnet/host_vars/knot/bird.yml
index 0c1d73b..94c610a 100644
--- a/tnet/host_vars/knot/bird.yml
+++ b/tnet/host_vars/knot/bird.yml
@@ -1,7 +1,23 @@
tnet_bird_peers:
+ conflatorio:
+ rr_client: true
+ interface: tnet-confltrio
+ coregonus:
+ rr_client: true
hash:
rr_client: true
+ kv24ix:
+ rr_client: true
node1:
rr_client: true
node2:
rr_client: true
+ lhn2pi:
+ rr_client: true
+ routedbits_lon1:
+ policy: dn42
+ as: 4242420207
+ address: fe80::207
+ interface: tnet-rtdbts_l1
+
+birdv: 2015
diff --git a/tnet/host_vars/knot/wg.yml b/tnet/host_vars/knot/wg.yml
index 6fe932e..243c9f2 100644
--- a/tnet/host_vars/knot/wg.yml
+++ b/tnet/host_vars/knot/wg.yml
@@ -9,7 +9,7 @@ tnet_wg:
address: fdb1:4242:3538:ffff:18b7:d3ec:5608:db9a
kv24ix:
port: 51003
- address: fdb1:4242:3538:ffff:ea4:11cb:863:5252
+ address: fe80:fef1:078a:5b64:efd3:ae7b:d286:d7ce
akili:
port: 51004
address: fdb1:4242:3538:ffff:59d7:cf77:8b5d:761a
@@ -26,3 +26,15 @@ tnet_wg:
node2:
port: 51008
address: fe80:9dd8:abac:cf05:aea3:dc03:4c74:32da
+ rtdbts_l1:
+ port: 51009
+ address: fe80::621b:7ccf:ff44:c42c
+ endpoint: router.lon1.routedbits.com:53538
+ conflatorio:
+ if_name: confltrio
+ port: 51010
+ address: fe80:47fc:0660:b91f:1063:a6ae:46bb:7589
+ coregonus:
+ if_name: coregonus
+ port: 51011
+ address: fe80:ba82:77f0:f96d:7a85:a7fa:ef6f:37d2
diff --git a/tnet/host_vars/kv24ix/wg.yml b/tnet/host_vars/kv24ix/wg.yml
index 9cfdc5d..99c54b6 100644
--- a/tnet/host_vars/kv24ix/wg.yml
+++ b/tnet/host_vars/kv24ix/wg.yml
@@ -1,2 +1,3 @@
tnet_wg:
knot:
+ address: fe80:fef1:078a:5b64:efd3:ae7b:d286:d7cf
diff --git a/tnet/host_vars/lhn2pi/bird.yml b/tnet/host_vars/lhn2pi/bird.yml
index b59526c..d132dd7 100644
--- a/tnet/host_vars/lhn2pi/bird.yml
+++ b/tnet/host_vars/lhn2pi/bird.yml
@@ -1,3 +1,3 @@
-tnet_bird_peers:
- hash:
- knot:
+tnet_bird_peers: []
+# hash:
+# knot:
diff --git a/tnet/keys/wg-conflatorio-hash.pub b/tnet/keys/wg-conflatorio-hash.pub
new file mode 100644
index 0000000..8a27ee5
--- /dev/null
+++ b/tnet/keys/wg-conflatorio-hash.pub
@@ -0,0 +1 @@
+9o91CH8mx6OhTYer+gTMzwEfp94O4dSEOFuEKy/B+Ew=
diff --git a/tnet/keys/wg-conflatorio-hash.sops.key b/tnet/keys/wg-conflatorio-hash.sops.key
new file mode 100644
index 0000000..8c17e7c
--- /dev/null
+++ b/tnet/keys/wg-conflatorio-hash.sops.key
@@ -0,0 +1,28 @@
+{
+ "data": "ENC[AES256_GCM,data:4wFMiJhThT4ORoE/AdIRiN9EHr5NbSwysfhWCJxsLN6o7W3cMPA15E6ABnzk,iv:ib383CRTa7gCsC+RYAaJYV6TN8WMAPDJlQmlA2yUVow=,tag:LhhzRZGgYyviy7UTEeJbaQ==,type:str]",
+ "sops": {
+ "kms": null,
+ "gcp_kms": null,
+ "azure_kv": null,
+ "hc_vault": null,
+ "age": [
+ {
+ "recipient": "age13wv3rp0varlg4nvt3tca48fq8u9q3mc6yfdekjeapcmc7kaq4dysrzcmv3",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaMDhIREx3emlWdUgvQ0RW\nRnEvV0g4OWJkMmVSSHZaNzRLQTkvS1R0d1JnCk8xM0hMbWdEWlVhRklLeTNJYk9i\ncGtOL0huM29aU3dSNG92elJlV0k4ZncKLS0tIDVGcDBLbTI5Y1lUeFFJeGMrMm80\nQlFoTjRiVEh6UndoMHkvS3ptN3ZYc0EKfjcibzyYgYbZDTkz5g+FyxFFIFlU5LLL\nWGtyCal+2zl+h3z3vn4WUyHcj6BTqe3ks2zeyYWwiNuoTb1tSzj94Q==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1mvh832crygenu5tu5njtraraet656rzwnawuasjggvs999dc9ueqj9qclw",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzaFIwSDg0ZFNPZXdNOUxh\nSGdqYk1CaUpmVGg3YW1waTJFaUNtUHloTGtvClAxdmJnK1FLNStKdzBNTXo0TEpL\nbTZhcTVMR202QXBkV2VTcDJ6Z2Fqak0KLS0tIG9hb2M0b1NaRWMwaGl3UXZKWTU0\nN0lyM0dudDJsSm9HRzlxempMWEdlcncK4OG+Qrsn06Dl+wxk6SCg5dULZvZpDemE\n+MT6qbu74mgcS07PuzrCguueCC5mNBsjy8WanPQDRnzWqX+DzBxeDQ==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1teasctdpkatekpsa47q58d3ugwyyqcuj5v9udtusk7ca9sfv694sw057a5",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnMVp2SGdMTWFVd2U0MjVq\ndksvVFJvYUp3U2RyZHhOSERxNXZtSTBpSW5jClJWTkt0QmF1RU9hRExJb0wyNGxt\nK2ZzTnpOcU1BcElXT2wxd1o1R1VyTHcKLS0tIEJqOUVwY0h3VWxrc3F5aHluTHJJ\nckNlVzJJMHJkRXZPbER6ZXg5Z2xVa0kKByXn7yYIHY8Ckhr83tBYv062UDyBOYMS\nJ+dfYZ0ouT58l5CyatLURhyEDohAvQI95eKsIM1KkPgpzvV97Uq31Q==\n-----END AGE ENCRYPTED FILE-----\n"
+ }
+ ],
+ "lastmodified": "2024-08-11T19:04:11Z",
+ "mac": "ENC[AES256_GCM,data:TroGIp1ZphoyDZXYxPbMpnCbq8i3v4eaT/8jlPnlFbCcHWqId2Tp2sBLlwuaq3E+vhvmN1K7ndbevCUhWmJW4oyWiEWXGUC3TUtVwc2nw3En/jsXFX9Yp7opF+a3iR+NLCbGTxm2CcQPoxuayAUIIp78ITB61SSF9QzIuAAhmcw=,iv:E3yB6yF3TDN8WPP+Kq78bK36Qw70Oz4Hl9lc7vhstnM=,tag:94udYmA1spcHcZMzylNA0w==,type:str]",
+ "pgp": null,
+ "unencrypted_suffix": "_unencrypted",
+ "version": "3.7.3"
+ }
+} \ No newline at end of file
diff --git a/tnet/keys/wg-conflatorio-knot.pub b/tnet/keys/wg-conflatorio-knot.pub
new file mode 100644
index 0000000..053a7d6
--- /dev/null
+++ b/tnet/keys/wg-conflatorio-knot.pub
@@ -0,0 +1 @@
+T6Gst6C4i8c1JDEdlWL4EMnkabEjUBfj9Ii6RiLU30c=
diff --git a/tnet/keys/wg-conflatorio-knot.sops.key b/tnet/keys/wg-conflatorio-knot.sops.key
new file mode 100644
index 0000000..973726d
--- /dev/null
+++ b/tnet/keys/wg-conflatorio-knot.sops.key
@@ -0,0 +1,28 @@
+{
+ "data": "ENC[AES256_GCM,data:X2V545B0R61+kZty3UEsBH83JytzpPCLMLpvgbct8+818EItkbhCiowJj01t,iv:ADEd0FZUSQPWuza8lL5Ld12j3nRfrewNxjMqwOfwA0Q=,tag:t/2Yg8XxOpCovgRn6zwztA==,type:str]",
+ "sops": {
+ "kms": null,
+ "gcp_kms": null,
+ "azure_kv": null,
+ "hc_vault": null,
+ "age": [
+ {
+ "recipient": "age13wv3rp0varlg4nvt3tca48fq8u9q3mc6yfdekjeapcmc7kaq4dysrzcmv3",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvTTdzekJDdEhuKzhEUitG\nSU5qYVI3TURHTXUySk5Xenowc2FpczFDM3lJClI0L1huRVhGWjB3N0ZzQ2VoNEI1\nWVJtRCtJWmkyb0c5M2RVeS9IaytmU0EKLS0tIHdUNExJTGhqckVvSzhhTFFFTDhE\nQXY4NzlwM0FJbW41RFlRTXZIcnlBZ00KFN8m0pMUkNUoaUGTforKg4VMDL0qbs/J\nsPVXbJf9n+GTEn7qeqOvMDHW9hj5s8zQOyeNNt8k1PkmNjHbxNNolw==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1mvh832crygenu5tu5njtraraet656rzwnawuasjggvs999dc9ueqj9qclw",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4RjNEdWQ5dnlzY2dubU5a\nTVN0ZFhOd2RrcGVrYjRKZzRBRVk5dHVSdDI4ClgyS1ZJUDVYQ2MzN2haWEZ4VTJj\nem5jYWdnYmpWMWhjREdBcHltTWV5YmsKLS0tIG5yVkt3em8weUVZTzY4N2JBOFo2\neUQ0M1JCL2RXTTlCc1RxakpjQzBXZDAKa+gNtS/eL3rdNp7Jl52EHcVfBzdVcezL\n8VawKcdVaFU8pXi2wSRjSJlVf4jESjTFC9dip3hAxM7R/V9M/SxXkg==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1teasctdpkatekpsa47q58d3ugwyyqcuj5v9udtusk7ca9sfv694sw057a5",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpdlNaM2RPYWZMMDh4V1Ew\nMkRIM2dTNktpYUxPWC9jcFFYeHcraTV1b2tvCk11RVZxMkdvd21ORWlXKzdrUm5w\nYUdZVTB2dmk3ZjFiaUlzdG54dmJpMDgKLS0tIDJwYWFGQmp2YXh6Z1BUMGdkWFNR\nemcwUHp1MjRobjh4ZEkyZjRzWDBFaGcK1EIKbWoR7dBHy/r0o2V9VxYaN9XJx5x4\n1fLZALfTA5C3kJgcuJbzhNUqvIwcKJ0LXpENidEHbAuZBTDzl0lYTQ==\n-----END AGE ENCRYPTED FILE-----\n"
+ }
+ ],
+ "lastmodified": "2024-08-11T19:04:13Z",
+ "mac": "ENC[AES256_GCM,data:czGSSuK2RW0cIeJ4WRyu87EINudH8/tlwAxuALcTuvMWnzJ2B4kap9BAesCOw5FuZHzc4dGulmzrVbbH1pBg8REaWvy7989ELvNDFLyFqOc54XPfDuDMjT6D2SGw+2y6mB3kg0r1ajd3SASfhvc1q/8K1R2NZiO5xSG1ybbqlUM=,iv:VJVsV+xpL0gvXnlZjpZeljtqcJgLXl/+Rtkj0iBmBQ0=,tag:cqEbeEp4uc/vTjNaASnkDQ==,type:str]",
+ "pgp": null,
+ "unencrypted_suffix": "_unencrypted",
+ "version": "3.7.3"
+ }
+} \ No newline at end of file
diff --git a/tnet/keys/wg-coregonus-knot.pub b/tnet/keys/wg-coregonus-knot.pub
new file mode 100644
index 0000000..181fd56
--- /dev/null
+++ b/tnet/keys/wg-coregonus-knot.pub
@@ -0,0 +1 @@
+uOqXlYKRgwBXVKPAaPn2fx4YtMHCH5M2qQ3hs/tZwms=
diff --git a/tnet/keys/wg-coregonus-knot.sops.key b/tnet/keys/wg-coregonus-knot.sops.key
new file mode 100644
index 0000000..b3c6239
--- /dev/null
+++ b/tnet/keys/wg-coregonus-knot.sops.key
@@ -0,0 +1,28 @@
+{
+ "data": "ENC[AES256_GCM,data:aPPYaRDzczKgMZxWKJXE5X7JC0pQxs9W0d3UZjY8QYLhxmxk8L+RpX6zWscR,iv:CE+JgwUMdkbFDrkk53ow77ehm3GEmeJFnVM5jbWXZIY=,tag:mlnV5SNhIOnU/+TnOWiU0g==,type:str]",
+ "sops": {
+ "kms": null,
+ "gcp_kms": null,
+ "azure_kv": null,
+ "hc_vault": null,
+ "age": [
+ {
+ "recipient": "age13wv3rp0varlg4nvt3tca48fq8u9q3mc6yfdekjeapcmc7kaq4dysrzcmv3",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMWml3V0dCRStJY0RsUEN5\nSVhya1dXYW5GQ0R1a1h3NVJMV09LbVV1eXhNCmFMS2JYVzVPbS95TmwxWG04emtO\nd3B5QUtxWGVaWTlpUDN4ZVErZ1BqcEEKLS0tIE9iTjJaN0RaZjJQeG5Zd1Z5Ylp1\nYkwxS0JqVzNLNHBkSjM0b2owcURZN1UKj5i3uMAwhcqM/vB6faF2vq3ndEYGEOAn\nH1m4LdRj0b03BOtz5vz5oeF+nW3e8rGwhq84N7UFdI4W+9w3ZCI2AQ==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1mvh832crygenu5tu5njtraraet656rzwnawuasjggvs999dc9ueqj9qclw",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMVGdPaERQRWNodnpmOUFM\nWG1QSGhJUmoyamplMFFsK3krNzd4ZHVvdlY0Cit3UHNzNUVIVWlZakNsTUFNVlA1\neE9rNTliWmZ0a295UVJZUXo3dk9WTkkKLS0tIDE2SjE1bXFVdno5NkwwQk15UGZY\nczBPTTUwdTBJT0laWWJsWmJmNDFuUG8KRlCmMio144qdPuPXuxc2AEHhdUxbJT8W\nDp7Atk0G57V57tX/zk1RaXjp+ORStvwpgDAdCwmikt1PW78Y6x77tQ==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1teasctdpkatekpsa47q58d3ugwyyqcuj5v9udtusk7ca9sfv694sw057a5",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpYWlHRUVTV1RreFExcDBj\nYmI3OTBpRnEwd0FBTDdPTHI1OVhRYmlZMGdFCjlHTWJPY0lSRVhPSTQyNEgxYkMy\nY3ljMnhKeURSL2JwcDd3dmlubW15bFEKLS0tIEZHUG9NUmNnUlh2NjlTd1RsYytR\nVDI0OVhZeGhyWFVFcU9URE1NRXpnR00KUO2W8ab2RehPhEAjFlOXWrr2rn55gBR5\neSvOtAPEEV1lWO+O0r3jOFpnUI/ahgPeBhMoLFOdionm3GPrYzf8aQ==\n-----END AGE ENCRYPTED FILE-----\n"
+ }
+ ],
+ "lastmodified": "2024-08-20T22:51:59Z",
+ "mac": "ENC[AES256_GCM,data:4haVcOm18uCW8LK06wURyf32qr9ZXnjc6feJHf4T85C0COrmZ7AmxUZKt5Mi9YoPO7dTMpjcvnxhEVEP4x6/wBc3SB5RpRSWU25GZ4/ofnqR/xBH0R1edirQtuhsDJeR3rYnTYeMjRltf9zpZknED907GRmmddaO15xsWtU8/t8=,iv:wXMIQRj4mV7SNnUqC3XVM/8mEhbPMwL1Z4/LrIBqpcs=,tag:i6CSlmj2449GgMqosa8e0A==,type:str]",
+ "pgp": null,
+ "unencrypted_suffix": "_unencrypted",
+ "version": "3.7.3"
+ }
+} \ No newline at end of file
diff --git a/tnet/keys/wg-hash-conflatorio.pub b/tnet/keys/wg-hash-conflatorio.pub
new file mode 100644
index 0000000..bf16a1c
--- /dev/null
+++ b/tnet/keys/wg-hash-conflatorio.pub
@@ -0,0 +1 @@
+oGEr7UWht1fUQ92hRu5r9SdRPfqj462behU34s6500o=
diff --git a/tnet/keys/wg-hash-conflatorio.sops.key b/tnet/keys/wg-hash-conflatorio.sops.key
new file mode 100644
index 0000000..c78eebc
--- /dev/null
+++ b/tnet/keys/wg-hash-conflatorio.sops.key
@@ -0,0 +1,28 @@
+{
+ "data": "ENC[AES256_GCM,data:LLC57pLBVZNEOTDdSEF4JgjGS8nLm/ef4ds71IFRJOX5tnnC9D/0hgbjdncF,iv:OU8/eGbM0axRajBOplvycs5rr100QPMv4RXYTv5NJMs=,tag:7IH46V36BbbhvCs5ze4UJQ==,type:str]",
+ "sops": {
+ "kms": null,
+ "gcp_kms": null,
+ "azure_kv": null,
+ "hc_vault": null,
+ "age": [
+ {
+ "recipient": "age13wv3rp0varlg4nvt3tca48fq8u9q3mc6yfdekjeapcmc7kaq4dysrzcmv3",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEdjRCWlQ5OVI0cTkwL3Ey\nWG5tYUdNSks1UkpROU0wVUVVMlhwWEdweXpvCmFQYTE2bkZlV1BlZXg2d3pia0Jr\nVFhQVElXUjJCVGRXS2R4aEhBdzFBNU0KLS0tIEUzaHQxbzQ4aml0VHBaU0MyMjhJ\ncHo4L0doL1NKa0VOc21PanhhdUh2UGcKetAIpPpINd6UgrHYvTh/o5w4DlTlNY2c\n94zKEsWGShRZDOJ2EWiYR+47+OLTZjRKpt/oyXBhnyTa4gBSsNwHHg==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1mvh832crygenu5tu5njtraraet656rzwnawuasjggvs999dc9ueqj9qclw",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCeTBwdU9iOGhaWThqOVN2\ndG1qUW43eW83NS9sQ0ExbnlIY0s3TlVQdlJJClJHeDloOTk2WFBPNitZQ3BXaFR0\nNVNCTncyV0RqVFJ4S2ZGWUt0RThHYWsKLS0tIDBxaVBXNjdlTXRsYlN5aWhnQkJ5\nd3pyS3preFRBWVF1eUE3eUYrZ2F6aDQKU447p1FB1bX98Ni3oQnhkRdM1al0ySvk\nSeApyf3gKO5BhtQkQKuMF2lRGQEJ8Vh4H0mxf8cTspCn4rld0T2P7w==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1teasctdpkatekpsa47q58d3ugwyyqcuj5v9udtusk7ca9sfv694sw057a5",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXMjYwbHpkT0xWTDhzd3ZD\nRko0NXlZU1MwcmhCdGtCdFJ5SnAvVU1VK244CkY5VWRDVFhZUUdzMFpFR00vMlRv\nNmxUYjg2azcrRnBkQ09BVXlxeTYzRkkKLS0tIGljOTFnMll2RE1TWmpvMld2RWxu\nU2d0d2xwbWtZa3NoSUlXc3pnSHMraDQKYc02UngnR+mCVRKDxZy1VqiOW1AA9mEf\nf8XNX9CARGaAbXesOnj8ADKswErDOHrca4f1CbrgOWd9UM1qk6HyTw==\n-----END AGE ENCRYPTED FILE-----\n"
+ }
+ ],
+ "lastmodified": "2024-08-11T19:04:03Z",
+ "mac": "ENC[AES256_GCM,data:ja8qprE1psQHAQ+hw8UDXxFqDg+K3tSBq+Hvef4z4nKd4+v8lhIBjCXTE7b+ovmFzJhV4jEd761ugHsxkLUcThAWkuaVy82dmF8idgKwTxg1NKmn3dBGC1fRjOXGPmOvO6Y6dCbL2L1e7z3EoQP2SzgcVa1/g+QgtnWEcTkvXKk=,iv:062sBg8V5nSq10VbFNZ3z7+FZLwXvKyXGbZEpdCjpM0=,tag:DM0zH1chw7pn8d9LwLh1Gg==,type:str]",
+ "pgp": null,
+ "unencrypted_suffix": "_unencrypted",
+ "version": "3.7.3"
+ }
+} \ No newline at end of file
diff --git a/tnet/keys/wg-knot-conflatorio.pub b/tnet/keys/wg-knot-conflatorio.pub
new file mode 100644
index 0000000..dfbd2b3
--- /dev/null
+++ b/tnet/keys/wg-knot-conflatorio.pub
@@ -0,0 +1 @@
+N3BmA8j6VuY7hmB/lWN3OjUK9cgNoMSOZiPiuSAytgQ=
diff --git a/tnet/keys/wg-knot-conflatorio.sops.key b/tnet/keys/wg-knot-conflatorio.sops.key
new file mode 100644
index 0000000..4565d73
--- /dev/null
+++ b/tnet/keys/wg-knot-conflatorio.sops.key
@@ -0,0 +1,28 @@
+{
+ "data": "ENC[AES256_GCM,data:hDq6uKsf4/ZaLBtR+vW+ldTnupF0wGKYh1NwFuraHEs//9muJIcRwQ93Zhhd,iv:c/U1BRw2PdhWWFle7zYNOfjsvl7BYCbj2cKsc/vaHHI=,tag:pABhOJxuO7ARyfuCuqMwoA==,type:str]",
+ "sops": {
+ "kms": null,
+ "gcp_kms": null,
+ "azure_kv": null,
+ "hc_vault": null,
+ "age": [
+ {
+ "recipient": "age13wv3rp0varlg4nvt3tca48fq8u9q3mc6yfdekjeapcmc7kaq4dysrzcmv3",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkb2ppbEY3SVZqL1pLM1h6\nWUJaZE5IQlRGUWlSNHBDeVpHSDBrT0Ztb1hzCjVOUEMyUm5JN1lBaTEvRlRHL1BT\nOTV0aGtXRnAvNWNNTWJiNGMwaU9CWncKLS0tIC9ySXdyOURsODRXODVNbkFyZlVm\nUXFwWFI4RzIrZUVUV1MvVlJyYTlCeDQKnZuwumgHUEwiAMtEEarlPEMAFYBQDGeD\n6oRPWB3lkVl4C7RAGjG/vkvgSf7Wq71Fv24YDRtJddYgnqWRTp+d9w==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1mvh832crygenu5tu5njtraraet656rzwnawuasjggvs999dc9ueqj9qclw",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNVStFYkUwNVVUUG9mRHFp\nazZValA1d08rcWlyeVdFTFBSVEJmUGFZQjNnCmtTQW5oeVNmWW4rR3liZjRJRDBi\nbEQ1VVFRajluSXUzcUtObm0ySUZYMjgKLS0tIHcweUVNendleGl5WlY1eVN0ZFFF\nRGs0enc1b2MxV2RBQnljdHR6N0dMTWsKKERcoegcxCLeAc07a/H5+jA9NopzyYfD\nlZ3tsursdaZKWsCRgPpQJfqtZVbin61zDrxgGJRpVsVkmGtqFZHfyQ==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1teasctdpkatekpsa47q58d3ugwyyqcuj5v9udtusk7ca9sfv694sw057a5",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkUThmR0xCOE9NN2xHTm9j\naGxpUVVQRXRTMzM5d2R4Mk84RkVScFdRZ3hZCk10TWtwZ09zWkl4TTU3ZDhDNWxp\nVEErYk5ucUpvNUordGdiRWsyS04zY1kKLS0tIEcwSTVZdU1HNFRVS2NTbjM3bGxB\ndGZreWNNWnFGd3JCM3VHeTJDZi83TzAK+y28heVBf2Tl+9X8sgKuAcyzrHn038RM\nzTFnhy0sn5FmmPeAt+DaTI5L23d4h9rs9kMuqkyWFvZH5L1ZKPMC6Q==\n-----END AGE ENCRYPTED FILE-----\n"
+ }
+ ],
+ "lastmodified": "2024-08-11T19:04:05Z",
+ "mac": "ENC[AES256_GCM,data:Wo9zqglEVWtnfqK9X513PexmbrHEVbcgWSIfvdBAGVT4SAT26yvWVoPzBH1Nt11iePBwkLSjut5+G0Zf5XvhCnWwM3oGqGFhXAJqx3ta3mJIAFwD8E8DDEzvsVy5KM9AZkPv+YFSz33OgtrgSX/8sKfcVYO0DzivwTXiYKEeS1M=,iv:qTyug6kkZCF16oAL6uFsMsMG4aTh5nN8L4+Z0m844LE=,tag:JKXI0oi8D+X0PVVFMInoag==,type:str]",
+ "pgp": null,
+ "unencrypted_suffix": "_unencrypted",
+ "version": "3.7.3"
+ }
+} \ No newline at end of file
diff --git a/tnet/keys/wg-knot-coregonus.pub b/tnet/keys/wg-knot-coregonus.pub
new file mode 100644
index 0000000..7fc1905
--- /dev/null
+++ b/tnet/keys/wg-knot-coregonus.pub
@@ -0,0 +1 @@
+lTuzdN+En+Jc8v9+cTx2U455mw6v+fl/QsWWxO7ZYgI=
diff --git a/tnet/keys/wg-knot-coregonus.sops.key b/tnet/keys/wg-knot-coregonus.sops.key
new file mode 100644
index 0000000..6acb9ef
--- /dev/null
+++ b/tnet/keys/wg-knot-coregonus.sops.key
@@ -0,0 +1,28 @@
+{
+ "data": "ENC[AES256_GCM,data:NhASCvnUd1DDdo8qQ8MNY+KXMa9fACx7DNEwNwwLgjuwSu+bV42z/OYTY6Ck,iv:z0mGt+HuBwuS+WnbuomGwqReCXqEfIC+qPOuz+JciSw=,tag:sCUW0nXWJWgxYEAbkp+7JQ==,type:str]",
+ "sops": {
+ "kms": null,
+ "gcp_kms": null,
+ "azure_kv": null,
+ "hc_vault": null,
+ "age": [
+ {
+ "recipient": "age13wv3rp0varlg4nvt3tca48fq8u9q3mc6yfdekjeapcmc7kaq4dysrzcmv3",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOTWY3a0xxbzJnVm1GRHdU\nZU1IcnhKQkdEVjBtNFRIb0swWHlqdldFSUR3Ckg4dGlERkV4Ly93YVRwSjBJdzB0\nS1hmSkNQY2ROdDBZVTVmODRUR2Z4bmMKLS0tIFh0ZDJ1d2ViMFVwNlRkY3d6eU5E\nbHVhSXVCRWI2b2NKVVI1cGVjL3RGaVEKgFzmd42NmzH4GH4Vuklcd1jkCJnngloO\nN4Q5/NdHij8fXWnhkuV/8xX7KnBXEGX5uHo9pYd1aYzyZTUD40rDyw==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1mvh832crygenu5tu5njtraraet656rzwnawuasjggvs999dc9ueqj9qclw",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0TmJ4UjZBN2pFU2dBZXdG\naDNtQUhGdkFnYkh5OXVlYTZ6c1N0YWpaTnpNCnZMWFgrWFpNd0tqVGpyN2NIZnlo\ncTRlQ1Q4UGJySm16TThwS0V1dW1nTlUKLS0tIGgzWjQvZ0hETW15TTV4S0Q1K1V5\naDFMODFVcVB4cmxnYXR5RTRnanQ0bVkKPZ/caVVhPQ/0I5X3A70czYnMNgw/l39W\nrf75d5RK5x5FcgZenz23l00g+AUt8uNfct+3YHc15OjL+vOrtm1NCQ==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1teasctdpkatekpsa47q58d3ugwyyqcuj5v9udtusk7ca9sfv694sw057a5",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjalBWcXg5NVlFS3Bjb0Vt\nUXlhNVNxMmtIMVhEdC8rb2h5UEJxUVpUckI0Ci9BaUM3YWJSczI1RVNQWGtIZllI\nQmhuK2dyMUwvRlpORUZDK2thWldUdFkKLS0tIDA2UVBzbTQ3aDEwcXNHcjRoMkNW\nRXhmZ3hmUlhVR0xzaWU1MDZBUW1zcTAKkkyLoqodk7FWwZV07wlkttEs115/v9ZI\nOVfi+VzkI++jLW2KzL1S1i1N+/BHnfXDnzNDaIqUTRrFi5jhd1kk0A==\n-----END AGE ENCRYPTED FILE-----\n"
+ }
+ ],
+ "lastmodified": "2024-08-20T23:20:12Z",
+ "mac": "ENC[AES256_GCM,data:l4s7OdTHRqBXVGHpCQMo/k6nwwPEcWK8J47n1b8pQSDuO4DFcB/ApI8rNKgFAujXLUwB10YeRwp0bcLdlGREt7PhcHhddNB5yRYx/8djqYpm0w3rSAN9p4IW5CNB5LmfdxQk2dI0Ow8wxw8UzTVO08T7cDNeYRZdQTJLd+VUhCo=,iv:Ffv/pz30FwLaho3Y2HlMO11jKIl71GUpKMe1cSMNOwo=,tag:Qo3ZSTnJa26jYdwJtGvmyQ==,type:str]",
+ "pgp": null,
+ "unencrypted_suffix": "_unencrypted",
+ "version": "3.7.3"
+ }
+} \ No newline at end of file
diff --git a/tnet/keys/wg-knot-rtdbts_l1.pub b/tnet/keys/wg-knot-rtdbts_l1.pub
new file mode 100644
index 0000000..4be8cef
--- /dev/null
+++ b/tnet/keys/wg-knot-rtdbts_l1.pub
@@ -0,0 +1 @@
+x/cvEG6uyatJEao1ob2aPGi7QGqY+2ShdtB/FTGlmAs= \ No newline at end of file
diff --git a/tnet/keys/wg-knot-rtdbts_l1.sops.key b/tnet/keys/wg-knot-rtdbts_l1.sops.key
new file mode 100644
index 0000000..e40eba9
--- /dev/null
+++ b/tnet/keys/wg-knot-rtdbts_l1.sops.key
@@ -0,0 +1,28 @@
+{
+ "data": "ENC[AES256_GCM,data:u95NnCXihKwyPP/ZujqZlCMgTI7j5DmTaFqrDa9Y3yc2uNystrCqdSqHZIQ=,iv:U6pvVRkDNx392kh3ofdfUVQ5Sf9hwa/HKNukkG5BvWg=,tag:Kb+uplrA41vB/FefskN5bA==,type:str]",
+ "sops": {
+ "kms": null,
+ "gcp_kms": null,
+ "azure_kv": null,
+ "hc_vault": null,
+ "age": [
+ {
+ "recipient": "age13wv3rp0varlg4nvt3tca48fq8u9q3mc6yfdekjeapcmc7kaq4dysrzcmv3",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmYy9GNDJWVkQ4MFpMQkFG\nRHZhemFySDFQUy9jR0ZaUkpXcTVNSkFid3p3ClZ0azRFUW82UjFyckNoM0RRNUhm\nMUpyNG04RVROQ0NibDRwb2ZxanYyMWMKLS0tIGVXdVJ2a1g1SU5LcFNMY1hVUU5X\nV0VYZ2pLNHpyUWEwSHJnTEdaWDFnV1UKi1U6BjgEjQT9KOMLajdDViKmb4XBSj1+\noTmdC1ZV2B4a/tlwRQjO0Rr3UoprPy+s4sKDIJNpbz9RcqxSU/voig==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1mvh832crygenu5tu5njtraraet656rzwnawuasjggvs999dc9ueqj9qclw",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBodGhUSnZZS0FpY1VqV0g3\nYVV0VW5OQUptckx1dVAwZjNLUHdtU3Q0S1dFCnh3RWlieU50a2c4SnRFYkFWcGNC\nOERSdG15VnQ4ZVZDZ3ErTW1nWGJQRVkKLS0tIHJPM3h6bEtwMGI3SGdHTFJiWFoy\nQUVGRm9JZzYwRkdmT0QzdUY5Z3F4V2cK7JhYdWfI3/PRKCyNCTbLj6gm9OkbkNzR\nVtLStGD0goqVNo1rpMecZxSqsypJgTmypbFl6tYClNKp5Ti33ptXqA==\n-----END AGE ENCRYPTED FILE-----\n"
+ },
+ {
+ "recipient": "age1teasctdpkatekpsa47q58d3ugwyyqcuj5v9udtusk7ca9sfv694sw057a5",
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHSzJ3cm45MXF0TEFPUHds\nVG9aSmd5REFweDdIbURhbU9HYmxURWV5WEhrCitXaFAvRFJ5eGk2cVB1YXAwRDNj\nMnFOaXFWd1VCdEl3SThqQ2N4U0pValUKLS0tIGdPK01VbFJac2JMMVlvWHNSd3lI\nbzVWRmZJTEpQamQ0Y2xXdk9aN3VPTTAKRtaOSu5GSw6lxG7ogYTx9AilqdeEcYGb\ngrWXPYPNfs7ePcItFSUiDiuS38eXpKCdfqjZmekBCxGCJQnuhMZZ6A==\n-----END AGE ENCRYPTED FILE-----\n"
+ }
+ ],
+ "lastmodified": "2024-06-16T20:30:33Z",
+ "mac": "ENC[AES256_GCM,data:SIbpVs2mmMlp8mfPr0vXI8ZSENuwIAslEcZHfFg7YfC9gcEHHFYq/ngeB62/8YBcOsYnhO9Sip3VvEg2MsdQe6if8asew67D0udPATrfHRhk55PIxLLb1DszlI8edAhH7PzcNRFSYy72mKvxK2eDeDw71sfBr73254jD6ud699s=,iv:6RUG4ZUGXWpV2CYGgFVI6SRSZRzNbNNQlbwLb0TS15c=,tag:KY0WAn+rW/xJjBUpHPq1Tw==,type:str]",
+ "pgp": null,
+ "unencrypted_suffix": "_unencrypted",
+ "version": "3.7.3"
+ }
+} \ No newline at end of file
diff --git a/tnet/keys/wg-routedbits_lon1-knot.pub b/tnet/keys/wg-routedbits_lon1-knot.pub
new file mode 100644
index 0000000..dd12e17
--- /dev/null
+++ b/tnet/keys/wg-routedbits_lon1-knot.pub
@@ -0,0 +1 @@
+vlqNoUSJ4T2sORBHusdwr9rCtQfdsIJvjV3Y/qBUcgY=
diff --git a/tnet/keys/wg-rtdbts_l1-knot.pub b/tnet/keys/wg-rtdbts_l1-knot.pub
new file mode 100644
index 0000000..dd12e17
--- /dev/null
+++ b/tnet/keys/wg-rtdbts_l1-knot.pub
@@ -0,0 +1 @@
+vlqNoUSJ4T2sORBHusdwr9rCtQfdsIJvjV3Y/qBUcgY=
diff --git a/tnet/templates/bird-tnet-pre.conf.j2 b/tnet/templates/bird-tnet-pre.conf.j2
index 7994dfe..e762cd5 100644
--- a/tnet/templates/bird-tnet-pre.conf.j2
+++ b/tnet/templates/bird-tnet-pre.conf.j2
@@ -1,7 +1,20 @@
-define tnet = fdb1:4242:3538::/48;
-define tnet_router = fdb1:4242:3538:ffff::/64;
+define tnet = {{ ipam6.networks.tnet_dn42.range }};
-function is_tnet() # -> bool
+function is_tnet(){{ " -> bool" if birdv >= 2015 }}
{
- return net ~ tnet && ! (net ~ tnet_router);
+ return net ~ tnet;
+}
+
+roa6 table dn42_roa;
+
+protocol static {
+ roa6 { table dn42_roa; };
+ include "/etc/bird/dn42_roa_bird2_6.conf";
+};
+
+function dn42_is_valid_network(){{ " -> bool" if birdv >= 2015 }}
+{
+ return net ~ [
+ fd00::/8{44,64} # ULA address space as per RFC 4193
+ ];
}
diff --git a/tnet/templates/bird-tnet.conf.j2 b/tnet/templates/bird-tnet.conf.j2
index 57e557a..2ba456b 100644
--- a/tnet/templates/bird-tnet.conf.j2
+++ b/tnet/templates/bird-tnet.conf.j2
@@ -1,3 +1,9 @@
+# Set to true if this peer is directly connected to a dn42 peer
+define is_dn42_peer = true;
+# If we are connected directly to dn42, we don't want the dn42 routes from others
+define import_dn42 = !is_dn42_peer;
+define export_dn42 = is_dn42_peer;
+
template bgp tnet_tpl {
local as 4242423538;
neighbor internal;
@@ -10,30 +16,73 @@ template bgp tnet_tpl {
next hop self;
import filter {
if is_tnet() then {
- print proto, ": import accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if import_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": import reject, reason=not tnet";
}
- print proto, ": import reject, reason=not tnet"; reject;
};
# newer bird's only
# import keep filtered;
export filter {
if is_tnet() then {
- print proto, ": export accept, net=", net, ", from=", from, ", gw=", gw;
- accept;
+ accept proto, ": (tnet) export accept, net=", net, ", from=", from, ", gw=", gw;
+ } else if export_dn42 && dn42_is_valid_network() then {
+ accept proto, ": (dn42) import accept, net=", net, ", from=", from, ", gw=", gw;
+ } else {
+ reject proto, ": export reject, reason=not tnet";
}
- print proto, ": export reject, reason=not tnet"; reject;
};
};
}
{% for p in tnet_bird_peers|default([])|sort %}
+{% set peer = tnet_bird_peers[p] %}
+{% set policy = peer.policy | default("tnet") %}
+{% if policy == "tnet" %}
protocol bgp tnet_{{ p }} from tnet_tpl {
neighbor {{ hostvars[p].tnet_wg[inventory_hostname].address }};
+{% if peer.interface is defined %}
+ interface "{{ peer.interface }}";
+{% else %}
interface "tnet-{{ p }}";
-{% if tnet_bird_peers[p].rr_client|default(False) %}
+{% endif %}
+{% if peer.rr_client|default(False) %}
rr client;
{% endif %}
}
+{% elif policy == "dn42" %}
+protocol bgp {{ p }} {
+ local as 4242423538;
+ neighbor {{ peer.address }};
+ neighbor as {{ peer.as }};
+{% if peer.interface is defined %}
+ interface "{{ peer.interface }}";
+{% endif %}
+
+ ipv6 {
+ import filter {
+ if dn42_is_valid_network() && (net !~ tnet) then {
+ # Check when unknown or invalid according to ROA
+ if (roa_check(dn42_roa, net, bgp_path.last) = ROA_VALID) then {
+ accept;
+ } else {
+ reject proto, "[dn42] ROA check failed for ", net, " ASN ", bgp_path.last;
+ }
+ } else {
+ reject proto, "[dn42] invalid dn42 network ", net, " ASN ", bgp_path.last;
+ }
+ };
+ export filter {
+ if net ~ tnet then {
+ accept proto, "[dn42] accepting export tnet: ", net;
+ } else {
+ reject proto, "[dn42] rejecting export: ", net;
+ }
+ };
+ };
+}
+{% endif %}
{% endfor %}
diff --git a/tnet/wg-keys-genkey.yml b/tnet/wg-keys-genkey.yml
index fe0e976..c974a1d 100644
--- a/tnet/wg-keys-genkey.yml
+++ b/tnet/wg-keys-genkey.yml
@@ -1,5 +1,8 @@
- set_fact:
- priv: "{{ lookup('community.sops.sops', 'keys/wg-{{ inventory_hostname }}-{{ item.key }}.sops.key', empty_on_not_exist=true) }}"
+ key: "keys/wg-{{ inventory_hostname }}-{{ item.key }}.sops.key"
+ pub: "keys/wg-{{ inventory_hostname }}-{{ item.key }}.pub"
+- set_fact:
+ priv: "{{ lookup('community.sops.sops', key, empty_on_not_exist=true) }}"
- when: priv == ""
block:
- name: wg genkey
@@ -17,10 +20,10 @@
- name: Save Wireguard key
community.sops.sops_encrypt:
- path: "keys/wg-{{ inventory_hostname }}-{{ item.key }}.sops.key"
+ path: "{{ key }}"
content_text: "{{ new_priv.stdout }}"
- name: Save Wireguard public key
copy:
- dest: "keys/wg-{{ inventory_hostname }}-{{ item.key }}.pub"
+ dest: "{{ pub }}"
content: "{{ new_pub.stdout }}"
diff --git a/tnet/wg-links-link.yml b/tnet/wg-links-link.yml
index 6f1bb87..c1c520b 100644
--- a/tnet/wg-links-link.yml
+++ b/tnet/wg-links-link.yml
@@ -1,3 +1,12 @@
+- set_fact:
+ if_name: tnet-{{ item.value.if_name|default(item.key) }}
+
+#- debug:
+# msg: |
+# if_name {{ if_name }}
+# item.value.if_name {{ item.value.if_name|default("NOT SET") }}
+# item.key {{ item.key }}
+
- notify: systemctl restart systemd-networkd
become: yes
file:
@@ -8,13 +17,13 @@
notify: systemctl restart systemd-networkd
become: yes
copy:
- dest: "/etc/systemd/network/50-tnet-{{ item.key }}.netdev"
+ dest: "/etc/systemd/network/50-{{ if_name }}.netdev"
owner: systemd-network
group: adm
mode: 0640
content: |
[NetDev]
- Name=tnet-{{ item.key }}
+ Name={{ if_name }}
Kind=wireguard
Description=tnet link to {{ item.key }}
@@ -42,12 +51,12 @@
notify: systemctl restart systemd-networkd
become: yes
copy:
- dest: "/etc/systemd/network/50-tnet-{{ item.key }}.network"
+ dest: "/etc/systemd/network/50-{{ if_name }}.network"
owner: systemd-network
group: adm
content: |
[Match]
- Name=tnet-{{ item.key }}
+ Name={{ if_name }}
[Network]
Address={{ item.value.address }}/64