Compare commits
No commits in common. "bb4662b3455ca6f6f862cc7266babd4d993d562b" and "c12a47cee0cab3e23e4f2a2d5ca0af4a14318950" have entirely different histories.
bb4662b345
...
c12a47cee0
40
base.nix
40
base.nix
|
@ -133,46 +133,6 @@
|
||||||
extraConfig = "return 444;";
|
extraConfig = "return 444;";
|
||||||
};
|
};
|
||||||
|
|
||||||
# source: https://github.com/logrotate/logrotate/blob/main/examples/logrotate.service
|
|
||||||
systemd.services.logrotate = {
|
|
||||||
documentation = [ "man:logrotate(8)" "man:logrotate.conf(5)" ];
|
|
||||||
unitConfig.RequiresMountsFor = "/var/log";
|
|
||||||
serviceConfig = {
|
|
||||||
Nice = 19;
|
|
||||||
IOSchedulingClass = "best-effort";
|
|
||||||
IOSchedulingPriority = 7;
|
|
||||||
|
|
||||||
ReadWritePaths = [ "/var/log" ];
|
|
||||||
|
|
||||||
AmbientCapabilities = [ "" ];
|
|
||||||
CapabilityBoundingSet = [ "" ];
|
|
||||||
DeviceAllow = [ "" ];
|
|
||||||
LockPersonality = true;
|
|
||||||
MemoryDenyWriteExecute = true;
|
|
||||||
NoNewPrivileges = true; # disable for third party rotate scripts
|
|
||||||
PrivateDevices = true;
|
|
||||||
PrivateNetwork = true; # disable for mail delivery
|
|
||||||
PrivateTmp = true;
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectHome = true; # disable for userdir logs
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
ProtectProc = "invisible";
|
|
||||||
ProtectSystem = "full";
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
RestrictSUIDSGID = true; # disable for creating setgid directories
|
|
||||||
SocketBindDeny = [ "any" ];
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
SystemCallFilter = [
|
|
||||||
"@system-service"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = lib.mkIf config.services.nginx.enable [ 80 443 ];
|
networking.firewall.allowedTCPPorts = lib.mkIf config.services.nginx.enable [ 80 443 ];
|
||||||
|
|
||||||
security.acme = {
|
security.acme = {
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
./services/kerberos
|
./services/kerberos
|
||||||
./services/mediawiki
|
./services/mediawiki
|
||||||
./services/nginx.nix
|
./services/nginx.nix
|
||||||
./services/phpfpm.nix
|
|
||||||
./services/vaultwarden.nix
|
./services/vaultwarden.nix
|
||||||
./services/webmail
|
./services/webmail
|
||||||
./services/website
|
./services/website
|
||||||
|
|
|
@ -6,8 +6,7 @@ let
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
./ci.nix
|
./ci.nix
|
||||||
./import-users
|
./import-users.nix
|
||||||
./web-secret-provider
|
|
||||||
];
|
];
|
||||||
|
|
||||||
sops.secrets = {
|
sops.secrets = {
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
{ config, pkgs, lib, ... }:
|
|
||||||
let
|
|
||||||
organizations = [
|
|
||||||
"Drift"
|
|
||||||
"Projects"
|
|
||||||
"Kurs"
|
|
||||||
];
|
|
||||||
|
|
||||||
giteaCfg = config.services.gitea;
|
|
||||||
|
|
||||||
giteaWebSecretProviderScript = pkgs.writers.writePython3 "gitea-web-secret-provider" {
|
|
||||||
libraries = with pkgs.python3Packages; [ requests ];
|
|
||||||
flakeIgnore = [
|
|
||||||
"E501" # Line over 80 chars lol
|
|
||||||
"E201" # "whitespace after {"
|
|
||||||
"E202" # "whitespace after }"
|
|
||||||
"E251" # unexpected spaces around keyword / parameter equals
|
|
||||||
"W391" # Newline at end of file
|
|
||||||
];
|
|
||||||
makeWrapperArgs = [
|
|
||||||
"--prefix PATH : ${(lib.makeBinPath [ pkgs.openssh ])}"
|
|
||||||
];
|
|
||||||
} (builtins.readFile ./gitea-web-secret-provider.py);
|
|
||||||
in
|
|
||||||
{
|
|
||||||
users.groups."gitea-web" = { };
|
|
||||||
users.users."gitea-web" = {
|
|
||||||
group = "gitea-web";
|
|
||||||
isSystemUser = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
sops.secrets."gitea/web-secret-provider/token" = {
|
|
||||||
owner = "gitea-web";
|
|
||||||
group = "gitea-web";
|
|
||||||
restartUnits = [
|
|
||||||
"gitea-web-secret-provider@"
|
|
||||||
] ++ (map (org: "gitea-web-secret-provider@${org}") organizations);
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.slices.system-giteaweb = {
|
|
||||||
description = "Gitea web directories";
|
|
||||||
};
|
|
||||||
|
|
||||||
# https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html#Specifiers
|
|
||||||
# %i - instance name (after the @)
|
|
||||||
# %d - secrets directory
|
|
||||||
systemd.services."gitea-web-secret-provider@" = {
|
|
||||||
description = "Ensure all repos in %i has an SSH key to push web content";
|
|
||||||
requires = [ "gitea.service" "network.target" ];
|
|
||||||
serviceConfig = {
|
|
||||||
Slice = "system-giteaweb.slice";
|
|
||||||
Type = "oneshot";
|
|
||||||
ExecStart = let
|
|
||||||
args = lib.cli.toGNUCommandLineShell { } {
|
|
||||||
org = "%i";
|
|
||||||
token-path = "%d/token";
|
|
||||||
api-url = "${giteaCfg.settings.server.ROOT_URL}api/v1";
|
|
||||||
key-dir = "/var/lib/gitea-web/keys/%i";
|
|
||||||
authorized-keys-path = "/var/lib/gitea-web/authorized_keys.d/%i";
|
|
||||||
rrsync-script = pkgs.writeShellScript "rrsync-chown" ''
|
|
||||||
${lib.getExe pkgs.rrsync} -wo "$1"
|
|
||||||
${pkgs.coreutils}/bin/chown -R gitea-web:gitea-web "$1"
|
|
||||||
'';
|
|
||||||
web-dir = "/var/lib/gitea-web/web";
|
|
||||||
};
|
|
||||||
in "${giteaWebSecretProviderScript} ${args}";
|
|
||||||
|
|
||||||
User = "gitea-web";
|
|
||||||
Group = "gitea-web";
|
|
||||||
|
|
||||||
StateDirectory = "gitea-web";
|
|
||||||
StateDirectoryMode = "0750";
|
|
||||||
LoadCredential = [
|
|
||||||
"token:${config.sops.secrets."gitea/web-secret-provider/token".path}"
|
|
||||||
];
|
|
||||||
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
PrivateTmp = true;
|
|
||||||
PrivateDevices = true;
|
|
||||||
ProtectSystem = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
|
|
||||||
RestrictRealtime = true;
|
|
||||||
RestrictSUIDSGID = true;
|
|
||||||
MemoryDenyWriteExecute = true;
|
|
||||||
LockPersonality = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.timers."gitea-web-secret-provider@" = {
|
|
||||||
description = "Ensure all repos in %i has an SSH key to push web content";
|
|
||||||
timerConfig = {
|
|
||||||
RandomizedDelaySec = "1h";
|
|
||||||
Persistent = true;
|
|
||||||
Unit = "gitea-web-secret-provider@%i.service";
|
|
||||||
OnCalendar = "daily";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.targets.timers.wants = map (org: "gitea-web-secret-provider@${org}.timer") organizations;
|
|
||||||
|
|
||||||
services.openssh.authorizedKeysFiles = map (org: "/var/lib/gitea-web/authorized_keys.d/${org}") organizations;
|
|
||||||
|
|
||||||
users.users.nginx.extraGroups = [ "gitea-web" ];
|
|
||||||
services.nginx.virtualHosts."pages.pvv.ntnu.no" = {
|
|
||||||
kTLS = true;
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
root = "/var/lib/gitea-web/web";
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
import argparse
|
|
||||||
import hashlib
|
|
||||||
import os
|
|
||||||
import requests
|
|
||||||
import subprocess
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
|
||||||
parser = argparse.ArgumentParser(description="Generate SSH keys for Gitea repositories and add them as secrets")
|
|
||||||
parser.add_argument("--org", required=True, type=str, help="The organization to generate keys for")
|
|
||||||
parser.add_argument("--token-path", metavar='PATH', required=True, type=Path, help="Path to a file containing the Gitea API token")
|
|
||||||
parser.add_argument("--api-url", metavar='URL', type=str, help="The URL of the Gitea API", default="https://git.pvv.ntnu.no/api/v1")
|
|
||||||
parser.add_argument("--key-dir", metavar='PATH', type=Path, help="The directory to store the generated keys in", default="/run/gitea-web-secret-provider")
|
|
||||||
parser.add_argument("--authorized-keys-path", metavar='PATH', type=Path, help="The path to the resulting authorized_keys file", default="/etc/ssh/authorized_keys.d/gitea-web-secret-provider")
|
|
||||||
parser.add_argument("--rrsync-script", metavar='PATH', type=Path, help="The path to a rrsync script, taking the destination path as its single argument")
|
|
||||||
parser.add_argument("--web-dir", metavar='PATH', type=Path, help="The directory to sync the repositories to", default="/var/www")
|
|
||||||
parser.add_argument("--force", action="store_true", help="Overwrite existing keys")
|
|
||||||
return parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
def add_secret(args: argparse.Namespace, token: str, repo: str, name: str, secret: str):
|
|
||||||
result = requests.put(
|
|
||||||
f"{args.api_url}/repos/{args.org}/{repo}/actions/secrets/{name}",
|
|
||||||
json = { 'data': secret },
|
|
||||||
headers = { 'Authorization': 'token ' + token },
|
|
||||||
)
|
|
||||||
if result.status_code not in (201, 204):
|
|
||||||
raise Exception(f"Failed to add secret: {result.json()}")
|
|
||||||
|
|
||||||
|
|
||||||
def get_org_repo_list(args: argparse.Namespace, token: str):
|
|
||||||
result = requests.get(
|
|
||||||
f"{args.api_url}/orgs/{args.org}/repos",
|
|
||||||
headers = { 'Authorization': 'token ' + token },
|
|
||||||
)
|
|
||||||
return [repo["name"] for repo in result.json()]
|
|
||||||
|
|
||||||
|
|
||||||
def generate_ssh_key(args: argparse.Namespace, repository: str):
|
|
||||||
keyname = hashlib.sha256(args.org.encode() + repository.encode()).hexdigest()
|
|
||||||
key_path = args.key_dir / keyname
|
|
||||||
if not key_path.is_file() or args.force:
|
|
||||||
subprocess.run(
|
|
||||||
[
|
|
||||||
"ssh-keygen",
|
|
||||||
*("-t", "ed25519"),
|
|
||||||
*("-f", key_path),
|
|
||||||
*("-N", ""),
|
|
||||||
*("-C", f"{args.org}/{repository}"),
|
|
||||||
],
|
|
||||||
check=True,
|
|
||||||
stdin=subprocess.DEVNULL,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE,
|
|
||||||
)
|
|
||||||
print(f"Generated SSH key for `{args.org}/{repository}`")
|
|
||||||
|
|
||||||
with open(key_path, "r") as f:
|
|
||||||
private_key = f.read()
|
|
||||||
|
|
||||||
pub_key_path = args.key_dir / (keyname + '.pub')
|
|
||||||
with open(pub_key_path, "r") as f:
|
|
||||||
public_key = f.read()
|
|
||||||
|
|
||||||
return private_key, public_key
|
|
||||||
|
|
||||||
|
|
||||||
SSH_OPTS = ",".join([
|
|
||||||
"restrict",
|
|
||||||
"no-agent-forwarding",
|
|
||||||
"no-port-forwarding",
|
|
||||||
"no-pty",
|
|
||||||
"no-X11-forwarding",
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
def generate_authorized_keys(args: argparse.Namespace, repo_public_keys: list[tuple[str, str]]):
|
|
||||||
lines = []
|
|
||||||
for repo, public_key in repo_public_keys:
|
|
||||||
command = f"{args.rrsync_script} {args.web_dir}/{args.org}/{repo}"
|
|
||||||
lines.append(f'command="{command}",{SSH_OPTS} {public_key}')
|
|
||||||
|
|
||||||
with open(args.authorized_keys_path, "w") as f:
|
|
||||||
f.writelines(lines)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
args = parse_args()
|
|
||||||
|
|
||||||
with open(args.token_path, "r") as f:
|
|
||||||
token = f.read().strip()
|
|
||||||
|
|
||||||
os.makedirs(args.key_dir, 0o700, exist_ok=True)
|
|
||||||
os.makedirs(args.authorized_keys_path.parent, 0o700, exist_ok=True)
|
|
||||||
|
|
||||||
repos = get_org_repo_list(args, token)
|
|
||||||
print(f'Found {len(repos)} repositories in `{args.org}`')
|
|
||||||
|
|
||||||
repo_public_keys = []
|
|
||||||
for repo in repos:
|
|
||||||
print(f"Locating key for `{args.org}/{repo}`")
|
|
||||||
private_key, public_key = generate_ssh_key(args, repo)
|
|
||||||
add_secret(args, token, repo, "WEB_SYNC_SSH_KEY", private_key)
|
|
||||||
repo_public_keys.append((repo, public_key))
|
|
||||||
|
|
||||||
generate_authorized_keys(args, repo_public_keys)
|
|
||||||
print(f"Wrote authorized_keys file to `{args.authorized_keys_path}`")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
|
@ -1,51 +0,0 @@
|
||||||
{ lib, ... }:
|
|
||||||
let
|
|
||||||
pools = map (pool: "phpfpm-${pool}") [
|
|
||||||
"idp"
|
|
||||||
"mediawiki"
|
|
||||||
"pvv-nettsiden"
|
|
||||||
"roundcube"
|
|
||||||
"snappymail"
|
|
||||||
];
|
|
||||||
in
|
|
||||||
{
|
|
||||||
# Source: https://www.pierreblazquez.com/2023/06/17/how-to-harden-apache-php-fpm-daemons-using-systemd/
|
|
||||||
systemd.services = lib.genAttrs pools (_: {
|
|
||||||
serviceConfig = let
|
|
||||||
caps = [
|
|
||||||
"CAP_NET_BIND_SERVICE"
|
|
||||||
"CAP_SETGID"
|
|
||||||
"CAP_SETUID"
|
|
||||||
"CAP_CHOWN"
|
|
||||||
"CAP_KILL"
|
|
||||||
"CAP_IPC_LOCK"
|
|
||||||
"CAP_DAC_OVERRIDE"
|
|
||||||
];
|
|
||||||
in {
|
|
||||||
AmbientCapabilities = caps;
|
|
||||||
CapabilityBoundingSet = caps;
|
|
||||||
DeviceAllow = [ "" ];
|
|
||||||
LockPersonality = true;
|
|
||||||
MemoryDenyWriteExecute = false;
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
PrivateMounts = true;
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
RemoveIPC = true;
|
|
||||||
UMask = "0077";
|
|
||||||
RestrictNamespaces = "~mnt";
|
|
||||||
RestrictRealtime = true;
|
|
||||||
RestrictSUIDSGID = true;
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
KeyringMode = "private";
|
|
||||||
SystemCallFilter = [
|
|
||||||
"@system-service"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -65,40 +65,4 @@ in {
|
||||||
proxyWebsockets = true;
|
proxyWebsockets = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.vaultwarden = lib.mkIf cfg.enable {
|
|
||||||
serviceConfig = {
|
|
||||||
AmbientCapabilities = [ "" ];
|
|
||||||
CapabilityBoundingSet = [ "" ];
|
|
||||||
DeviceAllow = [ "" ];
|
|
||||||
LockPersonality = true;
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
# MemoryDenyWriteExecute = true;
|
|
||||||
PrivateMounts = true;
|
|
||||||
PrivateUsers = true;
|
|
||||||
ProcSubset = "pid";
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
ProtectProc = "invisible";
|
|
||||||
RestrictAddressFamilies = [
|
|
||||||
"AF_INET"
|
|
||||||
"AF_INET6"
|
|
||||||
"AF_UNIX"
|
|
||||||
];
|
|
||||||
RemoveIPC = true;
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
RestrictSUIDSGID = true;
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
SystemCallFilter = [
|
|
||||||
"@system-service"
|
|
||||||
"~@privileged"
|
|
||||||
];
|
|
||||||
UMask = "0007";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
sslCert = config.security.acme.certs."postgres.pvv.ntnu.no";
|
||||||
|
in
|
||||||
{
|
{
|
||||||
services.postgresql = {
|
services.postgresql = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -76,16 +79,12 @@
|
||||||
|
|
||||||
systemd.services.postgresql.serviceConfig = {
|
systemd.services.postgresql.serviceConfig = {
|
||||||
LoadCredential = [
|
LoadCredential = [
|
||||||
"cert:/etc/certs/postgres.crt"
|
"cert:${sslCert.directory}/cert.pem"
|
||||||
"key:/etc/certs/postgres.key"
|
"key:${sslCert.directory}/key.pem"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.snakeoil-certs."/etc/certs/postgres" = {
|
users.groups.acme.members = [ "postgres" ];
|
||||||
owner = "postgres";
|
|
||||||
group = "postgres";
|
|
||||||
subject = "/C=NO/O=Programvareverkstedet/CN=postgres.pvv.ntnu.no/emailAddress=drift@pvv.ntnu.no";
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 5432 ];
|
networking.firewall.allowedTCPPorts = [ 5432 ];
|
||||||
networking.firewall.allowedUDPPorts = [ 5432 ];
|
networking.firewall.allowedUDPPorts = [ 5432 ];
|
||||||
|
|
|
@ -50,7 +50,7 @@ in
|
||||||
serviceConfig.Type = "oneshot";
|
serviceConfig.Type = "oneshot";
|
||||||
script = let
|
script = let
|
||||||
openssl = lib.getExe pkgs.openssl;
|
openssl = lib.getExe pkgs.openssl;
|
||||||
in lib.concatMapStringsSep "\n" ({ name, value }: ''
|
in lib.concatMapStringsSep "\n----------------\n" ({ name, value }: ''
|
||||||
mkdir -p $(dirname "${value.certificate}") $(dirname "${value.certificateKey}")
|
mkdir -p $(dirname "${value.certificate}") $(dirname "${value.certificateKey}")
|
||||||
if ! ${openssl} x509 -checkend 86400 -noout -in ${value.certificate}
|
if ! ${openssl} x509 -checkend 86400 -noout -in ${value.certificate}
|
||||||
then
|
then
|
||||||
|
@ -69,8 +69,6 @@ in
|
||||||
chown "${value.owner}:${value.group}" "${value.certificateKey}"
|
chown "${value.owner}:${value.group}" "${value.certificateKey}"
|
||||||
chmod "${value.mode}" "${value.certificate}"
|
chmod "${value.mode}" "${value.certificate}"
|
||||||
chmod "${value.mode}" "${value.certificateKey}"
|
chmod "${value.mode}" "${value.certificateKey}"
|
||||||
|
|
||||||
echo "\n-----------------\n"
|
|
||||||
'') (lib.attrsToList cfg);
|
'') (lib.attrsToList cfg);
|
||||||
};
|
};
|
||||||
systemd.timers."generate-snakeoil-certs" = {
|
systemd.timers."generate-snakeoil-certs" = {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
gitea:
|
gitea:
|
||||||
web-secret-provider:
|
|
||||||
token: ENC[AES256_GCM,data:pHmBKxrNcLifl4sjR44AGEElfdachja35Tl/InsqvBWturaeTv4R0w==,iv:emBWfXQs2VNqtpDp5iA5swNC+24AWDYYXo6nvN+Fwx4=,tag:lkhSVSs6IqhHpfDPOX0wQA==,type:str]
|
|
||||||
password: ENC[AES256_GCM,data:hlNzdU1ope0t50/3aztyLeXjMHd2vFPpwURX+Iu8f49DOqgSnEMtV+KtLA==,iv:qljRnSnchL5cFmaUAfCH9GQYQxcy5cyWejgk1x6bFgI=,tag:tIhboFU5kZsj5oAQR3hLbw==,type:str]
|
password: ENC[AES256_GCM,data:hlNzdU1ope0t50/3aztyLeXjMHd2vFPpwURX+Iu8f49DOqgSnEMtV+KtLA==,iv:qljRnSnchL5cFmaUAfCH9GQYQxcy5cyWejgk1x6bFgI=,tag:tIhboFU5kZsj5oAQR3hLbw==,type:str]
|
||||||
database: ENC[AES256_GCM,data:UlS33IdCEyeSvT6ngpmnkBWHuSEqsB//DT+3b7C+UwbD8UXWJlsLf1X8/w==,iv:mPRW5ldyZaHP+y/0vC2JGSLZmlkhgmkvXPk4LazkSDs=,tag:gGk6Z/nbPvzE1zG+tJC8Sw==,type:str]
|
database: ENC[AES256_GCM,data:UlS33IdCEyeSvT6ngpmnkBWHuSEqsB//DT+3b7C+UwbD8UXWJlsLf1X8/w==,iv:mPRW5ldyZaHP+y/0vC2JGSLZmlkhgmkvXPk4LazkSDs=,tag:gGk6Z/nbPvzE1zG+tJC8Sw==,type:str]
|
||||||
email-password: ENC[AES256_GCM,data:KRwC+aL1aPvJuXt91Oq1ttATMnFTnuUy,iv:ats8TygB/2pORkaTZzPOLufZ9UmvVAKoRcWNvYF1z6w=,tag:Do0fA+4cZ3+l7JJyu8hjBg==,type:str]
|
email-password: ENC[AES256_GCM,data:KRwC+aL1aPvJuXt91Oq1ttATMnFTnuUy,iv:ats8TygB/2pORkaTZzPOLufZ9UmvVAKoRcWNvYF1z6w=,tag:Do0fA+4cZ3+l7JJyu8hjBg==,type:str]
|
||||||
|
@ -92,8 +90,8 @@ sops:
|
||||||
UHpLRkdQTnhkeGlWVG9VS1hkWktyckEKAdwnA9URLYZ50lMtXrU9Q09d0L3Zfsyr
|
UHpLRkdQTnhkeGlWVG9VS1hkWktyckEKAdwnA9URLYZ50lMtXrU9Q09d0L3Zfsyr
|
||||||
4UsvjjdnFtsXwEZ9ZzOQrpiN0Oz24s3csw5KckDni6kslaloJZsLGg==
|
4UsvjjdnFtsXwEZ9ZzOQrpiN0Oz24s3csw5KckDni6kslaloJZsLGg==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2024-08-13T19:49:24Z"
|
lastmodified: "2024-05-26T02:07:41Z"
|
||||||
mac: ENC[AES256_GCM,data:AeJ53D+8A8mHYRmVHdqhcS1ZTbqVe5gQqJsJjMk4T/ZlNX8/V4M9mqAW2FB9m/JSdj234gDu+PBHcW70ZrCqeVsoUW/ETVgUX3W2gBmBgYJiRETp8I7/eks/5YEV6vIIxQsZNP/9dZTNX4T2wD74ELl23NSTXA/6k2tyzBlTMYo=,iv:DABafHvw+5w0PHCKqLgpwmQnv0uHOTyj+s8gdnHFTZ4=,tag:SNZ7W+6zdyuuv2AB9ir8eg==,type:str]
|
mac: ENC[AES256_GCM,data:CRaJefV1zcJc6eyzyjTLgd0+Wv46VT8o4iz2YAGU+c2b/Cr97Tj290LoEO6UXTI3uFwVfzii2yZ2l+4FK3nVVriD4Cx1O/9qWcnLa5gfK30U0zof6AsJx8qtGu1t6oiPlGUCF7sT0BW9Wp8cPumrY6cZp9QbhmIDV0o0aJNUNN4=,iv:8OSYV1eG6kYlJD4ovZZhcD1GaYnmy7vHPa/+7egM1nE=,tag:OPI13rpDh2l1ViFj8TBFWg==,type:str]
|
||||||
pgp:
|
pgp:
|
||||||
- created_at: "2024-08-04T00:03:28Z"
|
- created_at: "2024-08-04T00:03:28Z"
|
||||||
enc: |-
|
enc: |-
|
||||||
|
@ -116,4 +114,4 @@ sops:
|
||||||
-----END PGP MESSAGE-----
|
-----END PGP MESSAGE-----
|
||||||
fp: F7D37890228A907440E1FD4846B9228E814A2AAC
|
fp: F7D37890228A907440E1FD4846B9228E814A2AAC
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.9.0
|
version: 3.8.1
|
||||||
|
|
Loading…
Reference in New Issue