created role for bootstrapping a Linode VPS via API or a LAN homeserver

This commit is contained in:
2026-05-26 16:04:41 -04:00
parent c3e1f95350
commit ba5aa5e8d4
16 changed files with 782 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
Role Name
=========
A brief description of the role goes here.
Requirements
------------
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
Role Variables
--------------
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
Dependencies
------------
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
- hosts: servers
roles:
- { role: username.rolename, x: 42 }
License
-------
BSD
Author Information
------------------
An optional section for the role authors to include contact information, or a website (HTML is not allowed).

View File

@@ -0,0 +1,4 @@
#SPDX-License-Identifier: MIT-0
---
# defaults file for roles/init-vps
ip_pref: ipv4 # <str<enum>> represents internet protocol in use

View File

@@ -0,0 +1,2 @@
# <str<bool>> whether to harden managed node's SSH service
harden: true

View File

@@ -0,0 +1,11 @@
#SPDX-License-Identifier: MIT-0
---
# defaults file for roles/init-vps
# <list<dict>> list of administrative users (in Linux, users that can use "sudo")
admins:
- username: "" # <str> arbitrary valid user name
services: [] # <list[<str>]> if linux system user, assocated servce
keys: [] # <list[<str>]> list of control node or local SSH key basenames for this user
password: "" # <str<vault?>> hashed (and maybe salted) password
# <list[<dict>]> list of system users, typically for use for particular services
sys_users: []

View File

@@ -0,0 +1,7 @@
PermitEmptyPasswords no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no # enable if implementing TOTP 2FA
UsePAM yes
PrintMotd yes
Banner /etc/banner

View File

@@ -0,0 +1 @@
PermitRootLogin no

View File

@@ -0,0 +1,2 @@
ClientAliveInterval 900
ClientAliveCountMax 3

View File

@@ -0,0 +1,54 @@
# SPDX-License-Identifier: MIT-0
---
# handlers file for roles/init-vps
- name: Executing relevant files for software installation from git repository
block:
- name: Finalizing quartz installation
listen: quartz
block:
- name: Installing NodeJS dependencies of quartz software
community.general.npm:
executable: "{{ ansible_facts['user_dir'] }}/.nvm/versions/node/v24.11.1/lib/node_modules/npm"
path: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
state: latest
- name: Configuring quartz software
block:
- name: Initializing quartz website
ansible.builtin.command:
chdir: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
cmd: npx quartz create
register: stdout
changed_when: stdout.rc == 0
- name: Installing quartz plugins referenced in website template
ansible.builtin.command:
chdir: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
cmd: npx quartz plugin install --from-config
register: stdout
changed_when: stdout.rc == 0
# - name: Starting quartz site web server
# ansible.builtin.command:
# chdir: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
# cmd: npx quartz build --serve
# register: stdout
# changed_when: stdout
- name: Committing requisite actions for building software from source archives
block:
- name: Finalizing building of Surge
listen: surge
block:
- name: Hardlinking Surge executable
ansible.builtin.file:
src: "{{ ansible_facts['user_dir'] }}/downloads/archives/released/surge/surge"
dest: "{{ ansible_facts['user_dir'] }}/.local/bin/surge"
state: hard
mode: "755"
- name: Copying Surge executable
become: true
ansible.builtin.copy:
src: "{{ ansible_facts['user_dir'] }}/downloads/archives/released/surge/surge"
dest: /usr/bin/surge
owner: root
group: root
mode: "755"
force: true
backup: false

View File

@@ -0,0 +1,35 @@
#SPDX-License-Identifier: MIT-0
galaxy_info:
author: your name
description: your role description
company: your company (optional)
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
# - MIT
# - GPL-2.0-or-later
# - GPL-3.0-only
# - Apache-2.0
# - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: 2.2
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.

View File

