From af6e76134af44cc736b61fde1cb0d308c6840754 Mon Sep 17 00:00:00 2001 From: Taeer Bar-Yam Date: Wed, 3 Apr 2024 08:40:19 -0400 Subject: [PATCH] peertube data in s3 storage --- README.md | 6 ++++ flake.nix | 2 +- garage.nix | 55 ++++++++++++++++++++++++++++++++---- peertube.nix | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c7ec46c..bea1a92 100644 --- a/README.md +++ b/README.md @@ -66,15 +66,21 @@ You can then access the apps on your local machine (using the magic of port forw - [ ] get garage replication running (multiple machines) - [ ] some way of declaratively defining users? - [ ] shared users between fediverse services +- [ ] s3 cache server (SEE: https://docs.joinpeertube.org/maintain/remote-storage) +- [ ] is "s3" the right term, given that it's not an open protocol? # questions - what is meant to be shared between instances? - this is relevant to the security model. If garage is being shared between instances, we have to be careful having configurations depend on each other. +- we want to be able to migrate user's data. s3 migration is not supported by peertube. what do? (SEE: https://docs.joinpeertube.org/maintain/remote-storage) + # resources - Tutorial for setting up better logging: https://krisztianfekete.org/self-hosting-mastodon-on-nixos-a-proof-of-concept/ - Setting up development environment: https://docs.joinmastodon.org/dev/setup/ - Tutorial for PeerTube that doesn't use `createLocally`: https://nixos.wiki/wiki/PeerTube + +- garage settings for specific apps: https://garagehq.deuxfleurs.fr/documentation/connect/apps/ diff --git a/flake.nix b/flake.nix index 88c269e..be5a1f2 100644 --- a/flake.nix +++ b/flake.nix @@ -19,7 +19,7 @@ peertube = nixpkgs.lib.nixosSystem { inherit system; - modules = [ ./common.nix ./peertube.nix ]; + modules = [ ./common.nix ./peertube.nix ./garage.nix ]; }; pixelfed = nixpkgs.lib.nixosSystem { diff --git a/garage.nix b/garage.nix index ca24ca1..b3f2652 100644 --- a/garage.nix +++ b/garage.nix @@ -2,8 +2,8 @@ let # generate one using openssl (somehow) # XXX: when importing, garage tells you importing is only meant for keys previously generated by garage. is it okay to generate them using openssl? snakeoil_key = { - id = "GK3515373e4c851ebaad366558"; - secret = "7d37d093435a41f2aab8f13c19ba067d9776c90215f56614adad6ece597dbb34"; + id = "GK22a15201acacbd51cd43e327"; + secret = "82b2b4cbef27bf8917b350d5b10a87c92fa9c8b13a415aeeea49726cf335d74e"; }; in # TODO: expand to a multi-machine setup @@ -11,7 +11,7 @@ in # add in options to ensure creation of buckets and keys options = let - inherit (lib) types mkOption; + inherit (lib) types mkOption mkEnableOption; in { services.garage = { ensureBuckets = mkOption { @@ -21,11 +21,31 @@ in type = types.bool; default = false; }; + corsRules = { + enable = mkEnableOption "CORS Rules"; + allowedHeaders = mkOption { + type = types.listOf types.str; + default = []; + }; + allowedMethods = mkOption { + type = types.listOf types.str; + default = []; + }; + allowedOrigins = mkOption { + type = types.listOf types.str; + default = []; + }; + }; + aliases = mkOption { + type = types.listOf types.str; + default = []; + }; }; }); }; ensureKeys = mkOption { type = types.attrsOf (types.submodule { + # TODO: these should be managed as secrets, not in the nix store options = { id = mkOption { type = types.string; @@ -75,7 +95,7 @@ in } ]; }; - environment.systemPackages = [ pkgs.minio-client ]; + environment.systemPackages = [ pkgs.minio-client pkgs.awscli ]; networking.firewall.allowedTCPPorts = [ 3901 3902 ]; services.garage = { @@ -100,7 +120,7 @@ in systemd.services.ensure-garage = { after = [ "garage.service" ]; wantedBy = [ "garage.service" ]; - path = [ config.services.garage.package pkgs.perl ]; + path = [ config.services.garage.package pkgs.perl pkgs.awscli ]; script = '' set -xeuo pipefail # give garage time to start up @@ -114,13 +134,36 @@ in LAYOUT_VER=$(garage layout show | perl -ne '/Current cluster layout version: (\d*)/ && print $1') garage layout apply --version $((LAYOUT_VER + 1)) + # XXX: this is a hack because we want to write to the buckets here but we're not guaranteed any access keys + garage key import --yes -n tmp ${snakeoil_key.id} ${snakeoil_key.secret} + export AWS_ACCESS_KEY_ID=${snakeoil_key.id}; + export AWS_SECRET_ACCESS_KEY=${snakeoil_key.secret}; + ${ - lib.concatStringsSep "\n" (lib.mapAttrsToList (bucket: { website }: '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (bucket: { website, aliases, corsRules }: '' garage bucket create ${bucket} # XXX: should this --deny the website if `website` is false? ${lib.optionalString website '' garage bucket website --allow ${bucket} ''} + ${lib.concatStringsSep "\n" (map (alias: '' + garage bucket alias ${bucket} ${alias} + '') aliases)} + + ${lib.optionalString corsRules.enable '' + export CORS=${lib.concatStrings [ + "'" + ''{"CORSRules":[{'' + ''"AllowedHeaders":${builtins.toJSON corsRules.allowedHeaders},'' + ''"AllowedMethods":${builtins.toJSON corsRules.allowedMethods},'' + ''"AllowedOrigins":${builtins.toJSON corsRules.allowedOrigins}'' + ''}]}'' + "'" + ]} + garage bucket allow --read --write --owner ${bucket} --key tmp + aws --endpoint http://s3.garage.localhost:3900 s3api put-bucket-cors --bucket ${bucket} --cors-configuration $CORS + garage bucket deny --read --write --owner ${bucket} --key tmp + ''} '') config.services.garage.ensureBuckets) } ${ diff --git a/peertube.nix b/peertube.nix index 7de11c8..777a726 100644 --- a/peertube.nix +++ b/peertube.nix @@ -1,6 +1,86 @@ +let + snakeoil_key = { + id = "GK1f9feea9960f6f95ff404c9b"; + secret = "7295c4201966a02c2c3d25b5cea4a5ff782966a2415e3a196f91924631191395"; + }; +in { config, lib, pkgs, ... }: { networking.firewall.allowedTCPPorts = [ 80 9000 ]; + services.garage = { + ensureBuckets = { + peertube-videos = { + website = true; + corsRules = { + enable = true; + allowedHeaders = [ "*" ]; + allowedMethods = [ "GET" ]; + allowedOrigins = [ "*" ]; + }; + }; + peertube-playlists = { + website = true; + corsRules = { + enable = true; + allowedHeaders = [ "*" ]; + allowedMethods = [ "GET" ]; + allowedOrigins = [ "*" ]; + }; + }; + }; + ensureKeys = { + peertube = { + inherit (snakeoil_key) id secret; + ensureAccess = { + peertube-videos = { + read = true; + write = true; + owner = true; + }; + peertube-playlists = { + read = true; + write = true; + owner = true; + }; + }; + }; + }; + }; + + services.peertube = { + settings = { + object_storage = { + enabled = true; + endpoint = "http://s3.garage.localhost:3900"; + region = "garage"; + + # not supported by garage + # SEE: https://garagehq.deuxfleurs.fr/documentation/connect/apps/#peertube + proxy.proxyify_private_files = false; + + web_videos = { + bucket_name = "peertube-videos"; + prefix = ""; + base_url = "http://peertube-videos.web.garage.localhost:3902"; + }; + videos = { + bucket_name = "peertube-videos"; + prefix = ""; + base_url = "http://peertube-videos.web.garage.localhost:3902"; + }; + streaming_playlists = { + bucket_name = "peertube-playlists"; + prefix = ""; + base_url = "http://peertube-playlists.web.garage.localhost:3902"; + }; + }; + }; + serviceEnvironmentFile = "/etc/peertube-env"; + }; + environment.etc.peertube-env.text = '' + AWS_ACCESS_KEY_ID=${snakeoil_key.id} + AWS_SECRET_ACCESS_KEY=${snakeoil_key.secret} + ''; # these configurations only apply when producing a VM (e.g. nixos-rebuild build-vm) virtualisation.vmVariant = { config, ... }: { services.peertube = {