diff --git a/homelab/applications/README.md b/homelab/applications/README.md index 4a248e5..ea4f243 100644 --- a/homelab/applications/README.md +++ b/homelab/applications/README.md @@ -1,9 +1,22 @@ # NAxS Homelab -Prerequisites: -- Create a default network called homelab +## Prerequisites +0. Make sure that your user is part of the docker group + - `cat /etc/group | grep docker` - if the entry looks like `docker:x::`, you're good to go + - Otherwise please run `sudo usermod -aG docker `, followed by logging out & in again for these changes to take into effect + +1. Create a default network called homelab ``` docker network create homelab ``` +2. Set up 1Password for access to secrets + - Install `pass` & `gpg` + - Generate key with `gpg --full-generate-key` + - stick to defaults + - as password, use `GPG cert password` stored inside the `NAxS Homelab` vault in 1Password + - Initialize password storage with `pass init "GPG key ID"` + - You can check out the ID by using `gpg --list-secret-keys --keyid-format LONG` - you should see a line with `sec`, containing the following information `/ID` + - Store the 1Password service account token in `pass` as `op-sa_token` by executing `pass insert op-sa_token` + - Make sure your .zshrc file loads the token into the `OP_SERVICE_ACCOUNT_TOKEN` (this is needed by the 1Password CLI for authentication purposes when loading the secrets) environment variable by executing `export OP_SERVICE_ACCOUNT_TOKEN="$(pass op-sa_token)"` // TODO: Create template script Template script which helps with setting up new applications (asks for potential secrets needs, adds default network to compose file, creates new users/groups to run containers rootless) \ No newline at end of file diff --git a/homelab/applications/app-template-generator/create-files+directories.sh b/homelab/applications/app-template-generator/create-files+directories.sh new file mode 100644 index 0000000..ebb02ed --- /dev/null +++ b/homelab/applications/app-template-generator/create-files+directories.sh @@ -0,0 +1,180 @@ +#!/bin/zsh +while [[ "$#" -gt 0 ]] +do + case $1 in + --app_name) app_name="$2" + shift;; + *) echo "Unknown parameter passed: $1" + exit 1;; + esac + shift +done + +# Make sure app_name exists and is not empty +if [[ -z "$app_name" ]]; then + echo "app_name is unset or empty." + exit 1; +fi + +# Define the base directory for the new application structure +# This will be one level up from where this script is executed. +app_base_dir="../${app_name}" +app_data_dir="${app_base_dir}/data" +compose_file="${app_base_dir}/compose.yaml" +readme_file="${app_base_dir}/README.md" +start_script="${app_base_dir}/start.sh" + +echo "--- Setting up files and directories for application: ${app_name} ---" +echo "Base directory: ${app_base_dir}" + +# 1. Create the application base directory and data directory +echo "Creating directory: ${app_data_dir}" +mkdir -p "${app_data_dir}" || { echo "Error: Failed to create directory ${app_data_dir}"; exit 1; } + +# 2. Create compose.yaml and README.md +echo "Creating file: ${compose_file}" +touch "${compose_file}" || { echo "Error: Failed to create file ${compose_file}"; exit 1; } + +echo "Creating file: ${readme_file}" +touch "${readme_file}" || { echo "Error: Failed to create file ${readme_file}"; exit 1; } + +# 3. Prepopulate README.md with title case app name +# Convert app_name to title case (first letter of each word capitalized) +# This is a simple conversion; for more robust title casing, a function would be better. +app_name_title_case=$(echo "$app_name" | awk '{for(i=1;i<=NF;i++){ $i=toupper(substr($i,1,1)) tolower(substr($i,2)) }}1') + +echo "Prepopulating ${readme_file}..." +cat > "${readme_file}" << EOF +# ${app_name_title_case} + +This is the README file for the **${app_name}** application. + +## Overview +Provide a brief description of your application here. + +## Setup +Instructions for setting up the application. + +EOF + +# 4. Ask the user if secrets will be required +read "requires_secrets?Will this application require secrets (yes/no)? " +requires_secrets=$(echo "$requires_secrets" | tr '[:upper:]' '[:lower:]') # Convert to lowercase + +# 5. Prepopulate compose.yaml based on user selection re. secrets +echo "Prepopulating ${compose_file} based on secrets requirement..." +if [[ "$requires_secrets" == "yes" || "$requires_secrets" == "y" ]]; then + cat > "${compose_file}" << EOF +version: '3.8' +services: + ${app_name}: + image: your-app-image:latest + container_name: ${app_name}-container + ports: + - "8080:8080" + volumes: + - ./data:/app/data + environment: + # Example of how to pass secrets as environment variables + # These would typically be loaded from a .env file or a secrets management system + - DATABASE_URL=\${DATABASE_URL} + - API_KEY=\${API_KEY} + # Example of secrets usage with Docker Compose secrets (requires Docker Swarm or specific setup) + # secrets: + # - my_database_password + # - my_api_key + # deploy: + # resources: + # limits: + # cpus: '0.5' + # memory: 512M +secrets: + my_database_password: + external: true # Assumes secret is created externally (e.g., docker secret create) + my_api_key: + external: true +EOF +else + cat > "${compose_file}" << EOF +services: + ${app_name}: + image: your-app-image:latest + container_name: ${app_name}-container + ports: + - "8080:8080" + volumes: + - ./data:/app/data + # No secrets configuration needed for this version + # deploy: + # resources: + # limits: + # cpus: '0.5' + # memory: 512M +EOF +fi + +# 6. If secrets will be used - touch ../"app_name"/start.sh and prepopulate it +if [[ "$requires_secrets" == "yes" || "$requires_secrets" == "y" ]]; then + echo "Creating and prepopulating ${start_script}..." + cat > "${start_script}" << EOF +#!/bin/zsh + +# Example start script for an application using secrets +# This script assumes you have a .env file or similar mechanism +# for loading secrets into the environment before starting Docker Compose. + +# --- IMPORTANT: Replace with your actual secret loading mechanism --- +# Example 1: Load from a .env file +# if [[ -f ".env" ]]; then +# echo "Loading environment variables from .env" +# source .env +# else +# echo "Warning: .env file not found. Secrets might be missing." +# fi + +# Example 2: Using a secrets management tool (e.g., HashiCorp Vault, AWS Secrets Manager) +# echo "Fetching secrets from Vault..." +# export DATABASE_URL=\$(vault read -field=value secret/myapp/database_url) +# export API_KEY=\$(vault read -field=value secret/myapp/api_key) +# ------------------------------------------------------------------- + +echo "Starting Docker Compose services for ${app_name}..." +docker compose -f "${compose_file}" up -d + +echo "Application ${app_name} started. Check logs with: docker compose logs -f ${app_name}" +EOF + chmod +x "${start_script}" # Make the start script executable +fi + +# 7. If secrets will be used, append another chapter at the end of the README.md file +if [[ "$requires_secrets" == "yes" || "$requires_secrets" == "y" ]]; then + echo "Appending 'Secrets Management' chapter to ${readme_file}..." + cat >> "${readme_file}" << EOF + +## Secrets Management + +This application utilizes secrets for sensitive configurations (e.g., database credentials, API keys). + +### Configuration +Secrets are expected to be provided via environment variables or Docker Compose secrets. +Refer to the \`start.sh\` script for an example of how to load these secrets before application startup. + +**Example Environment Variables (to be set in your environment or a \`.env\` file):** +\`\`\` +DATABASE_URL="postgres://user:password@host:port/database" +API_KEY="your_super_secret_api_key" +\`\`\` + +**For Docker Compose secrets:** +Ensure the necessary Docker secrets are created on your Docker host or Swarm cluster. +\`\`\`bash +docker secret create my_database_password <(echo "your_db_password") +docker secret create my_api_key <(echo "your_api_key") +\`\`\` +Then, update the \`compose.yaml\` to reference these secrets. + +EOF +fi + +echo "--- Setup complete for ${app_name} ---" +echo "Check the '${app_base_dir}' directory for your new files." diff --git a/homelab/applications/app-template-generator/create-user.sh b/homelab/applications/app-template-generator/create-user.sh new file mode 100644 index 0000000..f599556 --- /dev/null +++ b/homelab/applications/app-template-generator/create-user.sh @@ -0,0 +1,80 @@ +#!/bin/zsh +while [[ "$#" -gt 0 ]] +do + case $1 in + --app_name) app_name="$2" + shift;; + --id) desired_id="$2" + shift;; + *) echo "Unknown parameter passed: $1" + exit 1;; + esac + shift +done + +# Validate desired_id is a number +if ! [[ "$desired_id" =~ ^[0-9]+$ ]]; then + echo "Error: Invalid UID/GID. Please enter a numeric value." + exit 1 +fi + +user_name="${app_name}-user" +group_name="${app_name}-group" + +echo "--- Checking/Creating User and Group for ${app_name} ---" + +# --- Handle Group --- +echo "Checking group: ${group_name}" +existing_gid=$(getent group "${group_name}" | cut -d: -f3) + +if [[ -n "$existing_gid" ]]; then + if [[ "$existing_gid" -eq "$desired_id" ]]; then + echo "Group '${group_name}' already exists with the correct GID (${desired_id})." + else + echo "Group '${group_name}' exists with GID ${existing_gid}, but desired GID is ${desired_id}." + echo "Attempting to modify group GID..." + if sudo groupmod -g "$desired_id" "${group_name}"; then + echo "Successfully adjusted group '${group_name}' to GID ${desired_id}." + else + echo "Failed to adjust group '${group_name}' GID. Please check permissions or try manually." + exit 1 + fi + fi +else + echo "Group '${group_name}' does not exist. Creating..." + if sudo groupadd -g "$desired_id" "${group_name}"; then + echo "Successfully created group '${group_name}' with GID ${desired_id}." + else + echo "Failed to create group '${group_name}'. Please check permissions or try manually." + exit 1 + fi +fi + +# --- Handle User --- +echo "Checking user: ${user_name}" +existing_uid=$(getent passwd "${user_name}" | cut -d: -f3) + +if [[ -n "$existing_uid" ]]; then + if [[ "$existing_uid" -eq "$desired_id" ]]; then + echo "User '${user_name}' already exists with the correct UID (${desired_id})." + else + echo "User '${user_name}' exists with UID ${existing_uid}, but desired UID is ${desired_id}." + echo "Attempting to modify user UID..." + if sudo usermod -u "$desired_id" -g "$desired_id" "${user_name}"; then + echo "Successfully adjusted user '${user_name}' to UID ${desired_id} and primary GID ${desired_id}." + else + echo "Failed to adjust user '${user_name}' UID/GID. Please check permissions or try manually." + exit 1 + fi + fi +else + echo "User '${user_name}' does not exist. Creating..." + if sudo useradd -u "$desired_id" -g "$desired_id" -s /sbin/nologin -c "Application User for ${app_name}" "${user_name}"; then + echo "Successfully created user '${user_name}' with UID ${desired_id} and primary GID ${desired_id}." + else + echo "Failed to create user '${user_name}'. Please check permissions or try manually." + exit 1 + fi +fi + +echo "--- Operation complete for ${app_name} ---" diff --git a/homelab/applications/app-template-generator/main.sh b/homelab/applications/app-template-generator/main.sh new file mode 100644 index 0000000..265d2f5 --- /dev/null +++ b/homelab/applications/app-template-generator/main.sh @@ -0,0 +1,8 @@ +#!/bin/zsh +# Ask for the application name +read "app_name?Enter the name of the application: " +# Ask for the desired UID/GID +read "desired_id?Enter the desired UID/GID for the application (e.g., 1001): " + +./create-user.sh --app_name ${app_name} --id ${desired_id} +./create-files+directories.sh --app_name ${app_name} \ No newline at end of file diff --git a/homelab/applications/gitea/README.md b/homelab/applications/gitea/README.md index 7c7c9b7..28a125e 100644 --- a/homelab/applications/gitea/README.md +++ b/homelab/applications/gitea/README.md @@ -25,13 +25,4 @@ In case user/group doesn't exist at all, please create the user & group incl. th ``` sudo groupadd -g 1003 gitea-group sudo useradd -g gitea-group -u 1003 gitea-user -``` - -## About secrets -In order to manage secrets centrally in 1Password and due to the need for secrets in Gitea, using `docker compose` directly in the terminal does not work. - -## Bring up/tear down container -Please use the `start.sh` to spin up the container -### Prerequisites start.sh -- User executing the script is part of the `docker` group -- Env variable `OP_SERVICE_ACCOUNT_TOKEN` is set up \[check out top-level README.md for more information on how to set this up\] \ No newline at end of file +``` \ No newline at end of file diff --git a/homelab/applications/gitea/compose.yml b/homelab/applications/gitea/compose.yml index 6855008..576c4ce 100644 --- a/homelab/applications/gitea/compose.yml +++ b/homelab/applications/gitea/compose.yml @@ -1,6 +1,3 @@ -secrets: - gitea_postgres_password: - environment: GITEA_POSTGRES_PASSWORD services: gitea: image: docker.gitea.com/gitea:1-rootless @@ -14,11 +11,9 @@ services: GITEA__database__HOST: postgres:5432 GITEA__database__NAME: gitea GITEA__database__USER: gitea - GITEA__database__PASSWD_FILE: /run/secrets/gitea_postgres_password restart: always volumes: ['./data:/var/lib/gitea', './config:/etc/gitea'] ports: ['8030:3000', '2222:2222'] - secrets: ['gitea_postgres_password'] networks: ['homelab'] networks: diff --git a/homelab/applications/gitea/start.sh b/homelab/applications/gitea/start.sh deleted file mode 100644 index 177f56c..0000000 --- a/homelab/applications/gitea/start.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/zsh -# Exit immediately if a command exits with a non-zero status. -set -e - -echo "--- Starting Docker Secret Management ---" -# Mount secrets -export GITEA_POSTGRES_PASSWORD="$(op read 'op://NAxS Homelab/Gitea Postgres credentials/password')" - -# Bring up container -docker compose up -d - -echo "--- Docker Secret Management Complete ---" \ No newline at end of file diff --git a/homelab/applications/postgres/README.md b/homelab/applications/postgres/README.md index 980a0d0..a4ccb77 100644 --- a/homelab/applications/postgres/README.md +++ b/homelab/applications/postgres/README.md @@ -2,20 +2,26 @@ ## Set up non-root user for container We are providing a non-root user to the container to limit the attack surface for privilege escalations. In order for this to work in our setup, please make sure to check if you have a user called `postgres` set up. -1. Check if user `postgres` exists and if the UID is 1002 +1. Check if user `postgres` exists ``` cat /etc/passwd | grep postgres ``` - -In case the `postgres` user exists but the UID is not 1002, please adjust it via +In case the `postgres` user doesn't exist, please create the user by running ``` -sudo usermod -u 1002 postgres +sudo useradd postgres +``` +2. `data` folder ownership +Also you need to make sure that the `postgres` owner owns the volumes mounted for docker +``` +sudo chown -R postgres:postgres data +sudo chmod 770 data ``` -In case the `postgres` user doesn't exist at all, please create the user incl. the right UID by running +3. Adjust compose.yml +Within `services > postgres > user`, make sure to replare `postgres` with the UID of the user on your machine ``` -sudo useradd -u 1002 postgres +cat /etc/passwd | grep postgres ``` ## About secrets @@ -25,4 +31,4 @@ In order to manage secrets centrally in 1Password and due to the need for secret Please use the `start.sh` to spin up the container ### Prerequisites start.sh - User executing the script is part of the `docker` group -- Env variable `OP_SERVICE_ACCOUNT_TOKEN` is set up \[check out top-level README.md for more information on how to set this up\] \ No newline at end of file +- Environment variable `OP_SERVICE_ACCOUNT_TOKEN` is set up \[check out top-level README.md for more information on how to set this up\] \ No newline at end of file diff --git a/homelab/ubuntu-server-setup.sh b/homelab/ubuntu-server-setup.sh index 918715b..d730712 100644 --- a/homelab/ubuntu-server-setup.sh +++ b/homelab/ubuntu-server-setup.sh @@ -101,6 +101,4 @@ op --version apt install pass gnupg2 - - echo "Done. Recommended: log out and back in (or reboot) to start using zsh and ensure all services are active." \ No newline at end of file diff --git a/working_machine/alfred/addToOmnifocus.js b/working_machine/alfred/addToOmnifocus.js new file mode 100644 index 0000000..18f3327 --- /dev/null +++ b/working_machine/alfred/addToOmnifocus.js @@ -0,0 +1,29 @@ +function run(argv) { + const title = $.NSProcessInfo.processInfo.environment.objectForKey("title").js; + const notes = $.NSProcessInfo.processInfo.environment.objectForKey("notes").js + + function addToOmnifocus(transportText) { + newTasks = Task.byParsingTransportText(transportText, true); + taskID = newTasks[0].id.primaryKey; + URL.fromString("omnifocus:///task/" + taskID).open(); + } + + function generateTransportText(title, notes) { + const tag = 'work'; + let transportText = `${title} @${tag}`; + if (notes) { + transportText = `${transportText} // ${notes}` + } + return transportText; + } + + const transportText = generateTransportText(title, notes); + const encodedFunctionAndInput = `%28${encodeURIComponent(addToOmnifocus.toString())}%29%28argument%29&arg=%22${encodeURIComponent(transportText)}%22`; + const omnifocusUrl = `omnifocus://localhost/omnijs-run?script=${encodedFunctionAndInput}`; + + console.log(omnifocusUrl); + + let app = Application.currentApplication(); + app.includeStandardAdditions = true; + app.openLocation(omnifocusUrl); +} \ No newline at end of file diff --git a/working_machine/alfred/omnifocus-alfred.alfredworkflow b/working_machine/alfred/omnifocus-alfred.alfredworkflow new file mode 100644 index 0000000..7371eed Binary files /dev/null and b/working_machine/alfred/omnifocus-alfred.alfredworkflow differ diff --git a/working_machine/zshrc/README.md b/working_machine/zshrc/README.md new file mode 100644 index 0000000..aa4417f --- /dev/null +++ b/working_machine/zshrc/README.md @@ -0,0 +1,5 @@ +# ZSH setup +1. Place .zshrc file in home directory +2. Create folder called zshrc +3. Include all needed .sh files inside the zshcrc folder +4. To activate the changes right away, make sure to execute `source .zshrc` from within the home directory in your terminal \ No newline at end of file diff --git a/working_machine/zshrc/env.sh b/working_machine/zshrc/env.sh new file mode 100644 index 0000000..5de0bda --- /dev/null +++ b/working_machine/zshrc/env.sh @@ -0,0 +1 @@ +export OP_SERVICE_ACCOUNT_TOKEN="$(pass op-sa_token)" \ No newline at end of file diff --git a/working_machine/zshrc/general.sh b/working_machine/zshrc/general.sh new file mode 100644 index 0000000..147876d --- /dev/null +++ b/working_machine/zshrc/general.sh @@ -0,0 +1,2 @@ +bindkey -v +PS1='%n@%m %~ $ ' \ No newline at end of file diff --git a/working_machine/zshrc b/working_machine/zshrc/macbook.sh similarity index 94% rename from working_machine/zshrc rename to working_machine/zshrc/macbook.sh index 504b610..ab611a8 100644 --- a/working_machine/zshrc +++ b/working_machine/zshrc/macbook.sh @@ -9,4 +9,4 @@ export PATH="/Users/mucas/.local/share/gem/ruby/3.2.0/bin:$PATH" export PYENV_ROOT="$HOME/.pyenv" [[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH" -eval "$(pyenv init - zsh)" +eval "$(pyenv init - zsh)" \ No newline at end of file diff --git a/working_machine/zshrc/zshrc b/working_machine/zshrc/zshrc new file mode 100644 index 0000000..b899589 --- /dev/null +++ b/working_machine/zshrc/zshrc @@ -0,0 +1,3 @@ +for FILE in ~/zshrc/*; do + source $FILE +done \ No newline at end of file