diff --git a/.ageboxreg.yml b/.ageboxreg.yml new file mode 100644 index 0000000..37d7cdd --- /dev/null +++ b/.ageboxreg.yml @@ -0,0 +1,8 @@ +file_ids: +- .env +- files/docker/fedi/.env +- files/docker/hoarder/.env +- files/docker/rss/.env +- roles/common/files/robo_key +- roles/docker/files/rclone.conf +version: "1" diff --git a/.devfiles/hooks/.gitkeep b/.devfiles/hooks/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.devfiles/hooks/commit-msg.sh b/.devfiles/hooks/commit-msg.sh new file mode 100644 index 0000000..1c54b90 --- /dev/null +++ b/.devfiles/hooks/commit-msg.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +cog verify --file "$1" diff --git a/.devfiles/hooks/pre-commit.sh b/.devfiles/hooks/pre-commit.sh new file mode 100644 index 0000000..c8d84f5 --- /dev/null +++ b/.devfiles/hooks/pre-commit.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +root="$(git rev-parse --show-toplevel)" + +cd "$root" + +export PATH=$PATH:.devfiles/bin + +gitleaks git + +# Only validate encrypted files if we are tracking any +if [[ -e .ageboxreg.yml ]]; then + agebox validate --no-decrypt +fi diff --git a/.devfiles/justfile b/.devfiles/justfile new file mode 100644 index 0000000..2d9a105 --- /dev/null +++ b/.devfiles/justfile @@ -0,0 +1,44 @@ +set dotenv-load := true + +export PATH := source_dir() + "/bin:" + source_dir() + "/scripts:" + env("PATH") +export AGEBOX_DEBUG := "0" +export AGEBOX_PUBLIC_KEYS := source_dir() + "/public_keys.txt" + +# Install agebox from the latest github realse +install-agebox: + curl -sSL "https://github.com/slok/agebox/releases/latest/download/agebox-linux-amd64" -o .devfiles/bin/agebox + chmod + x .devfiles/bin/agebox + +[no-cd] +install-hooks: + cog install-hook --all + +# Easy and simple file repository encryption tool based on Age. +[working-directory('..')] +agebox +ARGS="--help": + @agebox {{ ARGS }} + +# Encrypt the provided files, relative to project root. +encrypt +FILES: (agebox "encrypt " + FILES) + +# Encrypt all the tracked files. +encrypt-all: (agebox "encrypt --all") + +# Decrypt the provided files, relative to project root. +decrypt +FILES: (agebox "decrypt " + FILES) + +# Decrypt all the tracked files. +decrypt-all: (agebox "decrypt --all --force") + +# Reencrypt all the tracked files with the new public keys. +reencrypt: (agebox "reencrypt") + +# Show the content of an encrypted file to stdout. +crypt-peek +FILES: (agebox "cat " + FILES) + +# Validate that all tracked files are encrypted. +crypt-check:(agebox "validate --no-decrypt ") + +# Validate no credentials are pushed to git +leaks: + @gitleaks git --verbose --redact diff --git a/.devfiles/public_keys.txt b/.devfiles/public_keys.txt new file mode 100644 index 0000000..41951ff --- /dev/null +++ b/.devfiles/public_keys.txt @@ -0,0 +1,4 @@ +# aleidk +age1h0wfmxcrfjjcmv3ju7zcm6gc8j8pz35gs08kkqsjej20ndsxq54qv48hgn +# anavarro +age1gj7hj894l0a0lvu3fsndlkdkyc0da7963kcqhpfe43reflx3gafqnm058u diff --git a/.devfiles/scripts/.gitkeep b/.devfiles/scripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.devfiles/scripts/dependecy-check.sh b/.devfiles/scripts/dependecy-check.sh new file mode 100755 index 0000000..684a14b --- /dev/null +++ b/.devfiles/scripts/dependecy-check.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +set -euo pipefail + +root="$(git rev-parse --show-toplevel)" + +export PATH=$root/.devfiles/bin:$root/.devfiles/scripts:$PATH + +devtools=( + age + agebox + cog + gitleaks +) + +missing_tools=() + +for cmd in "${devtools[@]}"; do + if ! command -v "$cmd" &>/dev/null; then + missing_tools+=("$cmd") + fi +done + +if [[ ${#missing_tools[@]} != 0 ]]; then + echo "The following tools where not found:" + printf "%s\n" "${missing_tools[@]}" + exit 1 +else + echo -e "All tools are installed!" +fi diff --git a/.devfiles/scripts/fetch_gh_release.sh b/.devfiles/scripts/fetch_gh_release.sh new file mode 100755 index 0000000..5e80632 --- /dev/null +++ b/.devfiles/scripts/fetch_gh_release.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +basedir=".devfiles/bin" + +repo="$1" +shift +release_filename="$1" +shift +out_filename="$basedir/$1" +shift + +curl -sSL "https://github.com/$repo/releases/latest/download/$release_filename" -o "$out_filename" + +chmod +x "$out_filename" diff --git a/.devfiles/scripts/gitignore.sh b/.devfiles/scripts/gitignore.sh new file mode 100755 index 0000000..0b5100d --- /dev/null +++ b/.devfiles/scripts/gitignore.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +set -euo pipefail + +root="$(git rev-parse --show-toplevel)" + +base_url="https://git.alecodes.page/api/v1/gitignore/templates" + +query="$*" + +list_available() { + curl -Ssl $base_url | jq -r '.[]' +} + +if [[ -z $query ]]; then + list_available + exit 0 +fi + +tmp_file="$(mktemp)" + +for template in $query; do + # Capitalize the string + template=${template,,} + template=${template^} + + response="$(curl -Ssl "$base_url/$template")" + name="$(echo "$response" | jq -r '.name')" + content="$(echo "$response" | jq -r '.source')" + + if [[ "$content" == "null" ]]; then + echo "Template not found, available options:" + list_available + exit 1 + fi + + printf "\n### %s\n\n%s\n\n" "$name" "$content" >>"$tmp_file" +done + +sed -i -ne "/#### -- TEMPLATES BEGIN -- ####/ {p; r $tmp_file" -e ':a; n; /#### -- TEMPLATES END -- ####/ {p; b}; ba}; p' "$root/.gitignore" + +rm "$tmp_file" diff --git a/.env.agebox b/.env.agebox new file mode 100644 index 0000000..fc8549e Binary files /dev/null and b/.env.agebox differ diff --git a/.justfile b/.justfile index 9a9a9d2..62409ff 100644 --- a/.justfile +++ b/.justfile @@ -1,6 +1,10 @@ # Repo management tasks +mod repo '.devfiles/justfile' set dotenv-load := true +export ANSIBLE_VAULT_PASSWORD_FILE := justfile_directory() + "/.decrypt-pass.txt" +export ANSIBLE_BECOME_PASSWORD_FILE := justfile_directory() + "/.become-pass.txt" + # Debug output, disabled in CI export ANSIBLE_DISPLAY_ARGS_TO_STDOUT := if env('CI', '') == 'true' { 'false' } else { 'true' } diff --git a/ansible.cfg b/ansible.cfg index 6f1c6a8..c45dec5 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -170,7 +170,7 @@ inventory=/etc/ansible/hosts,./hosts/inventory.yaml ;log_path= # (pathspec) Colon separated paths in which Ansible will search for Lookup Plugins. -lookup_plugins=/home/aleidk/.ansible/plugins/lookup:/usr/share/ansible/plugins/lookup:./lookup_plugins/ +;lookup_plugins=/home/aleidk/.ansible/plugins/lookup:/usr/share/ansible/plugins/lookup # (string) Sets the macro for the 'ansible_managed' variable available for :ref:`ansible_collections.ansible.builtin.template_module` and :ref:`ansible_collections.ansible.windows.win_template_module`. This is only relevant for those two modules. ;ansible_managed=Ansible managed @@ -185,7 +185,7 @@ lookup_plugins=/home/aleidk/.ansible/plugins/lookup:/usr/share/ansible/plugins/l ;module_name=command # (pathspec) Colon separated paths in which Ansible will search for Modules. -# library=/home/aleidk/.ansible/plugins/modules:/usr/share/ansible/plugins/modules:./modules +;library=/home/aleidk/.ansible/plugins/modules:/usr/share/ansible/plugins/modules # (pathspec) Colon separated paths in which Ansible will search for Module utils files, which are shared by modules. ;module_utils=/home/aleidk/.ansible/plugins/module_utils:/usr/share/ansible/plugins/module_utils diff --git a/files/docker/rss/.env.agebox b/files/docker/rss/.env.agebox index a5b757d..59168e2 100644 Binary files a/files/docker/rss/.env.agebox and b/files/docker/rss/.env.agebox differ diff --git a/lookup_plugins/rbw.py b/lookup_plugins/rbw.py deleted file mode 100644 index 55c59d4..0000000 --- a/lookup_plugins/rbw.py +++ /dev/null @@ -1,50 +0,0 @@ -# python 3 headers, required if submitting to Ansible -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -import json -import subprocess - -from ansible.errors import AnsibleError, AnsibleParserError -from ansible.plugins.lookup import LookupBase -from ansible.utils.display import Display -from jinja2 import Environment - -DOCUMENTATION = r""" - name: rbw - short_description: get secrets using rbw - options: - _terms: - description: Name of the secret to get - required: True -""" - -display = Display() - - -def rbw(name: str): - sub = subprocess.run(["rbw", "get", name, "--raw"], capture_output=True) - - secret = json.loads(sub.stdout) - - display.debug(f'Obtaining data for "{secret["name"]}"') - - return secret - - -class LookupModule(LookupBase): - def run(self, terms, variables=None, **kwargs): - # First of all populate options, - # this will already take into account env vars and ini config - self.set_options(var_options=variables, direct=kwargs) - - # lookups in general are expected to both take a list as input and output a list - # this is done so they work with the looping construct 'with_'. - ret = [] - for term in terms: - secret = rbw(term) - - ret.append(secret) - - return ret diff --git a/opentofu/vms/.terraform.lock.hcl b/opentofu/vms/.terraform.lock.hcl new file mode 100644 index 0000000..690a74a --- /dev/null +++ b/opentofu/vms/.terraform.lock.hcl @@ -0,0 +1,24 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/bpg/proxmox" { + version = "0.43.2" + constraints = "0.43.2" + hashes = [ + "h1:5+YNvUbtMlus6GJJktc9/7o68tYgQIQxhjTqqt2WCpk=", + "zh:07c9357e80cc52c020bd3728e5a00e21b9c06b20ee91d13d0c8ea034c1de4b6f", + "zh:41208bfd4d69f04142a69e9eabd79d4cba99f4fcacd59318aad0265c7b4bfe9e", + "zh:420623a0ae35bee21c00da444c0fbc63d3d6008d71516d90e11512651f25210f", + "zh:4cf21c0245a4fcbfec9edc1c65a5a0f0d83180607d870229ce3761fa25652ac7", + "zh:6f07cab62a60d7adc7a2c3f6fb27057dd70883c02c8ee762aec683743aee16c0", + "zh:75c4c97b110373ee48ad87774d9becbb1e21d55e0a4324f594a3b3cc8d25d73e", + "zh:79b3ab36e5276a1172c661eb60574a330cb502f2de40410f2540a50061a777f7", + "zh:96a8cda572ac540aa6c616eabd2e8dc9399809e8558f6d53a883da2a9fbdede8", + "zh:99a78347944868062bac87e93372672aa0f12422cf82d5a7f13a00805f18d5bd", + "zh:a6d2ff27558114277a9e2db874f5c9c9ee65d0dc5e918f2d9994e3ec9ef0e2b5", + "zh:c220049b7b3890e8b882873f0a4320d5b6ca28cf4b3ff9128a130e86ffbc3209", + "zh:da586199b595f278d4ecfc64e60afa52b15b9183323edde00d74a7ede5abad27", + "zh:f2caa3eefc03dd03f05ce466e98ba6fb9f0b87ece3a7fc35eb73d63f816c13d4", + "zh:f99012369fff51af76557d5616a24ae48d12ef662c6d132aa74db7f6b9d4144b", + ] +} diff --git a/opentofu/vms/providers.tf b/opentofu/vms/providers.tf new file mode 100644 index 0000000..bb0c737 --- /dev/null +++ b/opentofu/vms/providers.tf @@ -0,0 +1,35 @@ +# docs: https://registry.terraform.io/providers/bpg/proxmox/latest/docs + +terraform { + required_providers { + proxmox = { + source = "bpg/proxmox" + version = "0.43.2" + } + } + + backend "s3" { + bucket = "opentofu-state" + region = "us-east-1" + key = "lxc/terraform.tfstate" + encrypt = false + + skip_credentials_validation = true + skip_region_validation = true + skip_requesting_account_id = true + skip_s3_checksum = true + + endpoints = { + s3 = "https://a7638f5d66d44acc48d4b80b7c3c8a0c.r2.cloudflarestorage.com" + } + } +} + +provider "proxmox" { + insecure = true + tmp_dir = "/var/tmp" + ssh { + agent = true + username = "robo" + } +} diff --git a/opentofu/vms/s3.tf b/opentofu/vms/s3.tf new file mode 100644 index 0000000..bd21365 --- /dev/null +++ b/opentofu/vms/s3.tf @@ -0,0 +1,56 @@ +# docs: https://registry.terraform.io/providers/bpg/proxmox/latest/docs/resources/virtual_environment_container + +variable "vm_names" { + type = list(string) + default = ["donkey-kong"] +} + +resource "proxmox_virtual_environment_container" "vm" { + for_each = toset(var.vm_names) + vm_id = 160 + index(var.vm_names, each.key) + node_name = "pve" + description = "S3 data storage" + unprivileged = true + + start_on_boot = "true" + + disk { + datastore_id = "local-lvm" + size = 8 + } + + initialization { + hostname = each.key + + ip_config { + ipv4 { + address = "10.0.10.${160 + index(var.vm_names, each.key)}/24" + gateway = "10.0.0.10" + } + } + + user_account { + password = var.root_password + } + } + + network_interface { + name = "eth0" + firewall = true + bridge = "vnet10" + } + + operating_system { + template_file_id = "local:vztmpl/alpine-latest-base-2024-12-30.tar.gz" + type = "alpine" + } + + tags = [ + "storage", + "s3", + ] + + features { + nesting = true + } +} diff --git a/opentofu/vms/variables.tf b/opentofu/vms/variables.tf new file mode 100644 index 0000000..35c2ef3 --- /dev/null +++ b/opentofu/vms/variables.tf @@ -0,0 +1,4 @@ +variable "root_password" { + type = string + description = "Password used for the root user" +} diff --git a/playbooks/initial-setup.yaml b/playbooks/initial-setup.yaml deleted file mode 100644 index a5d9bb6..0000000 --- a/playbooks/initial-setup.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -- hosts: localhost - vars: - secret: "{{ lookup('rbw', 'Work Laptop') }}" - tasks: - - - debug: - msg: the value of the secret is {{ secret.data.public_key }}