@@ -0,0 +1,125 @@
#SPDX-License-Identifier: MIT-0
---
# tasks file for roles/init-vps
- name: Creating prerequisite directory tree
ansible.builtin.file:
path: "{{ ansible_facts['user_dir'] }}/.local/bin"
recurse: true
state: directory
- name: Creating prerequisite directory tree
ansible.builtin.file:
path: "{{ ansible_facts['user_dir'] }}/downloads/archives/released"
recurse: true
state: directory
- name: Installing Linux software
when: ansible_facts["system"] == "Linux"
block:
- name: Installing software using Debian package manager
when: ansible_facts["os_family"] == "Debian"
become: true
block:
- name: Registering a package signing key
when: item.key is defined and item.key_path is defined
ansible.builtin.get_url:
url: "{{ item.key }}"
dest: "{{ item.key_path | default('/etc/apt/keyrings/') }}"
owner: root
group: root
mode: "644"
force: true
backup: true
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace | rejectattr('key', 'search', '\\.deb$') }}"
- name: Installing a package signing key
when: item.key is defined
ansible.builtin.apt:
deb: "{{ item.key }}"
state: present
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace | selectattr('key', 'search', '\\.deb$') }}"
- name: Registering a package source
when: item.src_entry is defined and item.src_path is defined
ansible.builtin.copy:
content: "{{ item.src_entry }}"
dest: "{{ item.src_path }}"
owner: root
group: root
mode: "644"
force: true
backup: true
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace }}"
- name: Installing a local package in managed node
when: item.uri is defined
ansible.builtin.apt:
deb: "{{ item.uri }}"
update_cache: true
state: present
notify: "{{ item.name }}"
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace | selectattr('uri', 'search', '\\.deb$') }}"
- name: Installing a package
when: item.name is defined and item.uri is undefined
ansible.builtin.package:
name: "{{ item.name }}"
update_cache: true
state: latest
notify: "{{ item.name }}" # @TODO create corresponding roles/init-vps handlers
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace | rejectattr('uri', 'search', '\\.deb$') }}"
tags:
- get_mngr_pkgs
- name: Installing software by executing installation shell scripts
when: item.src is defined
block:
- name: Acquiring installation shell script
ansible.builtin.get_url:
url: "{{ item.src }}"
dest: "{{ ansible_facts['user_dir'] }}/.local/bin/{{ item.name }}-install.sh"
force: true
backup: true
mode: "744"
loop: "{{ pkgs.script.core + pkgs.script.userspace }}"
register: install_scripts
- name: Executing a shell-scripted installation process
become: true
ansible.builtin.shell:
cmd: "{{ item.dest }}"
notify: "{{ (pkgs.script.core + pkgs.script.userspace)[idx].name }}"
loop: "{{ install_scripts.results }}"
loop_control:
index_var: idx
tags:
- get_script_pkgs
# @TODO complete below block task
- name: Installing software by building it from source archives
block:
- name: Acquiring software source archive
ansible.builtin.get_url:
url: "{{ item.src }}"
dest: "{{ ansible_facts['user_dir'] }}/downloads/archives/"
force: true
backup: true
mode: "644"
loop: "{{ pkgs.archive.core + pkgs.archive.userspace }}"
register: archived_builds
- name: Unarchiving software build archive
ansible.builtin.unarchive:
src: "{{ item.dest }}"
remote_src: true
dest: "{{ ansible_facts['user_dir'] }}/downloads/archives/released/{{ (pkgs.archive.core + pkgs.archive.userspace)[idx].name }}/"
notify: "{{ (pkgs.archive.core + pkgs.archive.userspace)[idx].name }}"
loop: "{{ archived_builds.results }}"
loop_control:
index_var: idx
tags:
- get_archive_pkgs
- name: Installing software from source git repositories
block:
- name: Clone git bare repository
ansible.builtin.git:
repo: "{{ item.src }}"
dest: "{{ ansible_facts['user_dir'] }}/repos/.foreign/{{ item.name }}"
version: "{{ item.branch }}"
clone: true
single_branch: true
notify: "{{ item.name }}"
loop: "{{ pkgs.git_repos.core + pkgs.git_repos.userspace }}"
register: installation_repos
tags:
- get_git_pkgs

View File

