From 38f495e3f4b403ca28919e7b881ca92c6cc79f7a Mon Sep 17 00:00:00 2001 From: amy Date: Tue, 1 Apr 2025 17:40:03 +0000 Subject: [PATCH] feat: initial commit --- .gitignore | 4 + .vscode/settings.json | 4 + README.md | 22 + environments/production/Puppetfile | 5 + environments/production/environment.conf | 1 + environments/production/manifests/config.pp | 20 + environments/production/manifests/site.pp | 63 + .../modules/authentik/files/compose.yml | 72 + .../modules/authentik/manifests/init.pp | 30 + .../modules/authentik/templates/.env.erb | 9 + .../production/modules/dns/manifests/init.pp | 9 + .../modules/dns/templates/resolv.conf.erb | 8 + .../modules/elastic/files/elastic.yml | 88 + .../modules/elastic/manifests/filebeat.pp | 18 + .../modules/elastic/manifests/init.pp | 3 + .../modules/elastic/manifests/kibana.pp | 35 + .../modules/elastic/manifests/search.pp | 35 + .../modules/elastic/templates/kibana.yml.erb | 111 + .../modules/forgejo/files/forgejo.service | 15 + .../modules/forgejo/manifests/init.pp | 41 + .../modules/garage/manifests/init.pp | 48 + .../modules/garage/manifests/webui.pp | 35 + .../modules/garage/templates/conf.toml.erb | 28 + .../garage/templates/garage-webui.service.erb | 15 + .../garage/templates/garage.service.erb | 14 + .../modules/hosts/manifests/init.pp | 9 + .../modules/hosts/templates/hosts.erb | 12 + .../modules/infisical/files/compose.yml | 36 + .../modules/infisical/manifests/cli.pp | 18 + .../modules/infisical/manifests/init.pp | 29 + .../modules/infisical/templates/.env.erb | 124 + .../modules/keys/files/puppet-push.pub | 2 + .../production/modules/keys/manifests/init.pp | 8 + .../modules/owncloud/manifests/init.pp | 43 + .../owncloud/templates/owncloud.service.erb | 32 + .../modules/postgresql/manifests/init.pp | 34 + .../modules/postgresql/manifests/pgadmin.pp | 42 + .../postgresql/templates/config_local.py.erb | 17 + .../modules/reverse_proxy/files/.gitignore | 1 + .../reverse_proxy/files/conf.d/auth.amy.mov | 137 + .../reverse_proxy/files/conf.d/blog.amy.mov | 13 + .../reverse_proxy/files/conf.d/cloud.amy.mov | 13 + .../reverse_proxy/files/conf.d/fedi.amy.mov | 13 + .../reverse_proxy/files/conf.d/forge.amy.mov | 14 + .../files/conf.d/internal-s3.amy.mov | 11 + .../reverse_proxy/files/conf.d/pg.amy.mov | 13 + .../reverse_proxy/files/conf.d/s3.amy.mov | 15 + .../files/conf.d/secrets.amy.mov | 13 + .../modules/reverse_proxy/files/nginx.conf | 31 + .../modules/reverse_proxy/manifests/init.pp | 56 + .../modules/unifi/files/libssl1.1.deb | Bin 0 -> 1128092 bytes .../modules/unifi/manifests/init.pp | 74 + .../modules/utils/manifests/init.pp | 5 + .../production/thirdparty/apt/CHANGELOG.md | 1019 +++ .../production/thirdparty/apt/CODEOWNERS | 2 + .../production/thirdparty/apt/CONTRIBUTING.md | 3 + .../production/thirdparty/apt/HISTORY.md | 692 ++ .../production/thirdparty/apt/LICENSE | 202 + .../production/thirdparty/apt/MAINTAINERS.md | 6 + environments/production/thirdparty/apt/NOTICE | 37 + .../production/thirdparty/apt/README.md | 401 ++ .../production/thirdparty/apt/REFERENCE.md | 1432 ++++ .../thirdparty/apt/data/common.yaml | 1 + .../thirdparty/apt/data/os/Debian.yaml | 3 + .../thirdparty/apt/data/os/Debian/12.yaml | 3 + .../thirdparty/apt/data/os/Ubuntu.yaml | 7 + .../thirdparty/apt/examples/backports.pp | 7 + .../thirdparty/apt/examples/builddep.pp | 3 + .../thirdparty/apt/examples/debian_testing.pp | 18 + .../apt/examples/debian_unstable.pp | 18 + .../thirdparty/apt/examples/disable_keys.pp | 5 + .../thirdparty/apt/examples/fancy_progress.pp | 4 + .../thirdparty/apt/examples/force.pp | 28 + .../thirdparty/apt/examples/hold.pp | 5 + .../production/thirdparty/apt/examples/key.pp | 6 + .../thirdparty/apt/examples/mark.pp | 3 + .../production/thirdparty/apt/examples/pin.pp | 5 + .../production/thirdparty/apt/examples/ppa.pp | 4 + .../thirdparty/apt/examples/release.pp | 4 + .../thirdparty/apt/examples/source.pp | 35 + .../apt/examples/unattended_upgrades.pp | 1 + .../thirdparty/apt/files/15update-stamp | 1 + .../production/thirdparty/apt/hiera.yaml | 21 + .../apt/lib/facter/apt_reboot_required.rb | 9 + .../thirdparty/apt/lib/facter/apt_sources.rb | 13 + .../apt/lib/facter/apt_update_last_success.rb | 18 + .../thirdparty/apt/lib/facter/apt_updates.rb | 103 + .../lib/puppet/provider/apt_key/apt_key.rb | 240 + .../thirdparty/apt/lib/puppet/type/apt_key.rb | 146 + .../thirdparty/apt/manifests/backports.pp | 119 + .../thirdparty/apt/manifests/conf.pp | 35 + .../thirdparty/apt/manifests/init.pp | 457 ++ .../thirdparty/apt/manifests/key.pp | 104 + .../thirdparty/apt/manifests/keyring.pp | 72 + .../thirdparty/apt/manifests/mark.pp | 37 + .../thirdparty/apt/manifests/pin.pp | 136 + .../thirdparty/apt/manifests/ppa.pp | 128 + .../thirdparty/apt/manifests/setting.pp | 77 + .../thirdparty/apt/manifests/source.pp | 363 + .../thirdparty/apt/manifests/update.pp | 98 + .../production/thirdparty/apt/metadata.json | 42 + .../production/thirdparty/apt/pdk.yaml | 2 + .../production/thirdparty/apt/provision.yaml | 37 + .../production/thirdparty/apt/tasks/init.json | 10 + .../production/thirdparty/apt/tasks/init.rb | 34 + .../thirdparty/apt/templates/_conf_header.epp | 1 + .../thirdparty/apt/templates/_header.epp | 1 + .../apt/templates/add-apt-repository.sh.epp | 8 + .../thirdparty/apt/templates/auth_conf.epp | 6 + .../thirdparty/apt/templates/pin.pref.epp | 26 + .../thirdparty/apt/templates/proxy.epp | 10 + .../thirdparty/apt/templates/source.list.epp | 8 + .../apt/templates/source_deb822.epp | 36 + .../thirdparty/apt/types/auth_conf_entry.pp | 20 + .../production/thirdparty/apt/types/proxy.pp | 28 + .../thirdparty/apt/types/proxy_per_host.pp | 26 + .../production/thirdparty/docker/CHANGELOG.md | 583 ++ .../production/thirdparty/docker/CODEOWNERS | 2 + .../thirdparty/docker/CONTRIBUTING.md | 3 + .../thirdparty/docker/CONTRIBUTORS.md | 187 + .../production/thirdparty/docker/HISTORY.md | 205 + .../production/thirdparty/docker/LICENSE | 207 + .../production/thirdparty/docker/README.md | 1041 +++ .../production/thirdparty/docker/REFERENCE.md | 4629 +++++++++++++ .../thirdparty/docker/data/common.yaml | 1 + .../docker/functions/sanitised_name.pp | 12 + .../production/thirdparty/docker/hiera.yaml | 21 + .../thirdparty/docker/lib/facter/docker.rb | 152 + .../docker/lib/puppet/functions/docker/env.rb | 12 + .../puppet/functions/docker_params_changed.rb | 155 + .../parser/functions/docker_exec_flags.rb | 25 + .../functions/docker_plugin_enable_flags.rb | 20 + .../functions/docker_plugin_install_flags.rb | 24 + .../functions/docker_plugin_remove_flags.rb | 16 + .../parser/functions/docker_run_flags.rb | 96 + .../parser/functions/docker_secrets_flags.rb | 33 + .../parser/functions/docker_service_flags.rb | 83 + .../parser/functions/docker_stack_flags.rb | 29 + .../functions/docker_swarm_init_flags.rb | 43 + .../functions/docker_swarm_join_flags.rb | 23 + .../puppet/provider/docker_compose/ruby.rb | 109 + .../puppet/provider/docker_network/ruby.rb | 95 + .../lib/puppet/provider/docker_stack/ruby.rb | 88 + .../lib/puppet/provider/docker_volume/ruby.rb | 70 + .../docker/lib/puppet/type/docker_compose.rb | 61 + .../docker/lib/puppet/type/docker_network.rb | 50 + .../docker/lib/puppet/type/docker_stack.rb | 33 + .../docker/lib/puppet/type/docker_volume.rb | 26 + .../thirdparty/docker/manifests/compose.pp | 54 + .../thirdparty/docker/manifests/config.pp | 16 + .../thirdparty/docker/manifests/exec.pp | 81 + .../thirdparty/docker/manifests/image.pp | 185 + .../thirdparty/docker/manifests/images.pp | 9 + .../thirdparty/docker/manifests/init.pp | 652 ++ .../thirdparty/docker/manifests/install.pp | 153 + .../thirdparty/docker/manifests/machine.pp | 108 + .../thirdparty/docker/manifests/networks.pp | 11 + .../thirdparty/docker/manifests/params.pp | 387 ++ .../thirdparty/docker/manifests/plugin.pp | 122 + .../thirdparty/docker/manifests/plugins.pp | 9 + .../thirdparty/docker/manifests/registry.pp | 159 + .../docker/manifests/registry_auth.pp | 9 + .../thirdparty/docker/manifests/repos.pp | 90 + .../thirdparty/docker/manifests/run.pp | 752 +++ .../docker/manifests/run_instance.pp | 9 + .../thirdparty/docker/manifests/service.pp | 524 ++ .../thirdparty/docker/manifests/services.pp | 205 + .../thirdparty/docker/manifests/stack.pp | 80 + .../thirdparty/docker/manifests/swarm.pp | 161 + .../thirdparty/docker/manifests/swarms.pp | 9 + .../docker/manifests/system_user.pp | 23 + .../docker/manifests/systemd_reload.pp | 10 + .../thirdparty/docker/manifests/volumes.pp | 9 + .../docker/manifests/windows_account.pp | 7 + .../thirdparty/docker/metadata.json | 70 + .../production/thirdparty/docker/pdk.yaml | 2 + .../thirdparty/docker/provision.yaml | 40 + .../thirdparty/docker/tasks/node_ls.json | 14 + .../thirdparty/docker/tasks/node_ls.rb | 30 + .../thirdparty/docker/tasks/node_rm.json | 14 + .../thirdparty/docker/tasks/node_rm.rb | 30 + .../thirdparty/docker/tasks/node_update.json | 27 + .../thirdparty/docker/tasks/node_update.rb | 47 + .../docker/tasks/service_create.json | 38 + .../thirdparty/docker/tasks/service_create.rb | 56 + .../thirdparty/docker/tasks/service_rm.json | 10 + .../thirdparty/docker/tasks/service_rm.rb | 28 + .../docker/tasks/service_scale.json | 18 + .../thirdparty/docker/tasks/service_scale.rb | 32 + .../docker/tasks/service_update.json | 22 + .../thirdparty/docker/tasks/service_update.rb | 45 + .../thirdparty/docker/tasks/swarm_init.json | 42 + .../thirdparty/docker/tasks/swarm_init.rb | 44 + .../thirdparty/docker/tasks/swarm_join.json | 22 + .../thirdparty/docker/tasks/swarm_join.rb | 34 + .../thirdparty/docker/tasks/swarm_leave.json | 10 + .../thirdparty/docker/tasks/swarm_leave.rb | 26 + .../thirdparty/docker/tasks/swarm_token.json | 10 + .../thirdparty/docker/tasks/swarm_token.rb | 28 + .../thirdparty/docker/tasks/swarm_update.json | 15 + .../thirdparty/docker/tasks/swarm_update.rb | 20 + .../docker/templates/docker-run-start.epp | 37 + .../docker/templates/docker-run-stop.epp | 10 + .../docker/templates/etc/conf.d/docker.epp | 56 + .../templates/etc/conf.d/docker.gentoo.epp | 56 + .../docker/templates/etc/default/docker.epp | 70 + .../templates/etc/init.d/docker-run.epp | 145 + .../etc/sysconfig/docker-storage-setup.epp | 19 + .../etc/sysconfig/docker-storage.epp | 39 + .../docker/templates/etc/sysconfig/docker.epp | 40 + .../etc/sysconfig/docker.systemd.epp | 38 + .../etc/systemd/system/docker-run.epp | 63 + .../service-overrides-debian.conf.epp | 11 + .../service-overrides-rhel.conf.epp | 17 + .../docker.socket.d/socket-overrides.conf.epp | 2 + .../templates/update_docker_image.sh.epp | 23 + .../templates/usr/local/bin/docker-run.sh.epp | 5 + .../templates/windows/check_docker.ps1.epp | 19 + .../windows/check_docker_url.ps1.epp | 22 + .../templates/windows/check_hash.ps1.epp | 17 + .../windows/check_powershell_provider.ps1.epp | 48 + .../templates/windows/compute_hash.ps1.epp | 10 + .../templates/windows/config/daemon.json.epp | 23 + .../templates/windows/download_docker.ps1.epp | 40 + .../windows/download_docker_compose.ps1.epp | 23 + .../windows/download_docker_machine.ps1.epp | 23 + .../install_powershell_provider.ps1.epp | 28 + .../templates/windows/remove_docker.ps1.epp | 48 + .../windows/update_docker_image.ps1.epp | 27 + .../production/thirdparty/stdlib/CHANGELOG.md | 1263 ++++ .../production/thirdparty/stdlib/CODEOWNERS | 3 + .../thirdparty/stdlib/CONTRIBUTING.md | 3 + .../production/thirdparty/stdlib/HISTORY.md | 1067 +++ .../production/thirdparty/stdlib/LICENSE | 202 + .../production/thirdparty/stdlib/NOTICE | 23 + .../production/thirdparty/stdlib/README.md | 593 ++ .../stdlib/README_DEVELOPER.markdown | 35 + .../thirdparty/stdlib/README_SPECS.markdown | 7 + .../production/thirdparty/stdlib/REFERENCE.md | 5907 +++++++++++++++++ .../stdlib/RELEASE_PROCESS.markdown | 24 + .../thirdparty/stdlib/data/common.yaml | 1 + .../thirdparty/stdlib/examples/file_line.pp | 9 + .../stdlib/examples/has_interface_with.pp | 9 + .../stdlib/examples/has_ip_address.pp | 3 + .../stdlib/examples/has_ip_network.pp | 3 + .../thirdparty/stdlib/examples/init.pp | 1 + .../stdlib/functions/deferrable_epp.pp | 18 + .../thirdparty/stdlib/functions/ensure.pp | 33 + .../thirdparty/stdlib/functions/time.pp | 11 + .../production/thirdparty/stdlib/hiera.yaml | 21 + .../stdlib/lib/facter/package_provider.rb | 21 + .../stdlib/lib/facter/pe_version.rb | 62 + .../stdlib/lib/facter/puppet_settings.rb | 46 + .../thirdparty/stdlib/lib/facter/root_home.rb | 11 + .../stdlib/lib/facter/service_provider.rb | 19 + .../stdlib/lib/facter/util/puppet_settings.rb | 18 + .../lib/puppet/functions/batch_escape.rb | 14 + .../lib/puppet/functions/deprecation.rb | 38 + .../lib/puppet/functions/ensure_packages.rb | 13 + .../stdlib/lib/puppet/functions/fact.rb | 65 + .../lib/puppet/functions/fqdn_rand_string.rb | 14 + .../lib/puppet/functions/fqdn_rotate.rb | 14 + .../puppet/functions/has_interface_with.rb | 14 + .../stdlib/lib/puppet/functions/is_a.rb | 44 + .../stdlib/lib/puppet/functions/merge.rb | 15 + .../lib/puppet/functions/os_version_gte.rb | 14 + .../stdlib/lib/puppet/functions/parsehocon.rb | 14 + .../stdlib/lib/puppet/functions/parsepson.rb | 34 + .../lib/puppet/functions/powershell_escape.rb | 14 + .../lib/puppet/functions/seeded_rand.rb | 14 + .../puppet/functions/seeded_rand_string.rb | 14 + .../lib/puppet/functions/shell_escape.rb | 14 + .../puppet/functions/stdlib/batch_escape.rb | 31 + .../lib/puppet/functions/stdlib/crc32.rb | 31 + .../lib/puppet/functions/stdlib/end_with.rb | 23 + .../functions/stdlib/ensure_packages.rb | 61 + .../lib/puppet/functions/stdlib/extname.rb | 28 + .../functions/stdlib/fqdn_rand_string.rb | 39 + .../puppet/functions/stdlib/fqdn_rotate.rb | 66 + .../puppet/functions/stdlib/has_function.rb | 33 + .../functions/stdlib/has_interface_with.rb | 47 + .../puppet/functions/stdlib/ip_in_range.rb | 32 + .../lib/puppet/functions/stdlib/merge.rb | 112 + .../puppet/functions/stdlib/nested_values.rb | 27 + .../puppet/functions/stdlib/os_version_gte.rb | 27 + .../lib/puppet/functions/stdlib/parsehocon.rb | 32 + .../functions/stdlib/powershell_escape.rb | 31 + .../puppet/functions/stdlib/seeded_rand.rb | 22 + .../functions/stdlib/seeded_rand_string.rb | 32 + .../lib/puppet/functions/stdlib/sha256.rb | 26 + .../puppet/functions/stdlib/shell_escape.rb | 25 + .../lib/puppet/functions/stdlib/sort_by.rb | 49 + .../lib/puppet/functions/stdlib/start_with.rb | 23 + .../puppet/functions/stdlib/str2resource.rb | 35 + .../lib/puppet/functions/stdlib/to_json.rb | 24 + .../puppet/functions/stdlib/to_json_pretty.rb | 74 + .../lib/puppet/functions/stdlib/to_python.rb | 42 + .../lib/puppet/functions/stdlib/to_ruby.rb | 39 + .../lib/puppet/functions/stdlib/to_toml.rb | 22 + .../lib/puppet/functions/stdlib/to_yaml.rb | 32 + .../lib/puppet/functions/stdlib/type_of.rb | 26 + .../functions/stdlib/validate_domain_name.rb | 34 + .../stdlib/validate_email_address.rb | 31 + .../lib/puppet/functions/stdlib/xml_encode.rb | 30 + .../stdlib/lib/puppet/functions/time.rb | 12 + .../stdlib/lib/puppet/functions/to_json.rb | 14 + .../lib/puppet/functions/to_json_pretty.rb | 14 + .../stdlib/lib/puppet/functions/to_python.rb | 14 + .../stdlib/lib/puppet/functions/to_ruby.rb | 14 + .../stdlib/lib/puppet/functions/to_toml.rb | 14 + .../stdlib/lib/puppet/functions/to_yaml.rb | 14 + .../stdlib/lib/puppet/functions/type_of.rb | 14 + .../puppet/functions/validate_domain_name.rb | 14 + .../functions/validate_email_address.rb | 14 + .../lib/puppet/functions/validate_legacy.rb | 68 + .../lib/puppet/parser/functions/any2array.rb | 56 + .../lib/puppet/parser/functions/any2bool.rb | 54 + .../puppet/parser/functions/assert_private.rb | 33 + .../lib/puppet/parser/functions/base64.rb | 81 + .../lib/puppet/parser/functions/basename.rb | 29 + .../lib/puppet/parser/functions/bool2num.rb | 44 + .../lib/puppet/parser/functions/bool2str.rb | 58 + .../lib/puppet/parser/functions/clamp.rb | 46 + .../lib/puppet/parser/functions/concat.rb | 46 + .../puppet/parser/functions/convert_base.rb | 49 + .../lib/puppet/parser/functions/count.rb | 40 + .../lib/puppet/parser/functions/deep_merge.rb | 49 + .../parser/functions/defined_with_params.rb | 78 + .../lib/puppet/parser/functions/delete.rb | 68 + .../lib/puppet/parser/functions/delete_at.rb | 57 + .../puppet/parser/functions/delete_regex.rb | 53 + .../parser/functions/delete_undef_values.rb | 42 + .../puppet/parser/functions/delete_values.rb | 33 + .../lib/puppet/parser/functions/difference.rb | 43 + .../lib/puppet/parser/functions/dirname.rb | 24 + .../lib/puppet/parser/functions/dos2unix.rb | 18 + .../puppet/parser/functions/enclose_ipv6.rb | 41 + .../parser/functions/ensure_resource.rb | 53 + .../parser/functions/ensure_resources.rb | 58 + .../lib/puppet/parser/functions/fqdn_uuid.rb | 71 + .../parser/functions/get_module_path.rb | 33 + .../lib/puppet/parser/functions/getparam.rb | 57 + .../lib/puppet/parser/functions/glob.rb | 32 + .../lib/puppet/parser/functions/grep.rb | 32 + .../parser/functions/has_interface_with.rb | 68 + .../puppet/parser/functions/has_ip_address.rb | 27 + .../puppet/parser/functions/has_ip_network.rb | 27 + .../puppet/parser/functions/intersection.rb | 33 + .../parser/functions/join_keys_to_values.rb | 53 + .../parser/functions/load_module_metadata.rb | 40 + .../lib/puppet/parser/functions/loadjson.rb | 75 + .../lib/puppet/parser/functions/loadyaml.rb | 68 + .../lib/puppet/parser/functions/member.rb | 62 + .../lib/puppet/parser/functions/merge.rb | 39 + .../lib/puppet/parser/functions/num2bool.rb | 49 + .../lib/puppet/parser/functions/parsejson.rb | 34 + .../lib/puppet/parser/functions/parseyaml.rb | 37 + .../lib/puppet/parser/functions/pick.rb | 37 + .../puppet/parser/functions/pick_default.rb | 43 + .../lib/puppet/parser/functions/prefix.rb | 51 + .../stdlib/lib/puppet/parser/functions/pry.rb | 37 + .../lib/puppet/parser/functions/pw_hash.rb | 89 + .../lib/puppet/parser/functions/range.rb | 96 + .../puppet/parser/functions/regexpescape.rb | 32 + .../lib/puppet/parser/functions/reject.rb | 38 + .../lib/puppet/parser/functions/reverse.rb | 29 + .../lib/puppet/parser/functions/shell_join.rb | 32 + .../puppet/parser/functions/shell_split.rb | 28 + .../lib/puppet/parser/functions/shuffle.rb | 45 + .../lib/puppet/parser/functions/squeeze.rb | 34 + .../lib/puppet/parser/functions/str2bool.rb | 46 + .../parser/functions/str2saltedpbkdf2.rb | 70 + .../parser/functions/str2saltedsha512.rb | 36 + .../lib/puppet/parser/functions/suffix.rb | 55 + .../lib/puppet/parser/functions/swapcase.rb | 38 + .../lib/puppet/parser/functions/to_bytes.rb | 39 + .../lib/puppet/parser/functions/union.rb | 30 + .../lib/puppet/parser/functions/unix2dos.rb | 19 + .../lib/puppet/parser/functions/uriescape.rb | 42 + .../parser/functions/validate_augeas.rb | 94 + .../puppet/parser/functions/validate_cmd.rb | 71 + .../functions/validate_x509_rsa_key_pair.rb | 49 + .../lib/puppet/parser/functions/values_at.rb | 92 + .../stdlib/lib/puppet/parser/functions/zip.rb | 36 + .../lib/puppet/provider/file_line/ruby.rb | 170 + .../stdlib/lib/puppet/type/anchor.rb | 54 + .../stdlib/lib/puppet/type/file_line.rb | 194 + .../thirdparty/stdlib/lib/puppet_x/stdlib.rb | 6 + .../stdlib/lib/puppet_x/stdlib/toml_dumper.rb | 135 + .../thirdparty/stdlib/manifests/init.pp | 13 + .../thirdparty/stdlib/manifests/manage.pp | 118 + .../thirdparty/stdlib/manifests/stages.pp | 32 + .../thirdparty/stdlib/metadata.json | 119 + .../production/thirdparty/stdlib/pdk.yaml | 2 + .../thirdparty/stdlib/provision.yaml | 84 + .../thirdparty/stdlib/readmes/README_ja_JP.md | 3135 +++++++++ .../thirdparty/stdlib/types/absolutepath.pp | 2 + .../thirdparty/stdlib/types/base32.pp | 2 + .../thirdparty/stdlib/types/base64.pp | 2 + .../stdlib/types/createresources.pp | 17 + .../thirdparty/stdlib/types/datasize.pp | 2 + .../thirdparty/stdlib/types/dns/zone.pp | 2 + .../thirdparty/stdlib/types/email.pp | 5 + .../thirdparty/stdlib/types/ensure/file.pp | 2 + .../stdlib/types/ensure/file/directory.pp | 2 + .../stdlib/types/ensure/file/file.pp | 2 + .../stdlib/types/ensure/file/link.pp | 2 + .../thirdparty/stdlib/types/ensure/package.pp | 2 + .../thirdparty/stdlib/types/ensure/service.pp | 2 + .../thirdparty/stdlib/types/filemode.pp | 5 + .../thirdparty/stdlib/types/filesource.pp | 9 + .../thirdparty/stdlib/types/fqdn.pp | 2 + .../thirdparty/stdlib/types/host.pp | 2 + .../thirdparty/stdlib/types/http/method.pp | 43 + .../thirdparty/stdlib/types/http/status.pp | 3 + .../thirdparty/stdlib/types/httpstatus.pp | 4 + .../thirdparty/stdlib/types/httpsurl.pp | 2 + .../thirdparty/stdlib/types/httpurl.pp | 2 + .../thirdparty/stdlib/types/ip/address.pp | 5 + .../stdlib/types/ip/address/cidr.pp | 5 + .../stdlib/types/ip/address/nosubnet.pp | 5 + .../thirdparty/stdlib/types/ip/address/v4.pp | 5 + .../stdlib/types/ip/address/v4/cidr.pp | 3 + .../stdlib/types/ip/address/v4/nosubnet.pp | 3 + .../thirdparty/stdlib/types/ip/address/v6.pp | 7 + .../stdlib/types/ip/address/v6/alternative.pp | 11 + .../stdlib/types/ip/address/v6/cidr.pp | 3 + .../stdlib/types/ip/address/v6/compressed.pp | 11 + .../stdlib/types/ip/address/v6/full.pp | 2 + .../stdlib/types/ip/address/v6/nosubnet.pp | 6 + .../ip/address/v6/nosubnet/alternative.pp | 11 + .../ip/address/v6/nosubnet/compressed.pp | 11 + .../types/ip/address/v6/nosubnet/full.pp | 2 + .../production/thirdparty/stdlib/types/mac.pp | 5 + .../thirdparty/stdlib/types/objectstore.pp | 5 + .../stdlib/types/objectstore/gsuri.pp | 2 + .../stdlib/types/objectstore/s3uri.pp | 2 + .../thirdparty/stdlib/types/port.pp | 2 + .../thirdparty/stdlib/types/port/dynamic.pp | 2 + .../thirdparty/stdlib/types/port/ephemeral.pp | 2 + .../stdlib/types/port/privileged.pp | 2 + .../stdlib/types/port/registered.pp | 2 + .../stdlib/types/port/unprivileged.pp | 2 + .../thirdparty/stdlib/types/port/user.pp | 2 + .../thirdparty/stdlib/types/syslogfacility.pp | 27 + .../thirdparty/stdlib/types/unixpath.pp | 3 + .../thirdparty/stdlib/types/windowspath.pp | 2 + .../thirdparty/stdlib/types/yes_no.pp | 2 + g10k/source.txt | 1 + scripts/agent-bootstrap.sh | 10 + scripts/push.sh | 5 + secrets/.env.example | 6 + secrets/README.md | 10 + secrets/SECRETS.md | 33 + secrets/apply-secrets.ts | 51 + secrets/deno-src/source.txt | 1 + secrets/secrets.eta | 3 + 457 files changed, 40577 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 100644 environments/production/Puppetfile create mode 100644 environments/production/environment.conf create mode 100644 environments/production/manifests/config.pp create mode 100644 environments/production/manifests/site.pp create mode 100644 environments/production/modules/authentik/files/compose.yml create mode 100644 environments/production/modules/authentik/manifests/init.pp create mode 100644 environments/production/modules/authentik/templates/.env.erb create mode 100644 environments/production/modules/dns/manifests/init.pp create mode 100644 environments/production/modules/dns/templates/resolv.conf.erb create mode 100644 environments/production/modules/elastic/files/elastic.yml create mode 100644 environments/production/modules/elastic/manifests/filebeat.pp create mode 100644 environments/production/modules/elastic/manifests/init.pp create mode 100644 environments/production/modules/elastic/manifests/kibana.pp create mode 100644 environments/production/modules/elastic/manifests/search.pp create mode 100644 environments/production/modules/elastic/templates/kibana.yml.erb create mode 100644 environments/production/modules/forgejo/files/forgejo.service create mode 100644 environments/production/modules/forgejo/manifests/init.pp create mode 100644 environments/production/modules/garage/manifests/init.pp create mode 100644 environments/production/modules/garage/manifests/webui.pp create mode 100644 environments/production/modules/garage/templates/conf.toml.erb create mode 100644 environments/production/modules/garage/templates/garage-webui.service.erb create mode 100644 environments/production/modules/garage/templates/garage.service.erb create mode 100644 environments/production/modules/hosts/manifests/init.pp create mode 100644 environments/production/modules/hosts/templates/hosts.erb create mode 100644 environments/production/modules/infisical/files/compose.yml create mode 100644 environments/production/modules/infisical/manifests/cli.pp create mode 100644 environments/production/modules/infisical/manifests/init.pp create mode 100644 environments/production/modules/infisical/templates/.env.erb create mode 100644 environments/production/modules/keys/files/puppet-push.pub create mode 100644 environments/production/modules/keys/manifests/init.pp create mode 100644 environments/production/modules/owncloud/manifests/init.pp create mode 100644 environments/production/modules/owncloud/templates/owncloud.service.erb create mode 100644 environments/production/modules/postgresql/manifests/init.pp create mode 100644 environments/production/modules/postgresql/manifests/pgadmin.pp create mode 100644 environments/production/modules/postgresql/templates/config_local.py.erb create mode 100644 environments/production/modules/reverse_proxy/files/.gitignore create mode 100644 environments/production/modules/reverse_proxy/files/conf.d/auth.amy.mov create mode 100644 environments/production/modules/reverse_proxy/files/conf.d/blog.amy.mov create mode 100644 environments/production/modules/reverse_proxy/files/conf.d/cloud.amy.mov create mode 100644 environments/production/modules/reverse_proxy/files/conf.d/fedi.amy.mov create mode 100644 environments/production/modules/reverse_proxy/files/conf.d/forge.amy.mov create mode 100644 environments/production/modules/reverse_proxy/files/conf.d/internal-s3.amy.mov create mode 100644 environments/production/modules/reverse_proxy/files/conf.d/pg.amy.mov create mode 100644 environments/production/modules/reverse_proxy/files/conf.d/s3.amy.mov create mode 100644 environments/production/modules/reverse_proxy/files/conf.d/secrets.amy.mov create mode 100644 environments/production/modules/reverse_proxy/files/nginx.conf create mode 100644 environments/production/modules/reverse_proxy/manifests/init.pp create mode 100644 environments/production/modules/unifi/files/libssl1.1.deb create mode 100644 environments/production/modules/unifi/manifests/init.pp create mode 100644 environments/production/modules/utils/manifests/init.pp create mode 100644 environments/production/thirdparty/apt/CHANGELOG.md create mode 100644 environments/production/thirdparty/apt/CODEOWNERS create mode 100644 environments/production/thirdparty/apt/CONTRIBUTING.md create mode 100644 environments/production/thirdparty/apt/HISTORY.md create mode 100644 environments/production/thirdparty/apt/LICENSE create mode 100644 environments/production/thirdparty/apt/MAINTAINERS.md create mode 100644 environments/production/thirdparty/apt/NOTICE create mode 100644 environments/production/thirdparty/apt/README.md create mode 100644 environments/production/thirdparty/apt/REFERENCE.md create mode 100644 environments/production/thirdparty/apt/data/common.yaml create mode 100644 environments/production/thirdparty/apt/data/os/Debian.yaml create mode 100644 environments/production/thirdparty/apt/data/os/Debian/12.yaml create mode 100644 environments/production/thirdparty/apt/data/os/Ubuntu.yaml create mode 100644 environments/production/thirdparty/apt/examples/backports.pp create mode 100644 environments/production/thirdparty/apt/examples/builddep.pp create mode 100644 environments/production/thirdparty/apt/examples/debian_testing.pp create mode 100644 environments/production/thirdparty/apt/examples/debian_unstable.pp create mode 100644 environments/production/thirdparty/apt/examples/disable_keys.pp create mode 100644 environments/production/thirdparty/apt/examples/fancy_progress.pp create mode 100644 environments/production/thirdparty/apt/examples/force.pp create mode 100644 environments/production/thirdparty/apt/examples/hold.pp create mode 100644 environments/production/thirdparty/apt/examples/key.pp create mode 100644 environments/production/thirdparty/apt/examples/mark.pp create mode 100644 environments/production/thirdparty/apt/examples/pin.pp create mode 100644 environments/production/thirdparty/apt/examples/ppa.pp create mode 100644 environments/production/thirdparty/apt/examples/release.pp create mode 100644 environments/production/thirdparty/apt/examples/source.pp create mode 100644 environments/production/thirdparty/apt/examples/unattended_upgrades.pp create mode 100644 environments/production/thirdparty/apt/files/15update-stamp create mode 100644 environments/production/thirdparty/apt/hiera.yaml create mode 100644 environments/production/thirdparty/apt/lib/facter/apt_reboot_required.rb create mode 100644 environments/production/thirdparty/apt/lib/facter/apt_sources.rb create mode 100644 environments/production/thirdparty/apt/lib/facter/apt_update_last_success.rb create mode 100644 environments/production/thirdparty/apt/lib/facter/apt_updates.rb create mode 100644 environments/production/thirdparty/apt/lib/puppet/provider/apt_key/apt_key.rb create mode 100644 environments/production/thirdparty/apt/lib/puppet/type/apt_key.rb create mode 100644 environments/production/thirdparty/apt/manifests/backports.pp create mode 100644 environments/production/thirdparty/apt/manifests/conf.pp create mode 100644 environments/production/thirdparty/apt/manifests/init.pp create mode 100644 environments/production/thirdparty/apt/manifests/key.pp create mode 100644 environments/production/thirdparty/apt/manifests/keyring.pp create mode 100644 environments/production/thirdparty/apt/manifests/mark.pp create mode 100644 environments/production/thirdparty/apt/manifests/pin.pp create mode 100644 environments/production/thirdparty/apt/manifests/ppa.pp create mode 100644 environments/production/thirdparty/apt/manifests/setting.pp create mode 100644 environments/production/thirdparty/apt/manifests/source.pp create mode 100644 environments/production/thirdparty/apt/manifests/update.pp create mode 100644 environments/production/thirdparty/apt/metadata.json create mode 100644 environments/production/thirdparty/apt/pdk.yaml create mode 100644 environments/production/thirdparty/apt/provision.yaml create mode 100644 environments/production/thirdparty/apt/tasks/init.json create mode 100755 environments/production/thirdparty/apt/tasks/init.rb create mode 100644 environments/production/thirdparty/apt/templates/_conf_header.epp create mode 100644 environments/production/thirdparty/apt/templates/_header.epp create mode 100644 environments/production/thirdparty/apt/templates/add-apt-repository.sh.epp create mode 100644 environments/production/thirdparty/apt/templates/auth_conf.epp create mode 100644 environments/production/thirdparty/apt/templates/pin.pref.epp create mode 100644 environments/production/thirdparty/apt/templates/proxy.epp create mode 100644 environments/production/thirdparty/apt/templates/source.list.epp create mode 100644 environments/production/thirdparty/apt/templates/source_deb822.epp create mode 100644 environments/production/thirdparty/apt/types/auth_conf_entry.pp create mode 100644 environments/production/thirdparty/apt/types/proxy.pp create mode 100644 environments/production/thirdparty/apt/types/proxy_per_host.pp create mode 100644 environments/production/thirdparty/docker/CHANGELOG.md create mode 100644 environments/production/thirdparty/docker/CODEOWNERS create mode 100644 environments/production/thirdparty/docker/CONTRIBUTING.md create mode 100644 environments/production/thirdparty/docker/CONTRIBUTORS.md create mode 100644 environments/production/thirdparty/docker/HISTORY.md create mode 100644 environments/production/thirdparty/docker/LICENSE create mode 100644 environments/production/thirdparty/docker/README.md create mode 100644 environments/production/thirdparty/docker/REFERENCE.md create mode 100644 environments/production/thirdparty/docker/data/common.yaml create mode 100644 environments/production/thirdparty/docker/functions/sanitised_name.pp create mode 100644 environments/production/thirdparty/docker/hiera.yaml create mode 100644 environments/production/thirdparty/docker/lib/facter/docker.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/functions/docker/env.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/functions/docker_params_changed.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/parser/functions/docker_exec_flags.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/parser/functions/docker_plugin_enable_flags.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/parser/functions/docker_plugin_install_flags.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/parser/functions/docker_plugin_remove_flags.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/parser/functions/docker_run_flags.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/parser/functions/docker_secrets_flags.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/parser/functions/docker_service_flags.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/parser/functions/docker_stack_flags.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/parser/functions/docker_swarm_init_flags.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/parser/functions/docker_swarm_join_flags.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/provider/docker_compose/ruby.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/provider/docker_network/ruby.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/provider/docker_stack/ruby.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/provider/docker_volume/ruby.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/type/docker_compose.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/type/docker_network.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/type/docker_stack.rb create mode 100644 environments/production/thirdparty/docker/lib/puppet/type/docker_volume.rb create mode 100644 environments/production/thirdparty/docker/manifests/compose.pp create mode 100644 environments/production/thirdparty/docker/manifests/config.pp create mode 100644 environments/production/thirdparty/docker/manifests/exec.pp create mode 100644 environments/production/thirdparty/docker/manifests/image.pp create mode 100644 environments/production/thirdparty/docker/manifests/images.pp create mode 100644 environments/production/thirdparty/docker/manifests/init.pp create mode 100644 environments/production/thirdparty/docker/manifests/install.pp create mode 100644 environments/production/thirdparty/docker/manifests/machine.pp create mode 100644 environments/production/thirdparty/docker/manifests/networks.pp create mode 100644 environments/production/thirdparty/docker/manifests/params.pp create mode 100644 environments/production/thirdparty/docker/manifests/plugin.pp create mode 100644 environments/production/thirdparty/docker/manifests/plugins.pp create mode 100644 environments/production/thirdparty/docker/manifests/registry.pp create mode 100644 environments/production/thirdparty/docker/manifests/registry_auth.pp create mode 100644 environments/production/thirdparty/docker/manifests/repos.pp create mode 100644 environments/production/thirdparty/docker/manifests/run.pp create mode 100644 environments/production/thirdparty/docker/manifests/run_instance.pp create mode 100644 environments/production/thirdparty/docker/manifests/service.pp create mode 100644 environments/production/thirdparty/docker/manifests/services.pp create mode 100644 environments/production/thirdparty/docker/manifests/stack.pp create mode 100644 environments/production/thirdparty/docker/manifests/swarm.pp create mode 100644 environments/production/thirdparty/docker/manifests/swarms.pp create mode 100644 environments/production/thirdparty/docker/manifests/system_user.pp create mode 100644 environments/production/thirdparty/docker/manifests/systemd_reload.pp create mode 100644 environments/production/thirdparty/docker/manifests/volumes.pp create mode 100644 environments/production/thirdparty/docker/manifests/windows_account.pp create mode 100644 environments/production/thirdparty/docker/metadata.json create mode 100644 environments/production/thirdparty/docker/pdk.yaml create mode 100644 environments/production/thirdparty/docker/provision.yaml create mode 100644 environments/production/thirdparty/docker/tasks/node_ls.json create mode 100755 environments/production/thirdparty/docker/tasks/node_ls.rb create mode 100644 environments/production/thirdparty/docker/tasks/node_rm.json create mode 100755 environments/production/thirdparty/docker/tasks/node_rm.rb create mode 100644 environments/production/thirdparty/docker/tasks/node_update.json create mode 100755 environments/production/thirdparty/docker/tasks/node_update.rb create mode 100644 environments/production/thirdparty/docker/tasks/service_create.json create mode 100755 environments/production/thirdparty/docker/tasks/service_create.rb create mode 100644 environments/production/thirdparty/docker/tasks/service_rm.json create mode 100755 environments/production/thirdparty/docker/tasks/service_rm.rb create mode 100644 environments/production/thirdparty/docker/tasks/service_scale.json create mode 100755 environments/production/thirdparty/docker/tasks/service_scale.rb create mode 100644 environments/production/thirdparty/docker/tasks/service_update.json create mode 100755 environments/production/thirdparty/docker/tasks/service_update.rb create mode 100644 environments/production/thirdparty/docker/tasks/swarm_init.json create mode 100755 environments/production/thirdparty/docker/tasks/swarm_init.rb create mode 100644 environments/production/thirdparty/docker/tasks/swarm_join.json create mode 100755 environments/production/thirdparty/docker/tasks/swarm_join.rb create mode 100644 environments/production/thirdparty/docker/tasks/swarm_leave.json create mode 100755 environments/production/thirdparty/docker/tasks/swarm_leave.rb create mode 100644 environments/production/thirdparty/docker/tasks/swarm_token.json create mode 100755 environments/production/thirdparty/docker/tasks/swarm_token.rb create mode 100644 environments/production/thirdparty/docker/tasks/swarm_update.json create mode 100755 environments/production/thirdparty/docker/tasks/swarm_update.rb create mode 100644 environments/production/thirdparty/docker/templates/docker-run-start.epp create mode 100644 environments/production/thirdparty/docker/templates/docker-run-stop.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/conf.d/docker.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/conf.d/docker.gentoo.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/default/docker.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/init.d/docker-run.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/sysconfig/docker-storage-setup.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/sysconfig/docker-storage.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/sysconfig/docker.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/sysconfig/docker.systemd.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/systemd/system/docker-run.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/systemd/system/docker.service.d/service-overrides-debian.conf.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/systemd/system/docker.service.d/service-overrides-rhel.conf.epp create mode 100644 environments/production/thirdparty/docker/templates/etc/systemd/system/docker.socket.d/socket-overrides.conf.epp create mode 100644 environments/production/thirdparty/docker/templates/update_docker_image.sh.epp create mode 100644 environments/production/thirdparty/docker/templates/usr/local/bin/docker-run.sh.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/check_docker.ps1.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/check_docker_url.ps1.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/check_hash.ps1.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/check_powershell_provider.ps1.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/compute_hash.ps1.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/config/daemon.json.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/download_docker.ps1.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/download_docker_compose.ps1.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/download_docker_machine.ps1.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/install_powershell_provider.ps1.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/remove_docker.ps1.epp create mode 100644 environments/production/thirdparty/docker/templates/windows/update_docker_image.ps1.epp create mode 100644 environments/production/thirdparty/stdlib/CHANGELOG.md create mode 100644 environments/production/thirdparty/stdlib/CODEOWNERS create mode 100644 environments/production/thirdparty/stdlib/CONTRIBUTING.md create mode 100644 environments/production/thirdparty/stdlib/HISTORY.md create mode 100644 environments/production/thirdparty/stdlib/LICENSE create mode 100644 environments/production/thirdparty/stdlib/NOTICE create mode 100644 environments/production/thirdparty/stdlib/README.md create mode 100644 environments/production/thirdparty/stdlib/README_DEVELOPER.markdown create mode 100644 environments/production/thirdparty/stdlib/README_SPECS.markdown create mode 100644 environments/production/thirdparty/stdlib/REFERENCE.md create mode 100644 environments/production/thirdparty/stdlib/RELEASE_PROCESS.markdown create mode 100644 environments/production/thirdparty/stdlib/data/common.yaml create mode 100644 environments/production/thirdparty/stdlib/examples/file_line.pp create mode 100644 environments/production/thirdparty/stdlib/examples/has_interface_with.pp create mode 100644 environments/production/thirdparty/stdlib/examples/has_ip_address.pp create mode 100644 environments/production/thirdparty/stdlib/examples/has_ip_network.pp create mode 100644 environments/production/thirdparty/stdlib/examples/init.pp create mode 100644 environments/production/thirdparty/stdlib/functions/deferrable_epp.pp create mode 100644 environments/production/thirdparty/stdlib/functions/ensure.pp create mode 100644 environments/production/thirdparty/stdlib/functions/time.pp create mode 100644 environments/production/thirdparty/stdlib/hiera.yaml create mode 100644 environments/production/thirdparty/stdlib/lib/facter/package_provider.rb create mode 100644 environments/production/thirdparty/stdlib/lib/facter/pe_version.rb create mode 100644 environments/production/thirdparty/stdlib/lib/facter/puppet_settings.rb create mode 100644 environments/production/thirdparty/stdlib/lib/facter/root_home.rb create mode 100644 environments/production/thirdparty/stdlib/lib/facter/service_provider.rb create mode 100644 environments/production/thirdparty/stdlib/lib/facter/util/puppet_settings.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/batch_escape.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/deprecation.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/ensure_packages.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/fact.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/fqdn_rand_string.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/fqdn_rotate.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/has_interface_with.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/is_a.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/merge.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/os_version_gte.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/parsehocon.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/parsepson.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/powershell_escape.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/seeded_rand.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/seeded_rand_string.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/shell_escape.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/batch_escape.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/crc32.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/end_with.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/ensure_packages.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/extname.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/fqdn_rand_string.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/fqdn_rotate.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/has_function.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/has_interface_with.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/ip_in_range.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/merge.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/nested_values.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/os_version_gte.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/parsehocon.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/powershell_escape.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/seeded_rand.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/seeded_rand_string.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/sha256.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/shell_escape.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/sort_by.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/start_with.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/str2resource.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/to_json.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/to_json_pretty.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/to_python.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/to_ruby.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/to_toml.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/to_yaml.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/type_of.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/validate_domain_name.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/validate_email_address.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/stdlib/xml_encode.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/time.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/to_json.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/to_json_pretty.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/to_python.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/to_ruby.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/to_toml.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/to_yaml.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/type_of.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/validate_domain_name.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/validate_email_address.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/functions/validate_legacy.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/any2array.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/any2bool.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/assert_private.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/base64.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/basename.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/bool2num.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/bool2str.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/clamp.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/concat.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/convert_base.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/count.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/deep_merge.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/defined_with_params.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/delete.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/delete_at.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/delete_regex.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/delete_undef_values.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/delete_values.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/difference.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/dirname.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/dos2unix.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/enclose_ipv6.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/ensure_resource.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/ensure_resources.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/fqdn_uuid.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/get_module_path.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/getparam.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/glob.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/grep.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/has_interface_with.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/has_ip_address.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/has_ip_network.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/intersection.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/join_keys_to_values.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/load_module_metadata.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/loadjson.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/loadyaml.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/member.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/merge.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/num2bool.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/parsejson.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/parseyaml.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/pick.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/pick_default.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/prefix.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/pry.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/pw_hash.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/range.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/regexpescape.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/reject.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/reverse.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/shell_join.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/shell_split.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/shuffle.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/squeeze.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/str2bool.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/str2saltedpbkdf2.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/str2saltedsha512.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/suffix.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/swapcase.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/to_bytes.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/union.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/unix2dos.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/uriescape.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/validate_augeas.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/validate_cmd.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/validate_x509_rsa_key_pair.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/values_at.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/parser/functions/zip.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/provider/file_line/ruby.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/type/anchor.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet/type/file_line.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet_x/stdlib.rb create mode 100644 environments/production/thirdparty/stdlib/lib/puppet_x/stdlib/toml_dumper.rb create mode 100644 environments/production/thirdparty/stdlib/manifests/init.pp create mode 100644 environments/production/thirdparty/stdlib/manifests/manage.pp create mode 100644 environments/production/thirdparty/stdlib/manifests/stages.pp create mode 100644 environments/production/thirdparty/stdlib/metadata.json create mode 100644 environments/production/thirdparty/stdlib/pdk.yaml create mode 100644 environments/production/thirdparty/stdlib/provision.yaml create mode 100644 environments/production/thirdparty/stdlib/readmes/README_ja_JP.md create mode 100644 environments/production/thirdparty/stdlib/types/absolutepath.pp create mode 100644 environments/production/thirdparty/stdlib/types/base32.pp create mode 100644 environments/production/thirdparty/stdlib/types/base64.pp create mode 100644 environments/production/thirdparty/stdlib/types/createresources.pp create mode 100644 environments/production/thirdparty/stdlib/types/datasize.pp create mode 100644 environments/production/thirdparty/stdlib/types/dns/zone.pp create mode 100644 environments/production/thirdparty/stdlib/types/email.pp create mode 100644 environments/production/thirdparty/stdlib/types/ensure/file.pp create mode 100644 environments/production/thirdparty/stdlib/types/ensure/file/directory.pp create mode 100644 environments/production/thirdparty/stdlib/types/ensure/file/file.pp create mode 100644 environments/production/thirdparty/stdlib/types/ensure/file/link.pp create mode 100644 environments/production/thirdparty/stdlib/types/ensure/package.pp create mode 100644 environments/production/thirdparty/stdlib/types/ensure/service.pp create mode 100644 environments/production/thirdparty/stdlib/types/filemode.pp create mode 100644 environments/production/thirdparty/stdlib/types/filesource.pp create mode 100644 environments/production/thirdparty/stdlib/types/fqdn.pp create mode 100644 environments/production/thirdparty/stdlib/types/host.pp create mode 100644 environments/production/thirdparty/stdlib/types/http/method.pp create mode 100644 environments/production/thirdparty/stdlib/types/http/status.pp create mode 100644 environments/production/thirdparty/stdlib/types/httpstatus.pp create mode 100644 environments/production/thirdparty/stdlib/types/httpsurl.pp create mode 100644 environments/production/thirdparty/stdlib/types/httpurl.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/cidr.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/nosubnet.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v4.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v4/cidr.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v4/nosubnet.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v6.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v6/alternative.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v6/cidr.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v6/compressed.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v6/full.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v6/nosubnet.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v6/nosubnet/alternative.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v6/nosubnet/compressed.pp create mode 100644 environments/production/thirdparty/stdlib/types/ip/address/v6/nosubnet/full.pp create mode 100644 environments/production/thirdparty/stdlib/types/mac.pp create mode 100644 environments/production/thirdparty/stdlib/types/objectstore.pp create mode 100644 environments/production/thirdparty/stdlib/types/objectstore/gsuri.pp create mode 100644 environments/production/thirdparty/stdlib/types/objectstore/s3uri.pp create mode 100644 environments/production/thirdparty/stdlib/types/port.pp create mode 100644 environments/production/thirdparty/stdlib/types/port/dynamic.pp create mode 100644 environments/production/thirdparty/stdlib/types/port/ephemeral.pp create mode 100644 environments/production/thirdparty/stdlib/types/port/privileged.pp create mode 100644 environments/production/thirdparty/stdlib/types/port/registered.pp create mode 100644 environments/production/thirdparty/stdlib/types/port/unprivileged.pp create mode 100644 environments/production/thirdparty/stdlib/types/port/user.pp create mode 100644 environments/production/thirdparty/stdlib/types/syslogfacility.pp create mode 100644 environments/production/thirdparty/stdlib/types/unixpath.pp create mode 100644 environments/production/thirdparty/stdlib/types/windowspath.pp create mode 100644 environments/production/thirdparty/stdlib/types/yes_no.pp create mode 100644 g10k/source.txt create mode 100644 scripts/agent-bootstrap.sh create mode 100755 scripts/push.sh create mode 100644 secrets/.env.example create mode 100644 secrets/README.md create mode 100644 secrets/SECRETS.md create mode 100644 secrets/apply-secrets.ts create mode 100644 secrets/deno-src/source.txt create mode 100644 secrets/secrets.eta diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae31811 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +secrets.pp +.env +.infisical.json +ocis.yaml \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..94443cb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "deno.enable": true, + "deno.path": "./secrets/deno-src/deno" +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a607f3 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# fruit-bowl automation + +## agent bootstrap +```console +apt update && apt install curl -y && curl -sSl https://s3.amy.mov/cluster/agent-bootstrap.sh | sh +``` + +(on the server) +```console +puppetserver ca sign --certname .cluster +``` + +## system bootstrap +### deps +- Deno (for running scripts) +- g10k (for pulling Forge modules) + +### process +- generate some kind of sample secrets file that will then be migrated into Infisical when it is up +- create databases/users in accordance with config.pp so services can come up +- set values in environments/production/config.pp +- add certs into reverse proxy (files/cert/{.key,.pem}) \ No newline at end of file diff --git a/environments/production/Puppetfile b/environments/production/Puppetfile new file mode 100644 index 0000000..1e607ee --- /dev/null +++ b/environments/production/Puppetfile @@ -0,0 +1,5 @@ +moduledir 'thirdparty' + +mod 'puppetlabs-apt', '10.0.1' +mod 'puppetlabs-stdlib', '9.7.0' +mod 'puppetlabs-docker', '10.2.0' \ No newline at end of file diff --git a/environments/production/environment.conf b/environments/production/environment.conf new file mode 100644 index 0000000..abe58c0 --- /dev/null +++ b/environments/production/environment.conf @@ -0,0 +1 @@ +modulepath = ./thirdparty:./modules:$basemodulepath \ No newline at end of file diff --git a/environments/production/manifests/config.pp b/environments/production/manifests/config.pp new file mode 100644 index 0000000..585af79 --- /dev/null +++ b/environments/production/manifests/config.pp @@ -0,0 +1,20 @@ +$authentik_host = "https://auth.amy.mov/" + +$authentik_pg_host = "postgresql.cluster" +$authentik_pg_db = "authentik" +$authentik_pg_user = "authentik" + +$infisical_pg_host = "postgresql.cluster" +$infisical_pg_pass = "infisical" +$infisical_pg_user = "infisical" +$infisical_pg_db = "infisical" + +$pg_oauth2_name = 'authentik' +$pg_oauth2_display_name ='authentik' +$pg_oauth2_token_url ='https://auth.amy.mov/application/o/token/' +$pg_oauth2_authorization_url = 'https://auth.amy.mov/application/o/authorize/' +$pg_oauth2_api_base_url = 'https://auth.amy.mov/' +$pg_oauth2_userinfo_endpoint = 'https://auth.amy.mov/application/o/userinfo/' +$pg_oauth2_server_metadata_url = 'https://auth.amy.mov/application/o/pgadmin/.well-known/openid-configuration' +$pg_oauth2_scope = 'openid email profile' +$pg_oauth2_icon = 'fa-key' diff --git a/environments/production/manifests/site.pp b/environments/production/manifests/site.pp new file mode 100644 index 0000000..8e682f5 --- /dev/null +++ b/environments/production/manifests/site.pp @@ -0,0 +1,63 @@ +$nameservers = ['192.168.1.155', '1.1.1.1'] +include stdlib + +include apt + +include hosts +include dns +include utils +include keys + +# For nodes that haven't got the service enabled +service { 'puppet': + ensure => 'running', + enable => true +} + +# This server itself +node 'puppet-server.cluster' { + include infisical::cli +} + +node 'nginx.cluster' { + include elastic::filebeat + include reverse_proxy +} + +node 'garage.cluster' { + include garage +} + +node 'postgresql.cluster' { + include postgresql +} + +node 'unifi.cluster' { + include unifi +} + +node 'authentik.cluster' { + include authentik +} + +node 'forgejo.cluster' { + include forgejo +} + +node 'kibana.cluster' { + include elastic::kibana +} + +node 'elasticsearch.cluster' { + include elastic::search +} + +node 'owncloud.cluster' { + include owncloud +} + +node 'infisical.cluster' { + include infisical +} + +node default {} diff --git a/environments/production/modules/authentik/files/compose.yml b/environments/production/modules/authentik/files/compose.yml new file mode 100644 index 0000000..e6426bd --- /dev/null +++ b/environments/production/modules/authentik/files/compose.yml @@ -0,0 +1,72 @@ +services: + redis: + image: docker.io/library/redis:alpine + command: --save 60 1 --loglevel warning + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "redis-cli ping | grep PONG"] + start_period: 20s + interval: 30s + retries: 5 + timeout: 3s + volumes: + - redis:/data + server: + image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.2.3} + restart: unless-stopped + command: server + environment: + AUTHENTIK_REDIS__HOST: redis + AUTHENTIK_POSTGRESQL__HOST: ${PG_HOST:-postgresql.cluster} + AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} + AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} + AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} + volumes: + - ./media:/media + - ./custom-templates:/templates + env_file: + - .env + ports: + - "${COMPOSE_PORT_HTTP:-9000}:9000" + - "${COMPOSE_PORT_HTTPS:-9443}:9443" + depends_on: + redis: + condition: service_healthy + rac: + image: ghcr.io/goauthentik/rac:${AUTHENTIK_TAG:-2025.2.3} + restart: unless-stopped + env_file: + - .env + depends_on: + - server + worker: + image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.2.3} + restart: unless-stopped + command: worker + environment: + AUTHENTIK_REDIS__HOST: redis + AUTHENTIK_POSTGRESQL__HOST: ${PG_HOST:-postgresql.cluster} + AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} + AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} + AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} + # `user: root` and the docker socket volume are optional. + # See more for the docker socket integration here: + # https://goauthentik.io/docs/outposts/integrations/docker + # Removing `user: root` also prevents the worker from fixing the permissions + # on the mounted folders, so when removing this make sure the folders have the correct UID/GID + # (1000:1000 by default) + user: root + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./media:/media + - ./certs:/certs + - ./custom-templates:/templates + env_file: + - .env + depends_on: + redis: + condition: service_healthy + +volumes: + redis: + driver: local diff --git a/environments/production/modules/authentik/manifests/init.pp b/environments/production/modules/authentik/manifests/init.pp new file mode 100644 index 0000000..de39ddb --- /dev/null +++ b/environments/production/modules/authentik/manifests/init.pp @@ -0,0 +1,30 @@ +class authentik { + include docker + + contain authentik::install +} + +class authentik::install { + package { 'docker-compose': + ensure => installed + } + + file { '/opt/authentik': + ensure => directory + } + + file { '/opt/authentik/compose.yml': + ensure => file, + source => 'puppet:///modules/authentik/compose.yml' + } + + file { '/opt/authentik/.env': + ensure => file, + content => template('authentik/.env.erb') + } + + docker_compose { 'authentik': + compose_files => ['/opt/authentik/compose.yml'], + ensure => present, + } +} diff --git a/environments/production/modules/authentik/templates/.env.erb b/environments/production/modules/authentik/templates/.env.erb new file mode 100644 index 0000000..51e9129 --- /dev/null +++ b/environments/production/modules/authentik/templates/.env.erb @@ -0,0 +1,9 @@ +AUTHENTIK_HOST=<%= @authentik_host %> +AUTHENTIK_INSECURE=false + +PG_HOST=<%= @authentik_pg_host %> +PG_USER=<%= @authentik_pg_user %> +PG_PASS=<%= @authentik_pg_pass %> + +AUTHENTIK_SECRET_KEY=<%= @authentik_secret_key %> +AUTHENTIK_TOKEN=<%= @authentik_rac_token %> \ No newline at end of file diff --git a/environments/production/modules/dns/manifests/init.pp b/environments/production/modules/dns/manifests/init.pp new file mode 100644 index 0000000..08ff3e7 --- /dev/null +++ b/environments/production/modules/dns/manifests/init.pp @@ -0,0 +1,9 @@ +class dns { + file { '/etc/resolv.conf': + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => template('dns/resolv.conf.erb'), + } +} diff --git a/environments/production/modules/dns/templates/resolv.conf.erb b/environments/production/modules/dns/templates/resolv.conf.erb new file mode 100644 index 0000000..c4404fd --- /dev/null +++ b/environments/production/modules/dns/templates/resolv.conf.erb @@ -0,0 +1,8 @@ +# !! Managed by Puppet !! + +domain cluster +search cluster + +<% [@nameservers].flatten.each do |ns| -%> +nameserver <%= ns %> +<% end -%> \ No newline at end of file diff --git a/environments/production/modules/elastic/files/elastic.yml b/environments/production/modules/elastic/files/elastic.yml new file mode 100644 index 0000000..d857540 --- /dev/null +++ b/environments/production/modules/elastic/files/elastic.yml @@ -0,0 +1,88 @@ +# ======================== Elasticsearch Configuration ========================= +# +# NOTE: Elasticsearch comes with reasonable defaults for most settings. +# Before you set out to tweak and tune the configuration, make sure you +# understand what are you trying to accomplish and the consequences. +# +# The primary way of configuring a node is via this file. This template lists +# the most important settings you may want to configure for a production cluster. +# +# Please consult the documentation for further information on configuration options: +# https://www.elastic.co/guide/en/elasticsearch/reference/index.html +# +# ---------------------------------- Cluster ----------------------------------- +# +# Use a descriptive name for your cluster: +# +#cluster.name: my-application +# +# ------------------------------------ Node ------------------------------------ +# +# Use a descriptive name for the node: +# +node.name: es-1 +# +# Add custom attributes to the node: +# +#node.attr.rack: r1 +# +# ----------------------------------- Paths ------------------------------------ +# +# Path to directory where to store the data (separate multiple locations by comma): +# +path.data: /var/lib/elasticsearch +# +# Path to log files: +# +path.logs: /var/log/elasticsearch +# +# ----------------------------------- Memory ----------------------------------- +# +# Lock the memory on startup: +# +#bootstrap.memory_lock: true +# +# Make sure that the heap size is set to about half the memory available +# on the system and that the owner of the process is allowed to use this +# limit. +# +# Elasticsearch performs poorly when the system is swapping the memory. +# +# ---------------------------------- Network ----------------------------------- +# +# Set the bind address to a specific IP (IPv4 or IPv6): +# +network.host: 0.0.0.0 +# +# Set a custom port for HTTP: +# +#http.port: 9200 +# +# For more information, consult the network module documentation. +# +# --------------------------------- Discovery ---------------------------------- +# +# Pass an initial list of hosts to perform discovery when this node is started: +# The default list of hosts is ["127.0.0.1", "[::1]"] +# +#discovery.seed_hosts: ["host1", "host2"] +# +# Bootstrap the cluster using an initial set of master-eligible nodes: +# +cluster.initial_master_nodes: ["es-1"] +# +# For more information, consult the discovery and cluster formation module documentation. +# +# ---------------------------------- Gateway ----------------------------------- +# +# Block initial recovery after a full cluster restart until N nodes are started: +# +#gateway.recover_after_nodes: 3 +# +# For more information, consult the gateway module documentation. +# +# ---------------------------------- Various ----------------------------------- +# +# Require explicit names when deleting indices: +# +#action.destructive_requires_name: true \ No newline at end of file diff --git a/environments/production/modules/elastic/manifests/filebeat.pp b/environments/production/modules/elastic/manifests/filebeat.pp new file mode 100644 index 0000000..f2456e3 --- /dev/null +++ b/environments/production/modules/elastic/manifests/filebeat.pp @@ -0,0 +1,18 @@ +class elastic::filebeat { + contain elastic::filebeat::install +} + +class elastic::filebeat::install { + file { '/opt/filebeat': + ensure => directory + } + + file { '/opt/filebeat/filebeat.deb': + ensure => file, + source => 'https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.10.2-amd64.deb' + } ~> + package { 'filebeat': + provider => dpkg, + source => "/opt/filebeat/filebeat.deb" + } +} diff --git a/environments/production/modules/elastic/manifests/init.pp b/environments/production/modules/elastic/manifests/init.pp new file mode 100644 index 0000000..4db0652 --- /dev/null +++ b/environments/production/modules/elastic/manifests/init.pp @@ -0,0 +1,3 @@ +class elastic { + +} diff --git a/environments/production/modules/elastic/manifests/kibana.pp b/environments/production/modules/elastic/manifests/kibana.pp new file mode 100644 index 0000000..faed781 --- /dev/null +++ b/environments/production/modules/elastic/manifests/kibana.pp @@ -0,0 +1,35 @@ +class elastic::kibana { + contain elastic::kibana::install + contain elastic::kibana::config + contain elastic::kibana::service +} + +class elastic::kibana::install { + file { '/opt/kibana': + ensure => directory + } + + file { '/opt/kibana/kibana.deb': + ensure => file, + source => 'https://artifacts.elastic.co/downloads/kibana/kibana-7.10.2-amd64.deb' + } ~> + package { 'kibana': + provider => dpkg, + source => "/opt/kibana/kibana.deb" + } +} + +class elastic::kibana::config { + file { '/etc/kibana/kibana.yml': + ensure => file, + content => template('elastic/kibana.yml.erb'), + notify => Service['kibana'] + } +} + +class elastic::kibana::service { + service { 'kibana': + ensure => running, + enable => true + } +} diff --git a/environments/production/modules/elastic/manifests/search.pp b/environments/production/modules/elastic/manifests/search.pp new file mode 100644 index 0000000..85ce9f2 --- /dev/null +++ b/environments/production/modules/elastic/manifests/search.pp @@ -0,0 +1,35 @@ +class elastic::search { + contain elastic::search::install + contain elastic::search::config + contain elastic::search::service +} + +class elastic::search::install { + file { '/opt/search': + ensure => directory + } + + file { '/opt/search/search.deb': + ensure => file, + source => 'https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.10.2-amd64.deb' + } ~> + package { 'search': + provider => dpkg, + source => "/opt/search/search.deb" + } +} + +class elastic::search::config { + file { '/etc/elasticsearch/elasticsearch.yml': + ensure => file, + source => 'puppet:///modules/elastic/elastic.yml', + notify => Service['elasticsearch'] + } +} + +class elastic::search::service { + service { 'elasticsearch': + ensure => running, + enable => true + } +} diff --git a/environments/production/modules/elastic/templates/kibana.yml.erb b/environments/production/modules/elastic/templates/kibana.yml.erb new file mode 100644 index 0000000..bae4eb4 --- /dev/null +++ b/environments/production/modules/elastic/templates/kibana.yml.erb @@ -0,0 +1,111 @@ +# Kibana is served by a back end server. This setting specifies the port to use. +server.port: 5601 + +# Specifies the address to which the Kibana server will bind. IP addresses and host names are both valid values. +# The default is 'localhost', which usually means remote machines will not be able to connect. +# To allow connections from remote users, set this parameter to a non-loopback address. +server.host: "0.0.0.0" + +# Enables you to specify a path to mount Kibana at if you are running behind a proxy. +# Use the `server.rewriteBasePath` setting to tell Kibana if it should remove the basePath +# from requests it receives, and to prevent a deprecation warning at startup. +# This setting cannot end in a slash. +#server.basePath: "" + +# Specifies whether Kibana should rewrite requests that are prefixed with +# `server.basePath` or require that they are rewritten by your reverse proxy. +# This setting was effectively always `false` before Kibana 6.3 and will +# default to `true` starting in Kibana 7.0. +#server.rewriteBasePath: false + +# The maximum payload size in bytes for incoming server requests. +#server.maxPayloadBytes: 1048576 + +# The Kibana server's name. This is used for display purposes. +server.name: "Kibana" + +# The URLs of the Elasticsearch instances to use for all your queries. +elasticsearch.hosts: [ "http://elasticsearch.cluster:9200" ] + +# Kibana uses an index in Elasticsearch to store saved searches, visualizations and +# dashboards. Kibana creates a new index if the index doesn't already exist. +#kibana.index: ".kibana" + +# The default application to load. +#kibana.defaultAppId: "home" + +# If your Elasticsearch is protected with basic authentication, these settings provide +# the username and password that the Kibana server uses to perform maintenance on the Kibana +# index at startup. Your Kibana users still need to authenticate with Elasticsearch, which +# is proxied through the Kibana server. +#elasticsearch.username: "kibana_system" +#elasticsearch.password: "pass" + +# Enables SSL and paths to the PEM-format SSL certificate and SSL key files, respectively. +# These settings enable SSL for outgoing requests from the Kibana server to the browser. +#server.ssl.enabled: false +#server.ssl.certificate: /path/to/your/server.crt +#server.ssl.key: /path/to/your/server.key + +# Optional settings that provide the paths to the PEM-format SSL certificate and key files. +# These files are used to verify the identity of Kibana to Elasticsearch and are required when +# xpack.security.http.ssl.client_authentication in Elasticsearch is set to required. +#elasticsearch.ssl.certificate: /path/to/your/client.crt +#elasticsearch.ssl.key: /path/to/your/client.key + +# Optional setting that enables you to specify a path to the PEM file for the certificate +# authority for your Elasticsearch instance. +#elasticsearch.ssl.certificateAuthorities: [ "/path/to/your/CA.pem" ] + +# To disregard the validity of SSL certificates, change this setting's value to 'none'. +#elasticsearch.ssl.verificationMode: full + +# Time in milliseconds to wait for Elasticsearch to respond to pings. Defaults to the value of +# the elasticsearch.requestTimeout setting. +#elasticsearch.pingTimeout: 1500 + +# Time in milliseconds to wait for responses from the back end or Elasticsearch. This value +# must be a positive integer. +#elasticsearch.requestTimeout: 30000 + +# List of Kibana client-side headers to send to Elasticsearch. To send *no* client-side +# headers, set this value to [] (an empty list). +#elasticsearch.requestHeadersWhitelist: [ authorization ] + +# Header names and values that are sent to Elasticsearch. Any custom headers cannot be overwritten +# by client-side headers, regardless of the elasticsearch.requestHeadersWhitelist configuration. +#elasticsearch.customHeaders: {} + +# Time in milliseconds for Elasticsearch to wait for responses from shards. Set to 0 to disable. +#elasticsearch.shardTimeout: 30000 + +# Logs queries sent to Elasticsearch. Requires logging.verbose set to true. +#elasticsearch.logQueries: false + +# Specifies the path where Kibana creates the process ID file. +#pid.file: /var/run/kibana.pid + +# Enables you to specify a file where Kibana stores log output. +#logging.dest: stdout + +# Set the value of this setting to true to suppress all logging output. +#logging.silent: false + +# Set the value of this setting to true to suppress all logging output other than error messages. +#logging.quiet: false + +# Set the value of this setting to true to log all events, including system usage information +# and all requests. +#logging.verbose: false + +# Set the interval in milliseconds to sample system and process performance +# metrics. Minimum is 100ms. Defaults to 5000. +#ops.interval: 5000 + +# Specifies locale to be used for all localizable strings, dates and number formats. +# Supported languages are the following: English - en , by default , Chinese - zh-CN . +#i18n.locale: "en" + +xpack: + encryptedSavedObjects: + encryptionKey: '<%= @kibana_encryption_key %>' diff --git a/environments/production/modules/forgejo/files/forgejo.service b/environments/production/modules/forgejo/files/forgejo.service new file mode 100644 index 0000000..32d8355 --- /dev/null +++ b/environments/production/modules/forgejo/files/forgejo.service @@ -0,0 +1,15 @@ +[Unit] +Description=Forgejo +Wants=basic.target +After=basic.target network.target + +[Service] +WorkingDirectory=/opt/forgejo +ExecStart=/opt/forgejo/forgejo +User=forgejo +KillMode=process +Restart=on-failure +RestartSec=30s + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/environments/production/modules/forgejo/manifests/init.pp b/environments/production/modules/forgejo/manifests/init.pp new file mode 100644 index 0000000..c3b2678 --- /dev/null +++ b/environments/production/modules/forgejo/manifests/init.pp @@ -0,0 +1,41 @@ +class forgejo { + contain forgejo::install + contain forgejo::service +} + +class forgejo::install { + user { 'forgejo': + ensure => 'present', + } + + file { '/opt/forgejo': + ensure => directory, + owner => 'forgejo', + } + + file { '/opt/forgejo/forgejo': + source => 'https://codeberg.org/forgejo/forgejo/releases/download/v10.0.3/forgejo-10.0.3-linux-amd64', + ensure => file, + owner => 'forgejo', + mode => '0744' + } +} + + +class forgejo::service { + file { '/lib/systemd/system/forgejo.service': + ensure => file, + source => 'puppet:///modules/forgejo/forgejo.service', + notify => Service['forgejo'] + }~> + exec { 'forgejo-systemd-reload': + command => 'systemctl daemon-reload', + path => [ '/usr/bin', '/bin', '/usr/sbin' ], + refreshonly => true, + } + + service { 'forgejo': + ensure => running, + enable => true, + } +} diff --git a/environments/production/modules/garage/manifests/init.pp b/environments/production/modules/garage/manifests/init.pp new file mode 100644 index 0000000..9ecb670 --- /dev/null +++ b/environments/production/modules/garage/manifests/init.pp @@ -0,0 +1,48 @@ +class garage { + contain garage::install + contain garage::config + contain garage::service + + contain garage::webui +} + +class garage::install { + file { '/opt/garage': + ensure => directory, + mode => '0640' + } + + file { '/opt/garage/garage': + ensure => file, + source => 'https://garagehq.deuxfleurs.fr/_releases/v1.1.0/x86_64-unknown-linux-musl/garage', + mode => '0740' + } +} + +class garage::config { + file { '/opt/garage/garage.toml': + content => template('garage/conf.toml.erb'), + ensure => file, + mode => '0644', + notify => [Service['garage'], Service['garage-webui']] + } +} + +class garage::service { + file { '/lib/systemd/system/garage.service': + mode => '0644', + owner => 'root', + group => 'root', + content => template('garage/garage.service.erb'), + }~> + exec { 'garage-systemd-reload': + command => 'systemctl daemon-reload', + path => [ '/usr/bin', '/bin', '/usr/sbin' ], + refreshonly => true, + } + + service { 'garage': + ensure => running, + enable => true, + } +} diff --git a/environments/production/modules/garage/manifests/webui.pp b/environments/production/modules/garage/manifests/webui.pp new file mode 100644 index 0000000..d5e551b --- /dev/null +++ b/environments/production/modules/garage/manifests/webui.pp @@ -0,0 +1,35 @@ +class garage::webui { + contain garage::webui::install + contain garage::webui::service +} + +class garage::webui::install { + file { '/opt/garage-webui': + ensure => directory + } + + file { '/opt/garage-webui/webui': + source => 'https://github.com/khairul169/garage-webui/releases/download/1.0.8/garage-webui-v1.0.8-linux-amd64', + ensure => 'file', + mode => '0740', + } +} + +class garage::webui::service { + file { '/lib/systemd/system/garage-webui.service': + mode => '0644', + owner => 'root', + group => 'root', + content => template('garage/garage-webui.service.erb'), + }~> + exec { 'garage-webui-systemd-reload': + command => 'systemctl daemon-reload', + path => [ '/usr/bin', '/bin', '/usr/sbin' ], + refreshonly => true, + } + + service { 'garage-webui': + ensure => running, + enable => true, + } +} diff --git a/environments/production/modules/garage/templates/conf.toml.erb b/environments/production/modules/garage/templates/conf.toml.erb new file mode 100644 index 0000000..b233afd --- /dev/null +++ b/environments/production/modules/garage/templates/conf.toml.erb @@ -0,0 +1,28 @@ +metadata_dir = "/opt/garage/meta" +data_dir = "/opt/garage/data" + +db_engine = "sqlite" + +replication_factor = 1 + +rpc_bind_addr = "[::]:3901" +rpc_public_addr = "127.0.0.1:3901" +rpc_secret = "<%= @garage_rpc_secret %>" + +[s3_api] +s3_region = "garage" +api_bind_addr = "[::]:3900" +root_domain = ".s3.amy.mov" + +[s3_web] +bind_addr = "[::]:3902" +root_domain = ".s3.amy.mov" +index = "index.html" + +[k2v_api] +api_bind_addr = "[::]:3904" + +[admin] +api_bind_addr = "[::]:3903" +admin_token = "<%= @garage_admin_token %>" +metrics_token = "<%= @garage_metrics_token %>" \ No newline at end of file diff --git a/environments/production/modules/garage/templates/garage-webui.service.erb b/environments/production/modules/garage/templates/garage-webui.service.erb new file mode 100644 index 0000000..7f47eee --- /dev/null +++ b/environments/production/modules/garage/templates/garage-webui.service.erb @@ -0,0 +1,15 @@ +[Unit] +Description=GarageHQ WebUI +Wants=basic.target +After=basic.target network.target + +[Service] +WorkingDirectory=/opt/garage-webui +Environment="CONFIG_PATH=/opt/garage/garage.toml" +ExecStart=/opt/garage-webui/webui +KillMode=process +Restart=on-failure +RestartSec=30s + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/environments/production/modules/garage/templates/garage.service.erb b/environments/production/modules/garage/templates/garage.service.erb new file mode 100644 index 0000000..3b8d98f --- /dev/null +++ b/environments/production/modules/garage/templates/garage.service.erb @@ -0,0 +1,14 @@ +[Unit] +Description=GarageHQ +Wants=basic.target +After=basic.target network.target + +[Service] +WorkingDirectory=/opt/garage +ExecStart=/opt/garage/garage -c /opt/garage/garage.toml server +KillMode=process +Restart=on-failure +RestartSec=30s + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/environments/production/modules/hosts/manifests/init.pp b/environments/production/modules/hosts/manifests/init.pp new file mode 100644 index 0000000..59326a2 --- /dev/null +++ b/environments/production/modules/hosts/manifests/init.pp @@ -0,0 +1,9 @@ +class hosts { + file { '/etc/hosts': + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => template('hosts/hosts.erb'), + } +} diff --git a/environments/production/modules/hosts/templates/hosts.erb b/environments/production/modules/hosts/templates/hosts.erb new file mode 100644 index 0000000..3008921 --- /dev/null +++ b/environments/production/modules/hosts/templates/hosts.erb @@ -0,0 +1,12 @@ +# !! Managed by Puppet !! + +127.0.0.1 localhost +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters + +# --- BEGIN PVE --- + +127.0.1.1 <%= @networking['hostname'] %>.cluster <%= @networking['hostname'] %> +192.168.1.200 internal-s3.amy.mov +# --- END PVE --- diff --git a/environments/production/modules/infisical/files/compose.yml b/environments/production/modules/infisical/files/compose.yml new file mode 100644 index 0000000..2427bc3 --- /dev/null +++ b/environments/production/modules/infisical/files/compose.yml @@ -0,0 +1,36 @@ +services: + backend: + container_name: infisical-backend + restart: unless-stopped + depends_on: + redis: + condition: service_started + image: infisical/infisical:latest-postgres + pull_policy: always + env_file: .env + ports: + - 8080:8080 + environment: + - NODE_ENV=production + networks: + - infisical + + redis: + image: redis + container_name: infisical-dev-redis + env_file: .env + restart: always + environment: + - ALLOW_EMPTY_PASSWORD=yes + ports: + - 6379:6379 + networks: + - infisical + volumes: + - redis_data:/data +volumes: + redis_data: + driver: local + +networks: + infisical: diff --git a/environments/production/modules/infisical/manifests/cli.pp b/environments/production/modules/infisical/manifests/cli.pp new file mode 100644 index 0000000..2944a97 --- /dev/null +++ b/environments/production/modules/infisical/manifests/cli.pp @@ -0,0 +1,18 @@ +class infisical::cli { + contain infisical::cli::install +} + +class infisical::cli::install { + file { '/opt/infisical': + ensure => directory + } + + file { '/opt/infisical/infisical-cli.deb': + ensure => file, + source => 'https://github.com/Infisical/infisical/releases/download/infisical-cli%2Fv0.36.22/infisical_0.36.22_linux_amd64.deb' + } ~> + package { '/opt/infisical/infisical-cli.deb': + provider => dpkg, + source => '/opt/infisical/infisical-cli.deb' + } +} diff --git a/environments/production/modules/infisical/manifests/init.pp b/environments/production/modules/infisical/manifests/init.pp new file mode 100644 index 0000000..73034d6 --- /dev/null +++ b/environments/production/modules/infisical/manifests/init.pp @@ -0,0 +1,29 @@ +class infisical { + include docker + + contain infisical::install +} + +class infisical::install { + package { 'docker-compose': + ensure => installed + } + + file { '/opt/infisical': + ensure => directory + } + + file { '/opt/infisical/compose.yml': + ensure => file, + source => 'puppet:///modules/infisical/compose.yml' + } + file { '/opt/infisical/.env': + ensure => file, + source => 'puppet:///modules/infisical/.env' + } + + docker_compose { 'infisical': + compose_files => ['/opt/infisical/compose.yml'], + ensure => present, + } +} diff --git a/environments/production/modules/infisical/templates/.env.erb b/environments/production/modules/infisical/templates/.env.erb new file mode 100644 index 0000000..e897114 --- /dev/null +++ b/environments/production/modules/infisical/templates/.env.erb @@ -0,0 +1,124 @@ + +# Keys +# Required key for platform encryption/decryption ops +# THIS IS A SAMPLE ENCRYPTION KEY AND SHOULD NEVER BE USED FOR PRODUCTION +ENCRYPTION_KEY="<%= @infisical_encryption_key %>" + +# JWT +# Required secrets to sign JWT tokens +# THIS IS A SAMPLE AUTH_SECRET KEY AND SHOULD NEVER BE USED FOR PRODUCTION +AUTH_SECRET="<%= @infisical_auth_secret %>" + +# Postgres creds +PG_HOST="<%= @infisical_pg_host %>" +PG_USER="<%= @infisical_pg_user %>" +PG_PASS="<%= @infisical_pg_pass %>" +PG_DB="<%= @infisical_pg_db %>" + +# Required +DB_CONNECTION_URI=postgres://${PG_USER}:${PG_PASS}@${PG_HOST}:5432/${PG_DB} + +# Redis +REDIS_URL=redis://redis:6379 + +# Website URL +# Required +SITE_URL=http://localhost:8080 + +# Mail/SMTP +SMTP_HOST= +SMTP_PORT= +SMTP_FROM_ADDRESS= +SMTP_FROM_NAME= +SMTP_USERNAME= +SMTP_PASSWORD= + +# Integration +# Optional only if integration is used +CLIENT_ID_HEROKU= +CLIENT_ID_VERCEL= +CLIENT_ID_NETLIFY= +CLIENT_ID_GITHUB= +CLIENT_ID_GITHUB_APP= +CLIENT_SLUG_GITHUB_APP= +CLIENT_ID_GITLAB= +CLIENT_ID_BITBUCKET= +CLIENT_SECRET_HEROKU= +CLIENT_SECRET_VERCEL= +CLIENT_SECRET_NETLIFY= +CLIENT_SECRET_GITHUB= +CLIENT_SECRET_GITHUB_APP= +CLIENT_SECRET_GITLAB= +CLIENT_SECRET_BITBUCKET= +CLIENT_SLUG_VERCEL= + +CLIENT_PRIVATE_KEY_GITHUB_APP= +CLIENT_APP_ID_GITHUB_APP= + +# Sentry (optional) for monitoring errors +SENTRY_DSN= + +# Infisical Cloud-specific configs +# Ignore - Not applicable for self-hosted version +POSTHOG_HOST= +POSTHOG_PROJECT_API_KEY= + +# SSO-specific variables +CLIENT_ID_GOOGLE_LOGIN= +CLIENT_SECRET_GOOGLE_LOGIN= + +CLIENT_ID_GITHUB_LOGIN= +CLIENT_SECRET_GITHUB_LOGIN= + +CLIENT_ID_GITLAB_LOGIN= +CLIENT_SECRET_GITLAB_LOGIN= + +CAPTCHA_SECRET= + +NEXT_PUBLIC_CAPTCHA_SITE_KEY= + +OTEL_TELEMETRY_COLLECTION_ENABLED=false +OTEL_EXPORT_TYPE=prometheus +OTEL_EXPORT_OTLP_ENDPOINT= +OTEL_OTLP_PUSH_INTERVAL= + +OTEL_COLLECTOR_BASIC_AUTH_USERNAME= +OTEL_COLLECTOR_BASIC_AUTH_PASSWORD= + +PLAIN_API_KEY= +PLAIN_WISH_LABEL_IDS= + +SSL_CLIENT_CERTIFICATE_HEADER_KEY= + +ENABLE_MSSQL_SECRET_ROTATION_ENCRYPT=true + +# App Connections + +# aws assume-role connection +INF_APP_CONNECTION_AWS_ACCESS_KEY_ID= +INF_APP_CONNECTION_AWS_SECRET_ACCESS_KEY= + +# github oauth connection +INF_APP_CONNECTION_GITHUB_OAUTH_CLIENT_ID= +INF_APP_CONNECTION_GITHUB_OAUTH_CLIENT_SECRET= + +#github app connection +INF_APP_CONNECTION_GITHUB_APP_CLIENT_ID= +INF_APP_CONNECTION_GITHUB_APP_CLIENT_SECRET= +INF_APP_CONNECTION_GITHUB_APP_PRIVATE_KEY= +INF_APP_CONNECTION_GITHUB_APP_SLUG= +INF_APP_CONNECTION_GITHUB_APP_ID= + +#gcp app connection +INF_APP_CONNECTION_GCP_SERVICE_ACCOUNT_CREDENTIAL= + +# azure app connection +INF_APP_CONNECTION_AZURE_CLIENT_ID= +INF_APP_CONNECTION_AZURE_CLIENT_SECRET= + +# datadog +SHOULD_USE_DATADOG_TRACER= +DATADOG_PROFILING_ENABLED= +DATADOG_ENV= +DATADOG_SERVICE= +DATADOG_HOSTNAME= diff --git a/environments/production/modules/keys/files/puppet-push.pub b/environments/production/modules/keys/files/puppet-push.pub new file mode 100644 index 0000000..4068c92 --- /dev/null +++ b/environments/production/modules/keys/files/puppet-push.pub @@ -0,0 +1,2 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK0MxN/ReEZsnPUWJz+UEq8okZIri+hDXClO/EUsaSFeQtuf5unr5zZ9ErMGmPTbyBloBEh7ZauFVmpwn6y9n9M= root@puppet-server +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK3ukunRoN0+GupDQwujcN3htQGERmEB+Sd5f33PqNhNXsR2EfBwg463lYiCRZo9CQ/hDjrYv5A9TLg8us1B5iA= amy@nixon \ No newline at end of file diff --git a/environments/production/modules/keys/manifests/init.pp b/environments/production/modules/keys/manifests/init.pp new file mode 100644 index 0000000..dd267b7 --- /dev/null +++ b/environments/production/modules/keys/manifests/init.pp @@ -0,0 +1,8 @@ +class keys { + file { '/root/.ssh/authorized_keys': + source => 'puppet:///modules/keys/puppet-push.pub', + owner => 'root', + group => 'root', + mode => '0640', + } +} diff --git a/environments/production/modules/owncloud/manifests/init.pp b/environments/production/modules/owncloud/manifests/init.pp new file mode 100644 index 0000000..9d6f557 --- /dev/null +++ b/environments/production/modules/owncloud/manifests/init.pp @@ -0,0 +1,43 @@ +class owncloud { + contain owncloud::install + contain owncloud::config + contain owncloud::service +} + +class owncloud::install { + file { '/opt/owncloud': + ensure => directory + } + + file { '/opt/owncloud/ocis': + ensure => file, + source => 'https://github.com/owncloud/ocis/releases/download/v7.1.2/ocis-7.1.2-linux-amd64', + mode => '0744' + } +} + +class owncloud::config { + file { '/opt/owncloud/ocis.yaml': + ensure => file, + source => 'puppet:///modules/owncloud/ocis.yaml', + notify => Service['owncloud'] + } +} + +class owncloud::service { + file { '/lib/systemd/system/owncloud.service': + ensure => file, + content => template('owncloud/owncloud.service.erb'), + notify => Service['owncloud'] + }~> + exec { 'owncloud-systemd-reload': + command => 'systemctl daemon-reload', + path => [ '/usr/bin', '/bin', '/usr/sbin' ], + refreshonly => true, + } + + service { 'owncloud': + ensure => running, + enable => true, + } +} diff --git a/environments/production/modules/owncloud/templates/owncloud.service.erb b/environments/production/modules/owncloud/templates/owncloud.service.erb new file mode 100644 index 0000000..061e86e --- /dev/null +++ b/environments/production/modules/owncloud/templates/owncloud.service.erb @@ -0,0 +1,32 @@ +[Unit] +Description=OwnCloud +Wants=basic.target +After=basic.target network.target + +[Service] +WorkingDirectory=/opt/owncloud +ExecStart=/opt/owncloud/ocis server + +Environment="PROXY_HTTP_ADDR=0.0.0.0:9200" +Environment="OCIS_URL=https://cloud.amy.mov" +Environment="OCIS_BASE_DATA_PATH=/opt/owncloud/" +Environment="OCIS_CONFIG_DIR=/opt/owncloud/" + +Environment="OCIS_INSECURE=true" + +Environment="STORAGE_USERS_DRIVER=s3ng" +Environment="STORAGE_HOME_DRIVER=s3ng" +Environment="STORAGE_METADATA_DRIVER=ocis" + +Environment="STORAGE_USERS_S3NG_REGION=garage" +Environment="STORAGE_USERS_S3NG_ENDPOINT=https://internal-s3.amy.mov" +Environment="STORAGE_USERS_S3NG_SECRET_KEY="<%= @oc_s3_secret_key %>" +Environment="STORAGE_USERS_S3NG_ACCESS_KEY="<%= @oc_s3_access_key %>" +Environment="STORAGE_USERS_S3NG_BUCKET=cloud" + +KillMode=process +Restart=on-failure +RestartSec=30s + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/environments/production/modules/postgresql/manifests/init.pp b/environments/production/modules/postgresql/manifests/init.pp new file mode 100644 index 0000000..5452e87 --- /dev/null +++ b/environments/production/modules/postgresql/manifests/init.pp @@ -0,0 +1,34 @@ +class postgresql { + contain postgresql::install + + contain postgresql::pgadmin +} + +class postgresql::install { + # https://www.postgresql.org/download/linux/debian/ + package { 'postgresql-common': + ensure => installed + } ~> + exec { 'postgresql-install': + command => '/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y', + refreshonly => true, + } ~> + exec { 'postgresql-apt-update': + command => 'apt update', + path => ['/usr/bin'], + refreshonly => true, + } ~> + package { 'postgresql-16': + ensure => installed + } ~> + package { 'postgresql-client-16': + ensure => installed + } +} + +class postgresql::service { + service { 'postgresql': + ensure => running, + enable => true + } +} diff --git a/environments/production/modules/postgresql/manifests/pgadmin.pp b/environments/production/modules/postgresql/manifests/pgadmin.pp new file mode 100644 index 0000000..28041ca --- /dev/null +++ b/environments/production/modules/postgresql/manifests/pgadmin.pp @@ -0,0 +1,42 @@ +class postgresql::pgadmin { + contain postgresql::pgadmin::install + contain postgresql::pgadmin::config +} + + +class postgresql::pgadmin::install { + apt::source { 'pgadmin': + comment => 'PGAdmin Repo', + location => 'https://ftp.postgresql.org/pub/pgadmin/pgadmin4/apt/bookworm', + release => 'pgadmin4', + repos => 'main', + key => { + 'name' => 'pgadmin.pub', + 'source' => 'https://www.pgadmin.org/static/packages_pgadmin_org.pub', + }, + include => { + 'deb' => true, + }, + } + + package { 'pgadmin4-web': + ensure => installed + } +} + +class postgresql::pgadmin::config { + exec { 'pgadmin-setup': + command => '/usr/pgadmin4/bin/setup-web.sh --yes', + environment => [ + "PGADMIN_SETUP_EMAIL=$pg_setup_email", + "PGADMIN_SETUP_PASSWORD=$pg_setup_password" + ], + path => ['/usr/bin'], + unless => ['test -f /var/lib/pgadmin', 'test -f /var/log/pgadmin'] + } + + file { '/usr/pgadmin4/web/config_local.py': + ensure => file, + content => template('postgresql/config_local.py.erb') + } +} diff --git a/environments/production/modules/postgresql/templates/config_local.py.erb b/environments/production/modules/postgresql/templates/config_local.py.erb new file mode 100644 index 0000000..7e8fd69 --- /dev/null +++ b/environments/production/modules/postgresql/templates/config_local.py.erb @@ -0,0 +1,17 @@ +AUTHENTICATION_SOURCES = ['oauth2', 'internal'] +OAUTH2_AUTO_CREATE_USER = True +OAUTH2_CONFIG = [{ + 'OAUTH2_NAME': '<%= @pg_oauth2_name %>', + 'OAUTH2_DISPLAY_NAME': '<%= @pg_oauth2_display_name %>', + 'OAUTH2_CLIENT_ID': '<%= @pg_oauth2_client_id %>', + 'OAUTH2_CLIENT_SECRET': '<%= @pg_oauth2_client_secret %>', + 'OAUTH2_TOKEN_URL': '<%= @pg_oauth2_token_url %>', + 'OAUTH2_AUTHORIZATION_URL': '<%= @pg_oauth2_authorization_url %>', + 'OAUTH2_API_BASE_URL': '<%= @pg_oauth2_api_base_url %>', + 'OAUTH2_USERINFO_ENDPOINT': '<%= @pg_oauth2_userinfo_endpoint %>', + 'OAUTH2_SERVER_METADATA_URL': '<%= @pg_oauth2_server_metadata_url %>', + 'OAUTH2_SCOPE': '<%= @pg_oauth2_scope %>', + 'OAUTH2_ICON': '<%= @pg_oauth2_icon %>' +}] + +WTF_CSRF_HEADERS = ['X-CSRF'] \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/.gitignore b/environments/production/modules/reverse_proxy/files/.gitignore new file mode 100644 index 0000000..13ac862 --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/.gitignore @@ -0,0 +1 @@ +cert/ \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/conf.d/auth.amy.mov b/environments/production/modules/reverse_proxy/files/conf.d/auth.amy.mov new file mode 100644 index 0000000..f00b8a3 --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/conf.d/auth.amy.mov @@ -0,0 +1,137 @@ +map $http_upgrade $connection_upgrade_keepalive { + default upgrade; + '' ''; +} + +server { + listen 443 ssl; + server_name auth.amy.mov; + resolver 192.168.1.155; + + location / { + proxy_http_version 1.1; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade_keepalive; + + proxy_pass http://authentik.cluster:9000; + } +} + +server { + listen 443 ssl; + server_name garage.amy.mov; + + proxy_buffers 8 16k; + proxy_buffer_size 32k; + + location / { + # Where should the authenticated requests go + proxy_pass http://garage.cluster:3909; + + proxy_set_header Host $host; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade_keepalive; + + auth_request /outpost.goauthentik.io/auth/nginx; + error_page 401 = @goauthentik_proxy_signin; + auth_request_set $auth_cookie $upstream_http_set_cookie; + add_header Set-Cookie $auth_cookie; + + auth_request_set $authentik_username $upstream_http_x_authentik_username; + auth_request_set $authentik_groups $upstream_http_x_authentik_groups; + auth_request_set $authentik_entitlements $upstream_http_x_authentik_entitlements; + auth_request_set $authentik_email $upstream_http_x_authentik_email; + auth_request_set $authentik_name $upstream_http_x_authentik_name; + auth_request_set $authentik_uid $upstream_http_x_authentik_uid; + + proxy_set_header X-authentik-username $authentik_username; + proxy_set_header X-authentik-groups $authentik_groups; + proxy_set_header X-authentik-entitlements $authentik_entitlements; + proxy_set_header X-authentik-email $authentik_email; + proxy_set_header X-authentik-name $authentik_name; + proxy_set_header X-authentik-uid $authentik_uid; + } + + # All requests to /outpost.goauthentik.io must be accessible without authentication + location /outpost.goauthentik.io { + proxy_pass http://authentik.cluster:9000/outpost.goauthentik.io; + + # Note: ensure the Host header matches your external authentik URL: + proxy_set_header Host $host; + + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + add_header Set-Cookie $auth_cookie; + auth_request_set $auth_cookie $upstream_http_set_cookie; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + } + + location @goauthentik_proxy_signin { + internal; + add_header Set-Cookie $auth_cookie; + return 302 /outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri; + } +} + +server { + listen 443 ssl; + server_name calibre.amy.mov; + + proxy_buffers 8 16k; + proxy_buffer_size 32k; + + location / { + # Where should the authenticated requests go + proxy_pass http://calibre.cluster:8080; + + proxy_set_header Host $host; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade_keepalive; + + auth_request /outpost.goauthentik.io/auth/nginx; + error_page 401 = @goauthentik_proxy_signin; + auth_request_set $auth_cookie $upstream_http_set_cookie; + add_header Set-Cookie $auth_cookie; + + auth_request_set $authentik_username $upstream_http_x_authentik_username; + auth_request_set $authentik_groups $upstream_http_x_authentik_groups; + auth_request_set $authentik_entitlements $upstream_http_x_authentik_entitlements; + auth_request_set $authentik_email $upstream_http_x_authentik_email; + auth_request_set $authentik_name $upstream_http_x_authentik_name; + auth_request_set $authentik_uid $upstream_http_x_authentik_uid; + + proxy_set_header X-authentik-username $authentik_username; + proxy_set_header X-authentik-groups $authentik_groups; + proxy_set_header X-authentik-entitlements $authentik_entitlements; + proxy_set_header X-authentik-email $authentik_email; + proxy_set_header X-authentik-name $authentik_name; + proxy_set_header X-authentik-uid $authentik_uid; + + # Since we're overwriting the Basic Auth headers + auth_request_set $authentik_auth $upstream_http_authorization; + proxy_set_header Authorization $authentik_auth; + } + + # All requests to /outpost.goauthentik.io must be accessible without authentication + location /outpost.goauthentik.io { + proxy_pass http://authentik.cluster:9000/outpost.goauthentik.io; + + # Note: ensure the Host header matches your external authentik URL: + proxy_set_header Host $host; + + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + add_header Set-Cookie $auth_cookie; + auth_request_set $auth_cookie $upstream_http_set_cookie; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + } + + location @goauthentik_proxy_signin { + internal; + add_header Set-Cookie $auth_cookie; + return 302 /outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri; + } +} \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/conf.d/blog.amy.mov b/environments/production/modules/reverse_proxy/files/conf.d/blog.amy.mov new file mode 100644 index 0000000..01de0da --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/conf.d/blog.amy.mov @@ -0,0 +1,13 @@ +server { + listen 443 ssl; + server_name blog.amy.mov; + + location / { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $http_host; + + proxy_pass http://192.168.1.210:2368; + } +} \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/conf.d/cloud.amy.mov b/environments/production/modules/reverse_proxy/files/conf.d/cloud.amy.mov new file mode 100644 index 0000000..8eb51a3 --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/conf.d/cloud.amy.mov @@ -0,0 +1,13 @@ +# !! Managed by Puppet !! + +server { + listen 443 ssl; + server_name cloud.amy.mov; + + location / { + proxy_pass https://owncloud.cluster:9200; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/conf.d/fedi.amy.mov b/environments/production/modules/reverse_proxy/files/conf.d/fedi.amy.mov new file mode 100644 index 0000000..b76fbe2 --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/conf.d/fedi.amy.mov @@ -0,0 +1,13 @@ +# !! Managed by Puppet !! + +server { + listen 443 ssl; + server_name fedi.amy.mov; + + location / { + proxy_pass http://192.168.1.201:3000; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/conf.d/forge.amy.mov b/environments/production/modules/reverse_proxy/files/conf.d/forge.amy.mov new file mode 100644 index 0000000..248fa2f --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/conf.d/forge.amy.mov @@ -0,0 +1,14 @@ +# !! Managed by Puppet !! + +server { + listen 443 ssl; + server_name forge.amy.mov; + resolver 192.168.1.155; + + location / { + proxy_pass http://forgejo.cluster:3000; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/conf.d/internal-s3.amy.mov b/environments/production/modules/reverse_proxy/files/conf.d/internal-s3.amy.mov new file mode 100644 index 0000000..8dfab14 --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/conf.d/internal-s3.amy.mov @@ -0,0 +1,11 @@ +server { + listen 443 ssl; + server_name internal-s3.amy.mov; + resolver 192.168.1.155; + + location / { + proxy_set_header Host internal-s3.amy.mov; + + proxy_pass http://garage.cluster:3900; + } +} \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/conf.d/pg.amy.mov b/environments/production/modules/reverse_proxy/files/conf.d/pg.amy.mov new file mode 100644 index 0000000..f901be1 --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/conf.d/pg.amy.mov @@ -0,0 +1,13 @@ +server { + listen 443 ssl; + server_name pg.amy.mov; + + location / { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $http_host; + + proxy_pass http://postgresql.cluster; + } +} \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/conf.d/s3.amy.mov b/environments/production/modules/reverse_proxy/files/conf.d/s3.amy.mov new file mode 100644 index 0000000..b56c8a1 --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/conf.d/s3.amy.mov @@ -0,0 +1,15 @@ +server { + listen 443 ssl; + server_name s3.amy.mov; + resolver 192.168.1.155; + + # Rewriting path based buckets to vhost buckets, ie: + # s3.amy.mov/test-bucket => test-bucket.s3.amy.mov + location ~ ^/([^/]+)(.*)$ { + # Set the host so Garage thinks we are coming from a vhost + proxy_set_header Host $1.s3.amy.mov; + + # But pass the path ($2) to the real proxy + proxy_pass http://garage.cluster:3902$2; + } +} \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/conf.d/secrets.amy.mov b/environments/production/modules/reverse_proxy/files/conf.d/secrets.amy.mov new file mode 100644 index 0000000..d9bb692 --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/conf.d/secrets.amy.mov @@ -0,0 +1,13 @@ +server { + listen 443 ssl; + server_name secrets.amy.mov; + + location / { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $http_host; + + proxy_pass http://infisical.cluster:8080; + } +} \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/files/nginx.conf b/environments/production/modules/reverse_proxy/files/nginx.conf new file mode 100644 index 0000000..8f515b6 --- /dev/null +++ b/environments/production/modules/reverse_proxy/files/nginx.conf @@ -0,0 +1,31 @@ +# !! Managed by Puppet !! + +user www-data; +worker_processes auto; + +pid /run/nginx.pid; + +events { + worker_connections 768; +} + +http { + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + sendfile on; + tcp_nopush on; + types_hash_max_size 2048; + + client_max_body_size 15M; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + + ssl_certificate /etc/nginx/cert/cf.pem; + ssl_certificate_key /etc/nginx/cert/cf.key; + + include /etc/nginx/conf.d/*; +} \ No newline at end of file diff --git a/environments/production/modules/reverse_proxy/manifests/init.pp b/environments/production/modules/reverse_proxy/manifests/init.pp new file mode 100644 index 0000000..5a81db0 --- /dev/null +++ b/environments/production/modules/reverse_proxy/manifests/init.pp @@ -0,0 +1,56 @@ +class reverse_proxy { + contain reverse_proxy::install + contain reverse_proxy::config + contain reverse_proxy::service +} + +class reverse_proxy::install { + package { 'nginx': + ensure => installed, + } +} + +define reverse_proxy::conf_file ( + $dest_base, + $source_base, + $group = 'www-data', + $owner = 'www-data', + $mode = '0640', +) { + file { "${dest_base}/${name}": + source => "${source_base}/${name}", + ensure => 'present', + group => $group, + owner => $owner, + mode => $mode, + notify => Service['nginx'], + } +} + +class reverse_proxy::config { + $config_files = [ + # Make our dirs first + 'conf.d', 'cert', + + # Then we can populate them + 'conf.d/fedi.amy.mov', 'conf.d/s3.amy.mov', 'conf.d/blog.amy.mov', 'conf.d/auth.amy.mov', 'conf.d/pg.amy.mov', + 'conf.d/forge.amy.mov', 'conf.d/cloud.amy.mov', 'conf.d/secrets.amy.mov', + + 'conf.d/internal-s3.amy.mov', + + 'cert/cf.key', 'cert/cf.pem', + 'nginx.conf' + ] + + reverse_proxy::conf_file { $config_files: + source_base => 'puppet:///modules/reverse_proxy', + dest_base => '/etc/nginx' + } +} + +class reverse_proxy::service { + service { 'nginx': + ensure => running, + enable => true, + } +} diff --git a/environments/production/modules/unifi/files/libssl1.1.deb b/environments/production/modules/unifi/files/libssl1.1.deb new file mode 100644 index 0000000000000000000000000000000000000000..9a05caa26420b9c77c40b0feacf69eaa72eddc43 GIT binary patch literal 1128092 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%0DqHeubbYzp~l^! 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 JZd#G@#k{_}LivF^Xqv}MqH^)m|3b8C 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