diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index b85f77f5..3b33de8a 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -47,6 +47,6 @@ USER ${ADMIN_USER} RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ - ./apply-adhoc.sh local-debian markosamuli.linuxbrew,debian_tools + ./apply-adhoc.sh local-debian debian_homebrew,debian_tools WORKDIR /home/${ADMIN_USER} diff --git a/Taskfile.yaml b/Taskfile.yaml index 58687d99..9d6d06ab 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -127,9 +127,9 @@ tasks: cmds: - lsb_release -a - uname -a - - ansible --version - - terraform --version - - docker --version || true + - 'ansible --version || echo "ansible: not installed"' + - 'terraform --version || echo "terraform: not installed"' + - 'docker --version || echo "docker: not installed"' backup-config: desc: Create a compressed backup of the configuration directory diff --git a/ansible/README.md b/ansible/README.md index 022c757f..7041df7b 100644 --- a/ansible/README.md +++ b/ansible/README.md @@ -22,7 +22,7 @@ https://www.ansible.com/ ## Setup steps -1. Install Ansible on the admin workstation with `bootstrap-ansible.sh`. (See: [Ansible control node](https://docs.ansible.com/ansible/latest/network/getting_started/basic_concepts.html#control-node)) +1. Install Ansible on the admin workstation with `sudo bootstrap-ansible.sh`. (See: [Ansible control node](https://docs.ansible.com/ansible/latest/network/getting_started/basic_concepts.html#control-node)) 2. Configure variables in `inventory/group_vars/` 3. Add hosts to `inventory/inventory.yaml` 4. Assign roles to hosts in `playbooks/` @@ -31,6 +31,8 @@ https://www.ansible.com/ - The playbook will set up passwordless `sudo`, so next time the `--ask-become-pass` parameter will not be required 6. When the administrative user is already created, use that user in the inventory instead of `root` (`ansible_user: `). This is more secure and also required by Homebrew. +For the complete infrastructure setup walkthrough using these playbooks, see [Getting Started](../docs/setup.md). + ## Bootstrapping hosts with authentication 1. Copy public SSH key, e.g.: diff --git a/ansible/Taskfile.ansible.yaml b/ansible/Taskfile.ansible.yaml index 8642cc29..de48b072 100644 --- a/ansible/Taskfile.ansible.yaml +++ b/ansible/Taskfile.ansible.yaml @@ -1,6 +1,11 @@ version: '3' tasks: + apply-localhost: + desc: Run 'homelab' Ansible playbook for the local host + cmds: + - ansible/apply-localhost.sh + apply-homelab: desc: Run 'homelab' Ansible playbook (apply configuration to local servers) cmds: diff --git a/ansible/apply-localhost.sh b/ansible/apply-localhost.sh new file mode 100755 index 00000000..0b56f33c --- /dev/null +++ b/ansible/apply-localhost.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +cd "$(dirname "$0")" || exit +ansible-playbook "playbooks/homelab.yaml" --limit "$(hostname)" \ + -e ansible_connection=local \ + -e ansible_pipelining=false \ + "$@" diff --git a/ansible/inventory/group_vars/debian/vars.yaml b/ansible/inventory/group_vars/debian/vars.yaml index d0087522..dc55085a 100644 --- a/ansible/inventory/group_vars/debian/vars.yaml +++ b/ansible/inventory/group_vars/debian/vars.yaml @@ -1,5 +1,7 @@ --- +ansible_python_interpreter: /usr/bin/python3 + admin_user: "buba" admin_name: "Buba" admin_email: "bubacoder@gmail.com" @@ -13,10 +15,7 @@ debian_base_install_crowdsec_bouncer: false # https://github.com/go-task/task/releases # renovate: datasource=github-releases depName=go-task/task -debian_base_go_task_version: "v3.50.0" - -linuxbrew_use_installer: true -linuxbrew_init_shell: true +debian_base_go_task_version: "v3.51.1" debian_base_apt_packages: # Common @@ -30,6 +29,7 @@ debian_base_apt_packages: - htop # https://htop.dev/ - tree # http://mama.indstate.edu/users/ice/tree/ # Network + - openssh-server # https://www.openssh.org/ - curl # https://curl.se/ - net-tools # https://sourceforge.net/projects/net-tools/ @@ -76,6 +76,7 @@ debian_tools_brew_packages_common: ## Dev Tools debian_tools_brew_packages_dev: - act # https://nektosact.com/ + - gh # https://cli.github.com/ ## AWS Cloud Tools debian_tools_brew_packages_aws: diff --git a/ansible/inventory/inventory.yaml b/ansible/inventory/inventory.yaml index 2dd2d005..6210825d 100644 --- a/ansible/inventory/inventory.yaml +++ b/ansible/inventory/inventory.yaml @@ -31,6 +31,25 @@ debian: # set 'debian_base_crowdsec_local_api_key' in group_vars/debian/secret.yaml debian_base_install_crowdsec_bouncer: true debian_base_crowdsec_local_api_url: http://127.0.0.1:7080/ + # packagecloud.io does not yet have CrowdSec packages for Ubuntu 25.10 "resolute" + debian_base_crowdsec_suite: noble + + # Enable all brew package groups + debian_tools_brew_install_groups: + common: true + dev: true + aws: true + azure: true + terraform: true + kubernetes: true + + colony: + debian_base_install_storage_packages: true + + # Crowdsec - configure docker/security/crowdsec/crowdsec.yaml and + # set 'debian_base_crowdsec_local_api_key' in group_vars/debian/secret.yaml + # debian_base_install_crowdsec_bouncer: true + # debian_base_crowdsec_local_api_url: http://127.0.0.1:7080/ # Enable all brew package groups debian_tools_brew_install_groups: diff --git a/ansible/playbooks/cloud.yaml b/ansible/playbooks/cloud.yaml index df78eed2..adad0a53 100755 --- a/ansible/playbooks/cloud.yaml +++ b/ansible/playbooks/cloud.yaml @@ -6,5 +6,5 @@ roles: - role: debian_base - role: debian_docker_host - - role: markosamuli.linuxbrew + - role: debian_homebrew - role: debian_tools diff --git a/ansible/playbooks/homelab.yaml b/ansible/playbooks/homelab.yaml index e9dd6a56..60b9e69f 100755 --- a/ansible/playbooks/homelab.yaml +++ b/ansible/playbooks/homelab.yaml @@ -11,19 +11,22 @@ - nas - nest - hive + - colony roles: - role: debian_docker_host -- name: Setup developer tools +- name: Setup Debian tools hosts: - nest - hive + - colony roles: - - role: markosamuli.linuxbrew + - role: debian_homebrew - role: debian_tools - name: Setup Samba client hosts: - nest + - colony roles: - role: debian_samba_client diff --git a/ansible/requirements.yml b/ansible/requirements.yml index 03ad1d29..835200f2 100644 --- a/ansible/requirements.yml +++ b/ansible/requirements.yml @@ -1,13 +1,6 @@ # ansible-galaxy install -r requirements.yml --- -# Install roles from Ansible Galaxy -roles: - # Source: https://github.com/markosamuli/ansible-linuxbrew - # Role: https://galaxy.ansible.com/ui/standalone/roles/markosamuli/linuxbrew/ - - name: markosamuli.linuxbrew - version: v2.0.2 - # Install collections from Ansible Galaxy collections: # Source: https://github.com/ansible-collections/community.general diff --git a/ansible/roles/debian_base/handlers/main.yaml b/ansible/roles/debian_base/handlers/main.yaml index 3163e4ed..cb836cbd 100644 --- a/ansible/roles/debian_base/handlers/main.yaml +++ b/ansible/roles/debian_base/handlers/main.yaml @@ -1,4 +1,9 @@ --- +- name: Update apt cache + ansible.builtin.apt: + update_cache: true + become: true + - name: Restart service systemd-resolved ansible.builtin.service: name: systemd-resolved diff --git a/ansible/roles/debian_base/tasks/50-crowdsec.yaml b/ansible/roles/debian_base/tasks/50-crowdsec.yaml index a3f29e40..435064d0 100644 --- a/ansible/roles/debian_base/tasks/50-crowdsec.yaml +++ b/ansible/roles/debian_base/tasks/50-crowdsec.yaml @@ -6,17 +6,16 @@ # Configuration file: /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml # Logs: /var/log/crowdsec-firewall-bouncer.log --- -- name: Add crowdsec apt-key - ansible.builtin.apt_key: - url: https://packagecloud.io/crowdsec/crowdsec/gpgkey - state: present - - name: Add crowdsec apt repository - ansible.builtin.apt_repository: - repo: deb https://packagecloud.io/crowdsec/crowdsec/{{ ansible_facts["distribution"] | lower }}/ {{ ansible_facts["distribution_release"] }} main + ansible.builtin.deb822_repository: + name: crowdsec + types: deb + uris: https://packagecloud.io/crowdsec/crowdsec/{{ ansible_facts["distribution"] | lower }}/ + suites: "{{ debian_base_crowdsec_suite | default(ansible_facts['distribution_release']) }}" + components: main + signed_by: https://packagecloud.io/crowdsec/crowdsec/gpgkey state: present - filename: crowdsec - update_cache: true + notify: Update apt cache - name: Install crowdsec iptables bouncer ansible.builtin.apt: diff --git a/ansible/roles/debian_base/tasks/70-user.yaml b/ansible/roles/debian_base/tasks/70-user.yaml index 03974ef8..e61ee8f5 100644 --- a/ansible/roles/debian_base/tasks/70-user.yaml +++ b/ansible/roles/debian_base/tasks/70-user.yaml @@ -24,7 +24,18 @@ group: "{{ admin_user }}" state: directory mode: '0700' + - name: Check if SSH key file exists + ansible.builtin.stat: + path: "{{ debian_base_ssh_key_file }}" + register: debian_base_ssh_key_stat + delegate_to: localhost + become: false + - name: Fail if SSH key file is missing and no admin password is set + when: not debian_base_ssh_key_stat.stat.exists and (admin_password | default('') == '') + ansible.builtin.fail: + msg: "SSH key file '{{ debian_base_ssh_key_file }}' not found and no admin_password set for user '{{ admin_user }}' — cannot configure secure access." - name: Set authorized key for user '{{ admin_user }}' + when: debian_base_ssh_key_stat.stat.exists ansible.posix.authorized_key: user: "{{ admin_user }}" state: present diff --git a/ansible/roles/debian_docker_host/tasks/10-docker-Debian.yaml b/ansible/roles/debian_docker_host/tasks/10-docker-Debian.yaml index 47959ae3..bede6896 100644 --- a/ansible/roles/debian_docker_host/tasks/10-docker-Debian.yaml +++ b/ansible/roles/debian_docker_host/tasks/10-docker-Debian.yaml @@ -11,17 +11,18 @@ - python3-pip - virtualenv - python3-setuptools + - python3-debian - cgroupfs-mount # To solve the issue: Docker failed to start daemon - "Devices cgroup isn't mounted" state: present -- name: Add Docker GPG Key (on Debian) - ansible.builtin.apt_key: - url: https://download.docker.com/linux/debian/gpg - state: present - -- name: Add Docker Repository (on Debian) - ansible.builtin.apt_repository: - repo: deb https://download.docker.com/linux/debian {{ ansible_facts["distribution_release"] }} stable +- name: Add Docker apt repository (on Debian) + ansible.builtin.deb822_repository: + name: docker + types: deb + uris: https://download.docker.com/linux/debian + suites: "{{ ansible_facts['distribution_release'] }}" + components: stable + signed_by: https://download.docker.com/linux/debian/gpg state: present - name: Update apt and install Docker packages diff --git a/ansible/roles/debian_docker_host/tasks/10-docker-Ubuntu.yaml b/ansible/roles/debian_docker_host/tasks/10-docker-Ubuntu.yaml index 69fbb0cf..99537119 100644 --- a/ansible/roles/debian_docker_host/tasks/10-docker-Ubuntu.yaml +++ b/ansible/roles/debian_docker_host/tasks/10-docker-Ubuntu.yaml @@ -13,14 +13,14 @@ - python3-setuptools state: present -- name: Add Docker GPG Key (on Ubuntu) - ansible.builtin.apt_key: - url: https://download.docker.com/linux/ubuntu/gpg - state: present - -- name: Add Docker Repository (on Ubuntu) - ansible.builtin.apt_repository: - repo: deb https://download.docker.com/linux/ubuntu {{ ansible_facts["distribution_release"] }} stable +- name: Add Docker apt repository (on Ubuntu) + ansible.builtin.deb822_repository: + name: docker + types: deb + uris: https://download.docker.com/linux/ubuntu + suites: "{{ ansible_facts['distribution_release'] }}" + components: stable + signed_by: https://download.docker.com/linux/ubuntu/gpg state: present - name: Update apt and install Docker packages diff --git a/ansible/roles/debian_homebrew/tasks/main.yaml b/ansible/roles/debian_homebrew/tasks/main.yaml new file mode 100644 index 00000000..72a455e6 --- /dev/null +++ b/ansible/roles/debian_homebrew/tasks/main.yaml @@ -0,0 +1,31 @@ +--- +# https://brew.sh/ +# https://docs.brew.sh/Homebrew-on-Linux + +- name: Install Homebrew prerequisites + ansible.builtin.apt: + name: + - build-essential + - procps + - curl + - file + - git + state: present + become: true + +- name: Install Homebrew + ansible.builtin.shell: | + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + args: + creates: /home/linuxbrew/.linuxbrew/bin/brew + environment: + NONINTERACTIVE: "1" + become: false + +- name: Add Homebrew to shell init + ansible.builtin.lineinfile: + path: "~/.bashrc" + line: 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' + create: true + mode: '0644' + become: false diff --git a/ansible/roles/debian_samba_client/tasks/10-samba.yaml b/ansible/roles/debian_samba_client/tasks/10-samba.yaml index a1370296..54e70ba1 100644 --- a/ansible/roles/debian_samba_client/tasks/10-samba.yaml +++ b/ansible/roles/debian_samba_client/tasks/10-samba.yaml @@ -6,6 +6,11 @@ - cifs-utils state: present +- name: Warn if admin_password is not set + ansible.builtin.debug: + msg: "WARNING: 'admin_password' is not defined — skipping credentials file creation. Samba mounts may fail." + when: admin_password is not defined + - name: Create credentials file ansible.builtin.copy: dest: "{{ debian_samba_client_credentials_file }}" @@ -15,6 +20,7 @@ owner: root group: root mode: "0600" + when: admin_password is defined - name: Create mount base directory ansible.builtin.file: @@ -41,3 +47,4 @@ opts: "{{ debian_samba_client_mount_opts }}" state: mounted loop: "{{ debian_samba_client_nas_shares }}" + when: admin_password is defined diff --git a/docs/setup.md b/docs/setup.md index de97fb62..046de1ff 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -52,9 +52,17 @@ MacOS is also supported, but only for working with Ansible remotely and applying Steps: - Clone the repository on a supported OS: `git clone ` -- Install Ansible with: `ansible/bootstrap-ansible.sh` -- Edit `ansible/inventory/inventory.yaml` and `ansible/playbooks/homelab.yaml`, include your host with `markosamuli.linuxbrew` and `debian_tools` roles -- Run `ansible/apply-homelab.sh` +- Install Ansible with: `sudo ansible/bootstrap-ansible.sh` + - Complete guide: [Ansible setup steps](../ansible/README.md#setup-steps) +- Update the configuration files: + - `ansible/inventory/group_vars/debian/vars.yaml` + - Place the SSH public key at the path indicated by `debian_base_ssh_key_file` (e.g. `~/.ssh/id_ed25519.pub`) + - `ansible/inventory/inventory.yaml` + - Add your host + - `ansible/playbooks/homelab.yaml` + - Include your host with `debian_tools` and `debian_homebrew` roles; add `debian_docker_host` if this host will also run Docker containers +- Apply the playbook locally: `ansible/apply-localhost.sh --ask-become-pass` + - (After passwordless sudo is configured, the `--ask-become-pass` parameter can be dropped) ### 3. Install Ubuntu Server VM (Docker host) @@ -68,7 +76,7 @@ Note - Alternatives: ### 4. Install and configure the required software using Ansible Required and recommended software (like Docker, tmux, ...) are installed and configured by Ansible. -For details, check the `ansible` / `inventory`|`roles`|`playbooks` folders. +See the [Ansible README](../ansible/README.md) for details on roles, inventories, and useful run options (`--limit`, `--verbose`). Execute on the admin host: `ansible/apply-homelab.sh`