Compare commits

...

2 commits

Author SHA1 Message Date
033d3d6371 feat: add rbw plugin for secret management 2025-05-28 16:21:12 -04:00
205cf36feb chore: cleanup repo 2025-05-28 12:42:05 -04:00
20 changed files with 60 additions and 290 deletions

View file

@ -1,8 +0,0 @@
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"

View file

@ -1,5 +0,0 @@
#!/usr/bin/env bash
set -euxo pipefail
cog verify --file "$1"

View file

@ -1,16 +0,0 @@
#!/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

View file

@ -1,44 +0,0 @@
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

View file

@ -1,4 +0,0 @@
# aleidk
age1h0wfmxcrfjjcmv3ju7zcm6gc8j8pz35gs08kkqsjej20ndsxq54qv48hgn
# anavarro
age1gj7hj894l0a0lvu3fsndlkdkyc0da7963kcqhpfe43reflx3gafqnm058u

View file

@ -1,30 +0,0 @@
#!/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

View file

@ -1,16 +0,0 @@
#!/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"

View file

@ -1,42 +0,0 @@
#!/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"

Binary file not shown.

View file

@ -1,10 +1,6 @@
# Repo management tasks # Repo management tasks
mod repo '.devfiles/justfile'
set dotenv-load := true 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 # Debug output, disabled in CI
export ANSIBLE_DISPLAY_ARGS_TO_STDOUT := if env('CI', '') == 'true' { 'false' } else { 'true' } export ANSIBLE_DISPLAY_ARGS_TO_STDOUT := if env('CI', '') == 'true' { 'false' } else { 'true' }

View file

@ -170,7 +170,7 @@ inventory=/etc/ansible/hosts,./hosts/inventory.yaml
;log_path= ;log_path=
# (pathspec) Colon separated paths in which Ansible will search for Lookup Plugins. # (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=/home/aleidk/.ansible/plugins/lookup:/usr/share/ansible/plugins/lookup:./lookup_plugins/
# (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. # (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 ;ansible_managed=Ansible managed
@ -185,7 +185,7 @@ inventory=/etc/ansible/hosts,./hosts/inventory.yaml
;module_name=command ;module_name=command
# (pathspec) Colon separated paths in which Ansible will search for Modules. # (pathspec) Colon separated paths in which Ansible will search for Modules.
;library=/home/aleidk/.ansible/plugins/modules:/usr/share/ansible/plugins/modules # library=/home/aleidk/.ansible/plugins/modules:/usr/share/ansible/plugins/modules:./modules
# (pathspec) Colon separated paths in which Ansible will search for Module utils files, which are shared by 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 ;module_utils=/home/aleidk/.ansible/plugins/module_utils:/usr/share/ansible/plugins/module_utils

Binary file not shown.

50
lookup_plugins/rbw.py Normal file
View file

@ -0,0 +1,50 @@
# 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

View file

@ -1,24 +0,0 @@
# 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",
]
}

View file

@ -1,35 +0,0 @@
# 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"
}
}

View file

@ -1,56 +0,0 @@
# 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
}
}

View file

@ -1,4 +0,0 @@
variable "root_password" {
type = string
description = "Password used for the root user"
}

View file

@ -0,0 +1,8 @@
---
- hosts: localhost
vars:
secret: "{{ lookup('rbw', 'Work Laptop') }}"
tasks:
- debug:
msg: the value of the secret is {{ secret.data.public_key }}