@@ -0,0 +1,41 @@
#SPDX-License-Identifier: MIT-0
---
# tasks file for roles/init-vps
# @TODO complete below tasks
- name: Checking whether administrative login used
when: ansible_facts["user_id"] not in (admins | map(attribute="username") | list)
ansible.builtin.fail:
msg: Administrative user does not exist on managed node
- name: Prohibiting SSH root login
when: harden
become: true
ansible.builtin.copy:
src: sshd_config.d/denyroot.conf
dest: /etc/ssh/sshd_config.d/denyroot.conf
owner: root
group: root
mode: "644"
force: true
backup: true
validate: "sshd -t %s"
- name: Create groups for FTP services
when: "'internal-sftp' in item.service or 'proftpd' in item.service or 'vsftpd' in item.service"
become: true
ansible.builtin.group:
name: "{{ item.username }}"
system: true
state: present
loop: "{{ sys_users }}"
register: ftp_groups
- name: Configuring SFTP for FTP group
become: true
ansible.builtin.template:
src: sshd_config.d/sftp.conf.j2
dest: /etc/ssh/sshd_config.d/sftp.conf
owner: root
group: root
mode: "644"
force: true
backup: true
validate: "sshd -t %s"
register: configured_sftp

View File

@@ -0,0 +1,443 @@
#SPDX-License-Identifier: MIT-0
---
# tasks file for roles/init-vps
# @NOTE server deployment method is based on task tags compiled herein
# @TODO review 'loop' task attribute return values and make compliant changes
- name: Finding SSH public keys for root
ansible.builtin.find:
paths: "{{ cnode_homedir | default('/home/' ~ ansible_user ~ '/.ssh') }}" # @TODO define 'cnode_homedir' in playbook
patterns: "{{ ['^'] | product(keys) | map('join') | list }}"
file_type: file
use_regex: true
register: ssh_keypairs
- name: Bootstrapping VPS
block:
- name: Creating VPS via Linode VPS service API
block:
- name: Creating the VPS
linode.cloud.instance:
api_token: "{{ token }}"
label: "{{ instance }}"
type: g6-standard-2
image: "{{ operating_system }}"
disk_encryption: enabled
region: "{{ origin }}"
private_ip: true
root_pass: "{{ password }}"
authorized_keys: "{{ ssh_keypairs.files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | map('lookup', 'file') | list }}"
state: present
register: new_instance
- name: Waiting for that VPS to come online
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
delegate_facts: true
ansible.builtin.wait_for_connection:
delay: 20
timeout: 300
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
- name: Checking if that VPS has required operating system
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
delegate_facts: true
when: ansible_facts["system"] != "Linux"
ansible.builtin.fail:
msg: Unsupported operating system found
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
- name: Checking if that VPS has required Linux distro
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
delegate_facts: true
when: ansible_facts["system"] == "Linux" and ansible_facts["os_family"] != "Debian"
ansible.builtin.fail:
msg: Unsupported Linux distro found
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
tags:
- linode
tags:
- vps
- name: Bootstrapping homeserver
block:
- name: Installing operating system or distro in server
when: operating_system is defined
block:
- name: Creating a server
block: []
tags:
- unimplemented
- name: Waiting for that VPS to come online
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
delegate_facts: true
ansible.builtin.wait_for_connection:
delay: 20
timeout: 300
vars:
ansible_user: root
- name: Checking if that server has required operating system
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
delegate_facts: true
when: ansible_facts["system"] != "Linux"
ansible.builtin.fail:
msg: Unsupported operating system found
vars:
ansible_user: root
- name: Checking if that server has required Linux distro
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
delegate_facts: true
when: ansible_facts["system"] == "Linux" and ansible_facts["os_family"] != "Debian"
ansible.builtin.fail:
msg: Unsupported Linux distro found
vars:
ansible_user: root
- name: Providing authorized keys for server root account
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
delegate_facts: true
ansible.posix.authorized_key:
user: "{{ ansible_facts['user_id'] }}"
key: "{{ lookup('file', item) }}"
state: present
vars:
ansible_root: root
loop: "{{ ssh_keypairs.files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | list }}"
tags:
- lan
- name: Starting SSH hardening
when: harden
delegate_facts: true
block:
- name: Hardening SSH service for the Linode VPS
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
ansible.builtin.copy:
src: sshd_config.d/harden.conf
dest: /etc/ssh/sshd_config.d/harden.conf
owner: root
group: root
mode: "644"
force: true
backup: true
validate: "sshd -t %s"
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
register: ssh_hardened
tags:
- linode
- name: Hardening SSH service for the server
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
ansible.builtin.copy:
src: sshd_config.d/harden.conf
dest: /etc/ssh/sshd_config.d/harden.conf
owner: root
group: root
mode: "644"
force: true
backup: true
validate: "sshd -t %s"
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
register: ssh_hardened
tags:
- lan
- name: Starting user and group creation for SSH access
block:
- name: Creating group remote for managing SSH access
delegate_facts: true
block:
- name: In the Linode VPS
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
ansible.builtin.group:
name: remote
system: true
state: present
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
register: remote_group
tags:
- linode
- name: In the server
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
ansible.builtin.group:
name: remote
system: true
state: present
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
register: remote_group
tags:
- lan
- name: Creating an administrative user
delegate_facts: true
when: ansible_facts["system"] == "Linux"
block:
- name: In the Linode VPS
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
ansible.builtin.user:
name: "{{ item.username }}"
comment: administrator
group: "{{ item.username }}"
groups:
- "{{ remote_group.name }}"
- sudo # @NOTE used by Debian
append: true
generate_ssh_key: true
create_home: true
password: "{{ item.password }}"
shell: "/bin/bash"
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
loop: "{{ admins }}"
register: admin_users
tags:
- linode
- name: In the server
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
ansible.builtin.user:
name: "{{ item.username }}"
comment: administrator
group: "{{ item.username }}"
groups:
- "{{ remote_group.name }}"
- sudo # @NOTE used by Debian
append: true
generate_ssh_key: true
create_home: true
password: "{{ item.password }}"
shell: "/bin/bash"
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
loop: "{{ admins }}"
register: admin_users
tags:
- lan
- name: Finding SSH public keys for an administrative user
when: item.username in (admin_users.results | map(attribute="name") | list)
ansible.builtin.find:
paths: "{{ cnode_homedir | default('/home/' ~ ansible_user ~ '/.ssh') }}" # @TODO define 'cnode_homedir' in playbook
patterns: "{{ ['^'] | product(item.keys) | map('join') | list }}"
file_type: file
use_regex: true
loop: "{{ admins }}"
register: admin_ssh_keypairs
- name: Authorizing SSH public key for an administrative user
delegate_facts: true
block:
- name: In the Linode VPS
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
ansible.posix.authorized_key:
user: "{{ admin_users.results[idx] }}"
key: "{{ admin_ssh_keypairs.results[idx].files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | map('lookup', 'file') | list | map('join','\n') }}"
state: present
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
loop: "{{ admin_users.results }}"
loop_control:
index_var: idx
register: ssh_authorizations
tags:
- linode
- name: In the server
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
ansible.posix.authorized_key:
user: "{{ admin_users.results[idx] }}"
key: "{{ admin_ssh_keypairs.results[idx].files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | map('lookup', 'file') | list | map('join','\n') }}"
state: present
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
loop: "{{ admin_users.results }}"
loop_control:
index_var: idx
register: ssh_authorizations
tags:
- lan
- name: Allowing sole SSH access to users in group remote
delegate_facts: true
block:
- name: In Linode VPS
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
ansible.builtin.template:
src: sshd_config.d/allowance.conf.j2 # @TODO create corresponding role template file
dest: /etc/ssh/sshd_config.d/allowance.conf
owner: root
group: root
mode: "644"
force: true
backup: true
validate: "sshd -t %s"
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
register: ssh_gatekept
tags:
- linode
- name: In Linode VPS
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
ansible.builtin.template:
src: sshd_config.d/allowance.conf.j2 # @TODO create corresponding role template file
dest: /etc/ssh/sshd_config.d/allowance.conf
owner: root
group: root
mode: "644"
force: true
backup: true
validate: "sshd -t %s"
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
register: ssh_gatekept
tags:
- lan
- name: Setting approved SSH authentication procedures
when: harden
delegate_facts: true
block:
- name: In the Linode VPS
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
ansible.builtin.copy:
src: sshd_config.d/auth.conf
dest: /etc/ssh/sshd_config.d/auth.conf
owner: root
group: root
mode: "644"
force: true
backup: true
validate: "sshd -t %s"
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
register: ssh_authenticator
tags:
- linode
- name: In the server
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
ansible.builtin.copy:
src: sshd_config.d/auth.conf
dest: /etc/ssh/sshd_config.d/auth.conf
owner: root
group: root
mode: "644"
force: true
backup: true
validate: "sshd -t %s"
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
register: ssh_authenticator
tags:
- lan
- name: Installing core packages
delegate_facts: true
block:
- name: In the Linode VPS
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
block:
- name: Registering a package signing key
when: ansible_facts["os_family"] == "Debian" and item.key is defined and item.key_path is defined
ansible.builtin.get_url:
url: "{{ item.key }}"
dest: "{{ item.key_path | default('/etc/apt/keyrings/') }}"
owner: root
group: root
mode: "644"
force: true
backup: true
loop: "{{ pkgs.mngr.core | rejectattr('key', 'search', '\\.deb$') }}"
- name: Installing a package signing key
when: ansible_facts["os_family"] == "Debian" and item.key is defined
ansible.builtin.apt:
deb: "{{ item.key }}"
state: latest
loop: "{{ pkgs.mngr.core | selectattr('key', 'search', '\\.deb$') }}"
- name: Registering a package source
when: ansible_facts["os_family"] == "Debian" and item.src_entry is defined and item.src_path is defined
ansible.builtin.copy:
content: "{{ item.src_entry }}"
dest: "{{ item.src_path }}"
owner: root
group: root
mode: "644"
force: true
backup: true
loop: "{{ pkgs.mngr.core }}"
- name: Installing a local package in managed node
when: ansible_facts["os_family"] == "Debian" and item.uri is defined
ansible.builtin.apt:
deb: "{{ item.uri }}"
update_cache: true
state: latest
loop: "{{ pkgs.mngr.core | selectattr('uri', 'search', '\\.deb$') }}"
- name: Installing a package
when: item.name is defined and item.uri is undefined
ansible.builtin.package:
name: "{{ item.name }}"
update_cache: true
state: latest
notify: "{{ item.name }}" # @TODO create corresponding roles/init-vps handlers
loop: "{{ pkgs.mngr.core| rejectattr('uri', 'search', '\\.deb$') }}"
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
tags:
- linode
- name: In the server
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
block:
- name: Registering a package signing key
when: ansible_facts["os_family"] == "Debian" and item.key is defined and item.key_path is defined
ansible.builtin.get_url:
url: "{{ item.key }}"
dest: "{{ item.key_path | default('/etc/apt/keyrings/') }}"
owner: root
group: root
mode: "644"
force: true
backup: true
loop: "{{ pkgs.mngr.core | rejectattr('key', 'search', '\\.deb$') }}"
- name: Installing a package signing key
when: ansible_facts["os_family"] == "Debian" and item.key is defined
ansible.builtin.apt:
deb: "{{ item.key }}"
state: latest
loop: "{{ pkgs.mngr.core | selectattr('key', 'search', '\\.deb$') }}"
- name: Registering a package source
when: ansible_facts["os_family"] == "Debian" and item.src_entry is defined and item.src_path is defined
ansible.builtin.copy:
content: "{{ item.src_entry }}"
dest: "{{ item.src_path }}"
owner: root
group: root
mode: "644"
force: true
backup: true
loop: "{{ pkgs.mngr.core }}"
- name: Installing a local package in managed node
when: ansible_facts["os_family"] == "Debian" and item.uri is defined
ansible.builtin.apt:
deb: "{{ item.uri }}"
update_cache: true
state: latest
notify: "{{ item.name }}"
loop: "{{ pkgs.mngr.core | selectattr('uri', 'search', '\\.deb$') }}"
- name: Installing a package
when: item.name is defined and item.uri is undefined
ansible.builtin.package:
name: "{{ item.name }}"
update_cache: true
state: latest
notify: "{{ item.name }}" # @TODO create corresponding roles/init-vps handlers
loop: "{{ pkgs.mngr.core| rejectattr('uri', 'search', '\\.deb$') }}"
vars:
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
ansible_user: root
tags:
- lan
tags:
- get_pkgs

View File

@@ -0,0 +1 @@
AllowGroups {{ remote_group.name }}

View File

@@ -0,0 +1,9 @@
{% for item in ftp_groups.results %}
Match Group {{ item.name }}
ForceCommand internal-sftp -d /%u
ChrootDirectory /srv/{{ item.name}}
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
{% endfor %}

View File

@@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
localhost

View File

@@ -0,0 +1,6 @@
#SPDX-License-Identifier: MIT-0
---
- hosts: localhost
remote_user: root
roles:
- roles/init-vps