refactor: restructured project for higher-utility naming practices and optimized data structures for variables
This commit is contained in:
@@ -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).
|
||||
@@ -0,0 +1,3 @@
|
||||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# defaults file for bootstrap
|
||||
@@ -0,0 +1,9 @@
|
||||
# @NOTE possible commit types: https://github.com/qoomon/git-conventional-commits?tab=readme-ov-file#config-file
|
||||
# @NOTE for description or body consider: motivation for or cause of change, impact and domain of change
|
||||
<type>[optional scope]: <description{<50char}>
|
||||
|
||||
[optional body]
|
||||
|
||||
# @NOTE footer should almost be treated as metadata of/for commit, or alerts of significant impact
|
||||
# @NOTE for footer purpose, see: https://dev.to/mochafreddo/a-comprehensive-guide-to-using-footers-in-conventional-commit-messages-37g6
|
||||
[optional footer(s)]
|
||||
@@ -0,0 +1,18 @@
|
||||
Match Group ftp
|
||||
ForceCommand internal-sftp -d /%u
|
||||
ChrootDirectory /srv/ftp
|
||||
AllowAgentForwarding no
|
||||
AllowTcpForwarding no
|
||||
X11Forwarding no
|
||||
|
||||
Match User ftp
|
||||
ForceCommand internal-sftp -d /public
|
||||
AuthorizedKeysFile /srv/ftp/.ssh/authorized_keys
|
||||
|
||||
Match User caddy,www-data
|
||||
ForceCommand internal-sftp -d /domain1.tld
|
||||
AuthorizedKeysFile /srv/www/.ssh/authorized_keys
|
||||
ChrootDirectory /srv/www
|
||||
AllowAgentForwarding no
|
||||
AllowTcpForwarding no
|
||||
X11Forwarding no
|
||||
@@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# handlers file for bootstrap
|
||||
@@ -0,0 +1,306 @@
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# handlers file for bootstrap
|
||||
- name: Configure git
|
||||
listen: git
|
||||
block:
|
||||
# @NOTE below are system git configuration
|
||||
- name: Configure git aliases
|
||||
become: true
|
||||
block:
|
||||
- name: Configure non-coding alias for merge subcommand
|
||||
community.general.git_config:
|
||||
name: alias.assimilate
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: merge
|
||||
- name: Configure alias for merge subcommand
|
||||
community.general.git_config:
|
||||
name: alias.mrg
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: merge
|
||||
- name: Configure non-coding alias for add subcommand
|
||||
community.general.git_config:
|
||||
name: alias.approve
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: add
|
||||
- name: Configure non-coding alias for status subcommand
|
||||
community.general.git_config:
|
||||
name: alias.revisions
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: status
|
||||
- name: Configure alias for status subcommand
|
||||
community.general.git_config:
|
||||
name: alias.stat
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: status
|
||||
- name: Configure non-coding alias for commit subcommand
|
||||
community.general.git_config:
|
||||
name: alias.finalize
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: commit
|
||||
- name: Configure alias for commit subcommand
|
||||
community.general.git_config:
|
||||
name: alias.cit
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: commit
|
||||
- name: Configure alias for config subcommand
|
||||
community.general.git_config:
|
||||
name: alias.cfg
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: config
|
||||
- name: Configure non-coding alias for commit subcommand with signing flag
|
||||
community.general.git_config:
|
||||
name: alias.claim
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: commit -S
|
||||
- name: Configure alias for commit subcommand with signing flag
|
||||
community.general.git_config:
|
||||
name: alias.sig
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: commit -S
|
||||
- name: Configure non-coding alias for show subcommand
|
||||
community.general.git_config:
|
||||
name: alias.review
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: show
|
||||
- name: Configure alias for show subcommand
|
||||
community.general.git_config:
|
||||
name: alias.peek
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: show
|
||||
- name: Configure alias for add subcommand with universal staging flag
|
||||
community.general.git_config:
|
||||
name: alias.badd
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: add -A
|
||||
- name: Configure non-coding alias for add subcommand with universal staging flag
|
||||
community.general.git_config:
|
||||
name: alias.approve-all
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: add -A
|
||||
- name: Configure non-coding alias for rm subcommand
|
||||
community.general.git_config:
|
||||
name: alias.redact
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: rm
|
||||
- name: Configure non-coding alias for init subcommand
|
||||
community.general.git_config:
|
||||
name: alias.author
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: init
|
||||
- name: Configure non-coding alias for mv subcommand
|
||||
community.general.git_config:
|
||||
name: alias.revise
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: mv
|
||||
- name: Configure non-coding alias for rebase subcommand
|
||||
community.general.git_config:
|
||||
name: alias.retroact
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: rebase
|
||||
- name: Configure alias for rebase subcommand
|
||||
community.general.git_config:
|
||||
name: alias.rb
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: rebase
|
||||
- name: Configure non-coding alias for push subcommand
|
||||
community.general.git_config:
|
||||
name: alias.publish
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: push
|
||||
- name: Configure non-coding alias for pull subcommand
|
||||
community.general.git_config:
|
||||
name: alias.publication
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: pull
|
||||
- name: Configure non-coding alias for fetch subcommand
|
||||
community.general.git_config:
|
||||
name: alias.manuscript
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: fetch
|
||||
- name: Configure alias for fetch subcommand
|
||||
community.general.git_config:
|
||||
name: alias.get
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: fetch
|
||||
- name: Configure non-coding alias for clone subcommand
|
||||
community.general.git_config:
|
||||
name: alias.copy
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: clone
|
||||
- name: Configure alias for clone subcommand
|
||||
community.general.git_config:
|
||||
name: alias.cp
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: clone
|
||||
- name: Configure non-coding alias for branch subcommand
|
||||
community.general.git_config:
|
||||
name: alias.draft
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: branch
|
||||
- name: Configure alias for branch subcommand
|
||||
community.general.git_config:
|
||||
name: alias.br
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: branch
|
||||
- name: Configure non-coding alias for switch subcommand
|
||||
community.general.git_config:
|
||||
name: alias.edit
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: switch
|
||||
- name: Configure alias for switch subcommand
|
||||
community.general.git_config:
|
||||
name: alias.cd
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: switch
|
||||
- name: Configure non-coding alias for restore subcommand
|
||||
community.general.git_config:
|
||||
name: alias.revert
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: restore
|
||||
- name: Configure alias for restore subcommand
|
||||
community.general.git_config:
|
||||
name: alias.rs
|
||||
add_mode: replace-all
|
||||
state: present
|
||||
value: restore
|
||||
- name: Set default editor for git
|
||||
become: true
|
||||
community.general.git_config:
|
||||
add_mode: replace-all
|
||||
name: core.editor
|
||||
state: present
|
||||
value: "{{ config.git.sys.editor }}"
|
||||
- name: Create a directory for storing system-level templates for git
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
group: root
|
||||
owner: root
|
||||
path: /etc/gitconfig.d
|
||||
state: directory
|
||||
- name: Create a commit message template file for git
|
||||
become: true
|
||||
ansible.builtin.copy:
|
||||
owner: root
|
||||
group: root
|
||||
backup: true
|
||||
dest: /etc/gitconfig.d/commit.msg
|
||||
force: true
|
||||
src: gitconfig.d/commit.msg
|
||||
- name: Set system-level commit message template file path for git
|
||||
become: true
|
||||
community.general.git_config:
|
||||
add_mode: replace-all
|
||||
name: commit.template
|
||||
state: present
|
||||
value: /etc/gitconfig.d/commit.msg
|
||||
- name: Set UI to have color for git at system-level
|
||||
become: true
|
||||
community.general.git_config:
|
||||
add_mode: replace-all
|
||||
name: color.ui
|
||||
state: present
|
||||
value: "true"
|
||||
- name: Set line-end conversion behavior for git
|
||||
become: true
|
||||
community.general.git_config:
|
||||
add_mode: replace-all
|
||||
name: core.autocrlf
|
||||
state: present
|
||||
value: input
|
||||
# @NOTE below are user git configuration
|
||||
- name: Create a user directory for a user gitignore file for git
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users
|
||||
ansible.builtin.file:
|
||||
owner: "{{ ansible_facts['user_id'] }}"
|
||||
group: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].group | default(ansible_facts['user_id']) }}"
|
||||
path: "{{ ansible_facts['user_dir'] }}/.config/git"
|
||||
state: directory
|
||||
- name: Create a user gitignore file for git
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users
|
||||
ansible.builtin.copy:
|
||||
owner: "{{ ansible_facts['user_id'] }}"
|
||||
group: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].group | default(ansible_facts['user_id']) }}"
|
||||
backup: true
|
||||
dest: "{{ ansible_facts['user_dir'] }}/.config/git/gitignore"
|
||||
force: true
|
||||
src: gitconfig.d/exclude.rules
|
||||
- name: Set user gitignore file path for git
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users
|
||||
community.general.git_config:
|
||||
add_mode: replace-all
|
||||
name: core.excludesfile
|
||||
scope: global
|
||||
state: present
|
||||
value: "{{ ansible_facts['user_dir'] }}/.config/git/gitignore"
|
||||
- name: Create link from user config directory git config file to user home directory git config file
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users
|
||||
community.general.file:
|
||||
src: "{{ ansible_facts['user_dir'] }}/.gitconfig"
|
||||
dest: "{{ ansible_facts['user_dir'] }}/.config/git/config"
|
||||
# @TODO check whether below two attributes make sense for links
|
||||
owner: "{{ ansible_facts['user_id'] }}"
|
||||
group: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].group | default(ansible_facts['user_id']) }}"
|
||||
state: hard
|
||||
- name: Set format for keys used by git
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users
|
||||
community.general.git_config:
|
||||
add_mode: replace-all
|
||||
name: gpg.format
|
||||
scope: global
|
||||
state: present
|
||||
value: openpgp
|
||||
- name: Set signing key to be used by git
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users and hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keys is not None and len(hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keys) > 0
|
||||
community.general.git_config:
|
||||
add_mode: replace-all
|
||||
name: user.signingkey
|
||||
scope: global
|
||||
state: present
|
||||
value: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keys[hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keyid_pref].id | default((hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keys | random).id) }}"
|
||||
- name: Set name of user of git
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users
|
||||
community.general.git_config:
|
||||
add_mode: replace-all
|
||||
name: user.name
|
||||
scope: global
|
||||
state: present
|
||||
value: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].git_profile.name }}"
|
||||
- name: Set email of user of git
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users
|
||||
community.general.git_config:
|
||||
add_mode: replace-all
|
||||
name: user.email
|
||||
scope: global
|
||||
state: present
|
||||
value: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].git_profile.email }}"
|
||||
@@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# handlers file for bootstrap
|
||||
- name: Postinstall set-up of git
|
||||
ansible.builtin.import_tasks:
|
||||
file: git.yml
|
||||
@@ -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.1
|
||||
|
||||
# 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.
|
||||
@@ -0,0 +1,38 @@
|
||||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# tasks file for bootstrap
|
||||
- name: Create GNUPGP directory in user home directory
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users
|
||||
ansible.builtin.file:
|
||||
group: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].group | default(ansible_facts['user_id']) }}"
|
||||
mode: "0700"
|
||||
owner: "{{ ansible_facts['user_id'] }}"
|
||||
path: "{{ ansible_facts['user_dir'] }}/.gnupg"
|
||||
state: directory
|
||||
- name: Create GPG key files
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users and hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keys is not None and len(hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keys) > 0
|
||||
ansible.builtin.copy:
|
||||
backup: true
|
||||
dest: "{{ ansible_facts['user_dir'] }}/.gnupg/{{ item.id }}.key"
|
||||
force: true
|
||||
group: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].group | default(ansible_facts['user_id']) }}"
|
||||
mode: "0600"
|
||||
owner: "{{ ansible_facts['user_id'] }}"
|
||||
src: "gnupg/{{ item.id }}.key"
|
||||
# validate: "gpg --verify {{ item.id }}.sig %s"
|
||||
loop: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keys }}"
|
||||
register: created_gpg_keys
|
||||
- name: Import GPG key files
|
||||
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users and hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keys is not None and len(hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keys) > 0
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- gpg
|
||||
- --batch
|
||||
- --passphrase-fd 0
|
||||
- --import
|
||||
- "{{ ansible_facts['user_dir'] }}/.gnupg/{{ item.id }}.key"
|
||||
stdin: "{{ item.password }}"
|
||||
loop: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].gpg_keys }}"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# tasks file for bootstrap
|
||||
- name: Create hidden SSH directories under users' home directories
|
||||
when: hostvars[inventory_hostname].groups.remote.group_name in item.value.groups
|
||||
ansible.builtin.file:
|
||||
group: "{{ item.value.group | default(item.value.username) }}"
|
||||
mode: "0700"
|
||||
owner: "{{ item.value.username }}"
|
||||
path: "{{ item.value.home | default('/home/' ~ item.value.username) }}/.ssh"
|
||||
state: directory
|
||||
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
|
||||
tags:
|
||||
- ensure_paths
|
||||
- ensure_files
|
||||
- name: Add authorized SSH public keys for users
|
||||
when: hostvars[inventory_hostname].groups.remote.group_name in item.value.groups and item.value.ssh_authorized_keys is not None and len(item.value.ssh_authorized_keys) > 0
|
||||
ansible.builtin.copy:
|
||||
backup: true
|
||||
content: "{{ item.value.ssh_authorized_keys.join('\n') }}"
|
||||
dest: "{{ item.value.home | default('/home/' ~ item.value.username) }}/.ssh/authorized_keys"
|
||||
# follow: true
|
||||
force: true
|
||||
group: "{{ item.value.group | default(item.value.username) }}"
|
||||
mode: "0600"
|
||||
owner: "{{ item.value.username }}"
|
||||
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
|
||||
tags:
|
||||
- ensure_files
|
||||
- name: Harden SSH security
|
||||
block:
|
||||
- name: Set users in group ftp to only be usable with SSH's SFTP service
|
||||
when: "'sftp' in item.value.services"
|
||||
ansible.builtin.blockinfile:
|
||||
backup: true
|
||||
block: |
|
||||
Match Group {{ item.value.group | default(item.value.username) }}
|
||||
ForceCommand internal-sftp -d /%u
|
||||
ChrootDirectory {{ item.value.home | default('/home/' ~ item.value.username) }}
|
||||
AllowAgentForwarding no
|
||||
AllowTcpForwarding no
|
||||
X11Forwarding no
|
||||
|
||||
Match User {{ item.value.username }}
|
||||
ForceCommand internal-sftp -d /public
|
||||
AuthorizedKeysFile {{ item.value.home | default('/home/' ~ item.value.username) }}/.ssh/authorized_keys
|
||||
create: true
|
||||
group: root
|
||||
insertafter: EOF
|
||||
marker: "# {mark} ANSIBLE-MANAGED SFTP BLOCK"
|
||||
marker_begin: BEGIN
|
||||
marker_end: END
|
||||
owner: root
|
||||
path: /etc/ssh/sshd_config.d/sftp.conf
|
||||
append_newline: true
|
||||
state: present
|
||||
validate: /bin/sshd -t
|
||||
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
|
||||
tags:
|
||||
- sftp_auth_step
|
||||
- name: Switch to preferred SSH authentication method
|
||||
ansible.builtin.template:
|
||||
backup: true
|
||||
comment_end_string: "#}"
|
||||
comment_start_string: "{#"
|
||||
dest: /etc/ssh/sshd_config.d/auth.conf
|
||||
# follow: true
|
||||
force: true
|
||||
group: root
|
||||
owner: root
|
||||
src: sshd_config.d/auth.conf.j2
|
||||
validate: /bin/sshd -t
|
||||
vars:
|
||||
empty_auth_used: false
|
||||
pass_auth_used: false
|
||||
pam_auth_used: false
|
||||
key_auth_used: true
|
||||
tags:
|
||||
- ssh_auth_step
|
||||
- name: Constrain idle online user accounts
|
||||
ansible.builtin.template:
|
||||
backup: true
|
||||
comment_end_string: "#}"
|
||||
comment_start_string: "{#"
|
||||
dest: /etc/ssh/sshd_config.d/harden.conf
|
||||
force: true
|
||||
group: root
|
||||
owner: root
|
||||
src: sshd_config.d/harden.conf.j2
|
||||
validate: /bin/sshd -t
|
||||
vars:
|
||||
client_subsistence: 900
|
||||
client_subsist_warn_max: 3
|
||||
tags:
|
||||
- ssh_timeout_step
|
||||
- name: Toggle ability to log in as root via SSH
|
||||
when: "hostvars[inventory_hostname].vps_service.root_fate == 'disposal'"
|
||||
ansible.builtin.template:
|
||||
backup: true
|
||||
comment_end_string: "#}"
|
||||
comment_start_string: "{#"
|
||||
dest: /etc/ssh/sshd_config.d/denyroot.conf
|
||||
force: true
|
||||
group: root
|
||||
owner: root
|
||||
src: sshd_config.d/denyroot.conf.j2
|
||||
validate: /bin/sshd -t
|
||||
vars:
|
||||
root_login_allowed: false
|
||||
tags:
|
||||
- ssh_root_step
|
||||
- name: Specify users or groups to whitelist or blacklist for SSH login
|
||||
when: "hostvars[inventory_hostname].vps_service.root_fate == 'disposal'"
|
||||
ansible.builtin.template:
|
||||
backup: true
|
||||
comment_end_string: "#}"
|
||||
comment_start_string: "{#"
|
||||
dest: /etc/ssh/sshd_config.d/allowance.conf
|
||||
force: true
|
||||
group: root
|
||||
owner: root
|
||||
src: sshd_config.d/allowance.conf.j2
|
||||
validate: /bin/sshd -t
|
||||
vars:
|
||||
list_type: whitelist
|
||||
policed_groups:
|
||||
- "{{ hostvars[inventory_hostname].groups.remote.group_name }}"
|
||||
tags:
|
||||
- ssh_gate_step
|
||||
tags:
|
||||
- ssh_harden_step
|
||||
@@ -0,0 +1,62 @@
|
||||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# tasks file for bootstrap
|
||||
- name: Create groups
|
||||
ansible.builtin.group:
|
||||
name: "{{ item.value.group_name }}"
|
||||
state: present
|
||||
system: "{{ 'true' if item.value.type == 'system' else 'false' }}"
|
||||
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].groups) }}"
|
||||
- name: Create users
|
||||
block:
|
||||
- name: Create administrative users
|
||||
when: "item.value.admin and item.value.type != 'system'"
|
||||
ansible.builtin.user:
|
||||
comment: "administrator for {{ fqdn.split('.')[0].lowercase }}"
|
||||
create_home: false
|
||||
home: "{{ item.value.home | default('/home/' ~ item.value.username) }}"
|
||||
generate_ssh_key: true
|
||||
ssh_key_comment: "ansible-generated for {{ item.value.username }}@{{ hostvars[inventory_hostname].fqdn.split('.')[0].lowercase() }}"
|
||||
ssh_key_type: "ed25519"
|
||||
group: "{{ item.value.group | default(item.value.username) }}"
|
||||
name: "{{ item.value.username }}"
|
||||
shell: "{{ item.value.shell }}"
|
||||
password: "{{ item.value.password }}"
|
||||
state: present
|
||||
system: "{{ 'true' if item.value.type == 'system' else 'false' }}"
|
||||
update_password: always
|
||||
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
|
||||
- name: Create regular users
|
||||
when: "not item.value.admin and item.value.type != 'system'"
|
||||
ansible.builtin.user:
|
||||
comment: "user of {{ fqdn.split('.')[0].lowercase }}"
|
||||
create_home: true
|
||||
home: "{{ item.value.home | default('/home/' ~ item.value.username) }}"
|
||||
generate_ssh_key: true
|
||||
group: "{{ item.value.group | default(item.value.username) }}"
|
||||
name: "{{ item.value.username }}"
|
||||
shell: "{{ item.value.shell }}"
|
||||
password: "{{ item.value.password }}"
|
||||
state: present
|
||||
system: "{{ 'true' if item.value.type == 'system' else 'false' }}"
|
||||
update_password: always
|
||||
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
|
||||
- name: Create users for managing data related to services
|
||||
when: "not item.value.admin and item.value.type == 'system' and item.value.service is not None"
|
||||
ansible.builtin.user:
|
||||
comment: "service data user for {{ item.value.services | random }} at {{ hostvars[inventory_hostname].fqdn.split('.')[0].lowercase() }}"
|
||||
create_home: false
|
||||
home: "{{ item.value.home | default('/home/' ~ item.value.username) }}"
|
||||
group: "{{ item.value.group | default(item.value.username) }}"
|
||||
name: "{{ item.value.username }}"
|
||||
shell: "{{ item.value.shell }}"
|
||||
state: present
|
||||
system: "{{ 'true' if item.value.type == 'system' else 'false' }}"
|
||||
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
|
||||
- name: Adjust users' groups
|
||||
when: item.value.groups is not None and len(item.value.groups) > 0
|
||||
ansible.builtin.user:
|
||||
name: "{{ item.value.username }}"
|
||||
append: true
|
||||
groups: "{{ item.value.groups }}"
|
||||
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
|
||||
@@ -0,0 +1,9 @@
|
||||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# tasks file for bootstrap
|
||||
- name: Populate system with groups and user accounts
|
||||
ansible.builtin.import_tasks:
|
||||
file: "create_users@{{ ansible_facts['system'].lowercase() }}.yml"
|
||||
- name: Configure SSH for root
|
||||
ansible.builtin.import_tasks:
|
||||
file: "configure_ssh@{{ ansible_facts['system'].lowercase() }}.yml"
|
||||
@@ -0,0 +1,86 @@
|
||||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# tasks file for bootstrap
|
||||
# @TODO create bootstrap tasks for installation and configuration of software
|
||||
- name: Update and upgrade software
|
||||
block:
|
||||
- name: Update Aptitude package cache and upgrade Aptitude packages
|
||||
when: "ansible_facts['pkg_mgr'] == 'apt'"
|
||||
become: true
|
||||
ansible.builtin.apt:
|
||||
upgrade: yes
|
||||
update_cache: yes
|
||||
cache_valid_time: 86400
|
||||
- name: Install NeoVim editor
|
||||
become: true
|
||||
block:
|
||||
- name: Install NeoVim using Aptitude package manager
|
||||
when: "ansible_facts['pkg_mgr'] == 'apt'"
|
||||
ansible.builtin.package:
|
||||
name: neovim
|
||||
use: "{{ ansible_facts['pkg_mgr'] }}"
|
||||
state: present
|
||||
# @TODO create handler to notify to for configuring neovim
|
||||
# notify: neovim
|
||||
- name: Install kitty-terminfo for SSH client xterm-kitty compatibility
|
||||
become: true
|
||||
block:
|
||||
- name: Install kitty-terminfo using Aptitude package manager
|
||||
when: "ansible_facts['pkg_mgr'] == 'apt'"
|
||||
ansible.builtin.package:
|
||||
name: kitty-terminfo
|
||||
use: "{{ ansible_facts['pkg_mgr'] }}"
|
||||
state: present
|
||||
- name: Install necessary software managers and container engines
|
||||
become: true
|
||||
block:
|
||||
- name: Install snapd
|
||||
when: "ansible_facts['pkg_mgr'] == 'apt'"
|
||||
block:
|
||||
- name: Install snapd using Aptitude package manager
|
||||
ansible.builtin.package:
|
||||
name: snapd
|
||||
use: "{{ ansible_facts['pkg_mgr'] }}"
|
||||
state: present
|
||||
- name: Install flatpak
|
||||
when: "ansible_facts['pkg_mgr'] == 'apt'"
|
||||
block:
|
||||
- name: Install flatpak using Aptitude package manager
|
||||
ansible.builtin.package:
|
||||
name: flatpak
|
||||
use: "{{ ansible_facts['pkg_mgr'] }}"
|
||||
state: present
|
||||
- name: Install podman
|
||||
when: "ansible_facts['pkg_mgr'] == 'apt'"
|
||||
block:
|
||||
- name: Install podman using Aptitude package manager
|
||||
ansible.builtin.package:
|
||||
name: podman
|
||||
use: "{{ ansible_facts['pkg_mgr'] }}"
|
||||
state: present
|
||||
- name: Install podman-compose
|
||||
when: "ansible_facts['pkg_mgr'] == 'apt'"
|
||||
block:
|
||||
- name: Install podman-compose using Aptitude package manager
|
||||
ansible.builtin.package:
|
||||
name: podman-compose
|
||||
use: "{{ ansible_facts['pkg_mgr'] }}"
|
||||
state: present
|
||||
- name: Install git
|
||||
block:
|
||||
- name: Install git using Aptitude package manager
|
||||
when: "ansible_facts['pkg_mgr'] == 'apt'"
|
||||
ansible.builtin.package:
|
||||
name: git
|
||||
use: "{{ ansible_facts['pkg_mgr'] }}"
|
||||
state: present
|
||||
notify: git
|
||||
- name: Install packages
|
||||
when: ansible_facts['pkg_mgr'] in item.value.name
|
||||
ansible.builtin.package:
|
||||
name: "{{ item.value.name[ansible_facts['pkg_mgr']] }}"
|
||||
use: "{{ ansible_facts['pkg_mgr'] }}"
|
||||
state: present
|
||||
# @TODO research what happens when nonexistent handler is called or notify field is null
|
||||
notify: "{{ item.key }}"
|
||||
loop: "{{ lookup('ansible.builtin.dict', software.pkgs) }}"
|
||||
@@ -0,0 +1,9 @@
|
||||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# tasks file for bootstrap
|
||||
- name: Configure GPG for user
|
||||
ansible.builtin.import_tasks:
|
||||
file: "configure_gpg@{{ ansible_facts['system'].lowercase() }}.yml"
|
||||
- name: Install and configure software on system
|
||||
ansible.builtin.import_tasks:
|
||||
file: "install@{{ ansible_facts['system'].lowercase() }}.yml"
|
||||
@@ -0,0 +1,15 @@
|
||||
{% if list_type == 'whitelist' %}
|
||||
{% if policed_groups is not None and len(policed_groups) > 0 %}
|
||||
AllowGroups {{ policed_groups.join(' ') }}
|
||||
{% endif %}
|
||||
{% if policed_users is not None and len(policed_users) > 0 %}
|
||||
AllowUsers {{ policed_users.join(' ') }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if policed_groups is not None and len(policed_groups) > 0 %}
|
||||
DenyGroups {{ policed_groups.join(' ') }}
|
||||
{% endif %}
|
||||
{% if policed_users is not None and len(policed_users) > 0 %}
|
||||
DenyGroups {{ policed_users.join(' ') }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -0,0 +1,27 @@
|
||||
{% if empty_auth_used %}
|
||||
PermitEmptyPasswords yes
|
||||
{% else %}
|
||||
PermitEmptyPasswords no
|
||||
{% endif %}
|
||||
{% if pass_auth_used %}
|
||||
PasswordAuthentication yes
|
||||
{% else %}
|
||||
PasswordAuthentication no
|
||||
{% endif %}
|
||||
{% if kbd_auth_used is not None %}
|
||||
{% if kbd_auth_used %}
|
||||
KbdInteractiveAuthentication yes
|
||||
{% else %}
|
||||
KbdInteractiveAuthentication no # enable if implementing TOTP 2FA
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if pam_auth_used %}
|
||||
UsePAM yes
|
||||
{% else %}
|
||||
UsePAM no # enable if implementing TOTP 2FA
|
||||
{% endif %}
|
||||
{% if key_auth_used %}
|
||||
PubkeyAuthentication yes
|
||||
{% else %}
|
||||
PubkeyAuthentication no
|
||||
{% endif %}
|
||||
@@ -0,0 +1,5 @@
|
||||
{% if root_login_allowed %}
|
||||
PermitRootLogin yes
|
||||
{% else %}
|
||||
PermitRootLogin no
|
||||
{% endif %}
|
||||
@@ -0,0 +1,2 @@
|
||||
ClientAliveInterval {{ client_subsistence }}
|
||||
ClientAliveCountMax {{ client_subsist_warn_max }}
|
||||
@@ -0,0 +1,3 @@
|
||||
#SPDX-License-Identifier: MIT-0
|
||||
localhost
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
- hosts: localhost
|
||||
remote_user: root
|
||||
roles:
|
||||
- bootstrap
|
||||
@@ -0,0 +1,208 @@
|
||||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# vars file for bootstrap
|
||||
# @TODO make list or dictionary of software to be installed in bootstrap task
|
||||
software:
|
||||
pkgs:
|
||||
# @NOTE keep fields or keys constant; otherwise will have to edit handler notifiers and listeners elsewhere
|
||||
gocryptfs:
|
||||
name:
|
||||
apt: gocryptfs
|
||||
lua-lang:
|
||||
name:
|
||||
apt: lua5.4
|
||||
lua-docs:
|
||||
name:
|
||||
apt: luadoc
|
||||
lua-pkg:
|
||||
name:
|
||||
apt: luarocks
|
||||
python-lang:
|
||||
name:
|
||||
apt: python3
|
||||
python-pkg:
|
||||
name:
|
||||
apt: python3-pip
|
||||
python-linter:
|
||||
name:
|
||||
apt: python3-doc8
|
||||
python-docs:
|
||||
name:
|
||||
apt: python3-doc
|
||||
rust-lang:
|
||||
name:
|
||||
apt: rustc # @NOTE alternative: rustup
|
||||
rust-pkg:
|
||||
name:
|
||||
apt: cargo
|
||||
rust-debugger:
|
||||
name:
|
||||
apt: rust-analyzer
|
||||
rust-linter:
|
||||
name:
|
||||
apt: rust-clippy
|
||||
rust-docs:
|
||||
name:
|
||||
apt: rust-doc
|
||||
java-lang:
|
||||
name:
|
||||
apt: default-jdk-headless
|
||||
java-docs:
|
||||
name:
|
||||
apt: default-jdk-doc
|
||||
java-runtime:
|
||||
name:
|
||||
apt: default-jre-headless
|
||||
kotlin-lang:
|
||||
name:
|
||||
apt: kotlin
|
||||
swift-lang:
|
||||
name:
|
||||
apt: swiftlang
|
||||
swift-docs:
|
||||
name:
|
||||
apt: swiftlang-doc
|
||||
erlang-lang:
|
||||
name:
|
||||
apt: erlang
|
||||
erlang-pkg:
|
||||
name:
|
||||
apt: erlang-hex
|
||||
erlang-docs:
|
||||
name:
|
||||
apt: erlang-doc
|
||||
elixir-lang:
|
||||
name:
|
||||
apt: elixir
|
||||
crystal-lang:
|
||||
name:
|
||||
apt: crystal
|
||||
crystal-docs:
|
||||
name:
|
||||
apt: crystal-doc
|
||||
javascript-lang:
|
||||
name:
|
||||
apt: nodejs
|
||||
javascript-docs:
|
||||
name:
|
||||
apt: nodejs-doc
|
||||
javascript-pkg:
|
||||
name:
|
||||
apt: npm
|
||||
javascript-linter:
|
||||
name:
|
||||
apt: eslint
|
||||
php-lang:
|
||||
name:
|
||||
apt: php
|
||||
php-docs:
|
||||
name:
|
||||
apt: php-common
|
||||
php-debugger:
|
||||
name:
|
||||
apt: php-xdebug
|
||||
php-pkg:
|
||||
name:
|
||||
apt: composer
|
||||
html-linter:
|
||||
name:
|
||||
apt: tidy
|
||||
json-linter:
|
||||
name:
|
||||
apt: jsonlint
|
||||
yaml-linter:
|
||||
name:
|
||||
apt: yamllint
|
||||
pandoc:
|
||||
name:
|
||||
apt: pandoc
|
||||
distrobox:
|
||||
name:
|
||||
apt: distrobox
|
||||
# @TODO manually install the commented below on current active new VPS, then uncomment
|
||||
# duplicity:
|
||||
# name:
|
||||
# apt: duplicity
|
||||
# pass:
|
||||
# name:
|
||||
# apt: pass
|
||||
# sonicpi:
|
||||
# name:
|
||||
# apt: sonic-pi-server
|
||||
# sonicpi-docs:
|
||||
# name:
|
||||
# apt: sonic-pi-server-doc
|
||||
# supercollider:
|
||||
# name:
|
||||
# apt: supercollider
|
||||
# supercollider-docs:
|
||||
# name:
|
||||
# apt: supercollider-common
|
||||
# supercollider-plugins:
|
||||
# name:
|
||||
# apt: sc3-plugins-language
|
||||
qrencode:
|
||||
name:
|
||||
apt: qrencode
|
||||
ffmpeg:
|
||||
name:
|
||||
apt: ffmpeg
|
||||
ffmpeg-docs:
|
||||
name:
|
||||
apt: ffmpeg-doc
|
||||
graphicsmagick:
|
||||
name:
|
||||
apt: graphicsmagick
|
||||
graphicsmagick-compatibility:
|
||||
name:
|
||||
apt: graphicsmagick-imagemagick-compat
|
||||
timg:
|
||||
name:
|
||||
apt: timg
|
||||
tmux:
|
||||
name:
|
||||
apt: tmux
|
||||
# @TODO add glow apt repository in install@linux bootstrap role play before uncommenting the below
|
||||
# glow:
|
||||
# name:
|
||||
# apt: glow
|
||||
# @TODO add ZFS apt repository in install@linux bootstrap role play before uncommenting the below
|
||||
# zfs:
|
||||
# name:
|
||||
# apt: zfsutils-linux
|
||||
# @TODO manually install the commented below on current active new VPS, then uncomment
|
||||
# dpkg-dev:
|
||||
# name:
|
||||
# apt: dpkg-dev
|
||||
# ldap-utils:
|
||||
# name:
|
||||
# apt: ldap-utils
|
||||
# slapd:
|
||||
# name:
|
||||
# apt: slapd
|
||||
# proftpd:
|
||||
# name:
|
||||
# apt: proftpd
|
||||
# rsync:
|
||||
# name:
|
||||
# apt: rsync
|
||||
# rclone:
|
||||
# name:
|
||||
# apt: rsync
|
||||
# aria:
|
||||
# name:
|
||||
# apt: aria2
|
||||
# mopidy:
|
||||
# name:
|
||||
# apt: mopidy
|
||||
# mopidy-mpd:
|
||||
# name:
|
||||
# apt: mopidy-mpd
|
||||
# caddy:
|
||||
# name:
|
||||
# apt: caddy
|
||||
config:
|
||||
git:
|
||||
sys:
|
||||
editor: nvim
|
||||
|
||||
Reference in New Issue
Block a user