init commit
This commit is contained in:
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Secrets and sensitive inventory
|
||||||
|
inventory/*.ini
|
||||||
|
inventory/host_vars/
|
||||||
|
inventory/group_vars/*_vault.yml
|
||||||
|
.vault_pass.txt
|
||||||
|
|
||||||
|
# SSH keys
|
||||||
|
*.pem
|
||||||
|
id_rsa*
|
||||||
|
id_ed25519*
|
||||||
|
|
||||||
|
# Local config
|
||||||
|
.ansible.cfg
|
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# semaphore
|
||||||
|
|
||||||
|
Ansible GUI for infrastructure management
|
20
playbooks/add-gitea-ssh-key.yml
Normal file
20
playbooks/add-gitea-ssh-key.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
- name: Add SSH key from Gitea
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Ensure .ssh directory exists
|
||||||
|
file:
|
||||||
|
path: "/home/{{ username }}/.ssh"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ username }}"
|
||||||
|
group: "{{ username }}"
|
||||||
|
mode: '0700'
|
||||||
|
|
||||||
|
- name: Add public key from Gitea to authorized_keys
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: "{{ username }}"
|
||||||
|
key: "https://gitea.purpleraft.com/{{ username }}.keys"
|
||||||
|
state: present
|
||||||
|
manage_dir: false # we already ensured it
|
29
playbooks/add-usertogroup.yml
Normal file
29
playbooks/add-usertogroup.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure user is in specified group
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
vars:
|
||||||
|
check_user: "{{ check_user }}"
|
||||||
|
check_group: "{{ check_group }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Ensure group exists
|
||||||
|
group:
|
||||||
|
name: "{{ check_group }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Check if user exists
|
||||||
|
getent:
|
||||||
|
database: passwd
|
||||||
|
key: "{{ check_user }}"
|
||||||
|
register: user_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: user_check.ansible_facts.getent_passwd[check_user] is not defined
|
||||||
|
|
||||||
|
- name: Add user to group (non-destructively)
|
||||||
|
user:
|
||||||
|
name: "{{ check_user }}"
|
||||||
|
groups: "{{ check_group }}"
|
||||||
|
append: true
|
24
playbooks/check-reboot-needed.yml
Normal file
24
playbooks/check-reboot-needed.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
- name: Check if reboot is required
|
||||||
|
hosts: all
|
||||||
|
gather_facts: false
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
reboot_machines: false # default, override via --extra-vars
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Check for /var/run/reboot-required
|
||||||
|
stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_flag
|
||||||
|
|
||||||
|
- name: Display reboot status
|
||||||
|
debug:
|
||||||
|
msg: "{{ inventory_hostname }} {{ 'REQUIRES' if reboot_flag.stat.exists else 'does NOT require' }} a reboot."
|
||||||
|
|
||||||
|
- name: Reboot if required and reboot_machines flag is true
|
||||||
|
reboot:
|
||||||
|
msg: "Rebooting due to /var/run/reboot-required"
|
||||||
|
pre_reboot_delay: 5
|
||||||
|
when:
|
||||||
|
- reboot_flag.stat.exists
|
||||||
|
- reboot_machines | bool
|
32
playbooks/check-time-sync.yml
Normal file
32
playbooks/check-time-sync.yml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
- name: Quick check of time offset using ntpdate
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
gather_facts: false
|
||||||
|
vars:
|
||||||
|
ntp_check_target: "pool.ntp.org"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: Ensure ntpdate is installed
|
||||||
|
apt:
|
||||||
|
name: ntpdate
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Query time offset from {{ ntp_check_target }}
|
||||||
|
command: "ntpdate -q {{ ntp_check_target }}"
|
||||||
|
register: ntp_offset
|
||||||
|
changed_when: false
|
||||||
|
failed_when: ntp_offset.rc != 0
|
||||||
|
|
||||||
|
- name: Try to extract final offset line
|
||||||
|
set_fact:
|
||||||
|
ntp_offset_summary: "{{ ntp_offset.stdout_lines | select('search', 'adjust time') | list | first | default('No offset line found') }}"
|
||||||
|
|
||||||
|
- name: Show full ntpdate output per host
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
[{{ inventory_hostname }}]
|
||||||
|
Offset summary: {{ ntp_offset_summary }}
|
||||||
|
Raw output:
|
||||||
|
{{ ntp_offset.stdout_lines | join('\n') }}
|
31
playbooks/check-useringroup.yml
Normal file
31
playbooks/check-useringroup.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
- name: Check if user is in specified group
|
||||||
|
hosts: all
|
||||||
|
gather_facts: false
|
||||||
|
become: true
|
||||||
|
|
||||||
|
vars_prompt:
|
||||||
|
- name: check_user
|
||||||
|
prompt: "Enter the username to check"
|
||||||
|
private: no
|
||||||
|
|
||||||
|
- name: check_group
|
||||||
|
prompt: "Enter the group to verify membership"
|
||||||
|
private: no
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Get groups for specified user
|
||||||
|
ansible.builtin.command: "id -nG {{ check_user }}"
|
||||||
|
register: user_groups
|
||||||
|
changed_when: false
|
||||||
|
failed_when: user_groups.rc != 0
|
||||||
|
|
||||||
|
- name: Set fact if user is in group
|
||||||
|
set_fact:
|
||||||
|
user_in_group: "{{ check_group in user_groups.stdout.split() }}"
|
||||||
|
|
||||||
|
- name: Report user group membership
|
||||||
|
debug:
|
||||||
|
msg: >
|
||||||
|
User '{{ check_user }}' {{ 'IS' if user_in_group else 'IS NOT' }}
|
||||||
|
in the '{{ check_group }}' group on {{ inventory_hostname }}.
|
46
playbooks/check_unallocated_disk.yml
Normal file
46
playbooks/check_unallocated_disk.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
- name: Check unallocated disk space
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: Get block device sizes
|
||||||
|
command: lsblk -b -o NAME,SIZE,TYPE -dn
|
||||||
|
register: lsblk_output
|
||||||
|
|
||||||
|
- name: Parse lsblk output into structured facts
|
||||||
|
set_fact:
|
||||||
|
disks: "{{ disks | default({}) | combine({ item.split()[0]: item.split()[1]|int }) }}"
|
||||||
|
loop: "{{ lsblk_output.stdout_lines }}"
|
||||||
|
when: "'disk' in item"
|
||||||
|
|
||||||
|
- name: Get partition sizes for each disk
|
||||||
|
command: lsblk -b -o NAME,SIZE,TYPE -n
|
||||||
|
register: partition_output
|
||||||
|
|
||||||
|
- name: Initialize disk usage map
|
||||||
|
set_fact:
|
||||||
|
used_space: "{{ used_space | default({}) }}"
|
||||||
|
|
||||||
|
- name: Sum partition sizes under each disk
|
||||||
|
set_fact:
|
||||||
|
used_space: >-
|
||||||
|
{{
|
||||||
|
used_space | combine({
|
||||||
|
(item.0): (used_space[item.0]|default(0)) + (item.1.split()[1]|int)
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
with_nested:
|
||||||
|
- "{{ disks.keys() | list }}"
|
||||||
|
- "{{ partition_output.stdout_lines }}"
|
||||||
|
when: item.1.startswith(item.0) and 'part' in item.1
|
||||||
|
|
||||||
|
- name: Show disk usage summary
|
||||||
|
debug:
|
||||||
|
msg: >-
|
||||||
|
Disk /dev/{{ item.key }}: Total {{ item.value|int // 1024**3 }} GB,
|
||||||
|
Used {{ used_space[item.key]|default(0)|int // 1024**3 }} GB,
|
||||||
|
Unallocated {{ (item.value|int - used_space[item.key]|default(0)|int) // 1024**3 }} GB
|
||||||
|
loop: "{{ disks|dict2items }}"
|
51
playbooks/configure-chrony.yml
Normal file
51
playbooks/configure-chrony.yml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
- name: Configure Chrony NTP Client
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
tasks:
|
||||||
|
- name: Ensure chrony is installed
|
||||||
|
apt:
|
||||||
|
name: chrony
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Disable systemd-timesyncd if present
|
||||||
|
systemd:
|
||||||
|
name: systemd-timesyncd
|
||||||
|
enabled: false
|
||||||
|
state: stopped
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Ensure sources.d directory exists
|
||||||
|
file:
|
||||||
|
path: /etc/chrony/sources.d
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Deploy atomic source
|
||||||
|
copy:
|
||||||
|
src: templates/ntp/atomic.sources
|
||||||
|
dest: /etc/chrony/sources.d/atomic.sources
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Deploy navy source
|
||||||
|
copy:
|
||||||
|
src: templates/ntp/navy.sources
|
||||||
|
dest: /etc/chrony/sources.d/navy.sources
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Deploy fallback pool
|
||||||
|
copy:
|
||||||
|
src: templates/ntp/fallback.sources
|
||||||
|
dest: /etc/chrony/sources.d/fallback.sources
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Reload NTP sources
|
||||||
|
command: chronyc reload sources
|
||||||
|
register: reload_output
|
||||||
|
changed_when: "'Sources reloaded' in reload_output.stdout"
|
35
playbooks/create-user.yml
Normal file
35
playbooks/create-user.yml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
- name: Create a user with SSH access and optional groups
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
vars:
|
||||||
|
username: "{{ username }}"
|
||||||
|
authorized_key: "{{ authorized_key }}"
|
||||||
|
extra_groups: "{{ extra_groups | default('') }}"
|
||||||
|
extra_groups_list: "{{ extra_groups.split(',') | map('trim') | list if extra_groups else [] }}"
|
||||||
|
default_shell: "{{ default_shell | default('/bin/bash') }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Ensure each extra group exists
|
||||||
|
ansible.builtin.group:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: present
|
||||||
|
loop: "{{ extra_groups_list }}"
|
||||||
|
when: extra_groups_list | length > 0
|
||||||
|
|
||||||
|
- name: Ensure user account exists
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ username }}"
|
||||||
|
shell: "{{ default_shell }}"
|
||||||
|
groups: "{{ extra_groups_list }}"
|
||||||
|
append: true
|
||||||
|
create_home: true
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Set authorized SSH key
|
||||||
|
ansible.builtin.authorized_key:
|
||||||
|
user: "{{ username }}"
|
||||||
|
key: "{{ authorized_key }}"
|
||||||
|
state: present
|
43
playbooks/deploy_sshd_config.yml
Normal file
43
playbooks/deploy_sshd_config.yml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy complete SSH server configuration
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Deploy base /etc/ssh/sshd_config file
|
||||||
|
template:
|
||||||
|
src: templates/sshd/sshd_config.j2
|
||||||
|
dest: /etc/ssh/sshd_config
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: Reload SSH
|
||||||
|
|
||||||
|
- name: Deploy hardened global ssh config include
|
||||||
|
template:
|
||||||
|
src: templates/sshd/00-global.conf.j2
|
||||||
|
dest: /etc/ssh/sshd_config.d/00-global.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: Reload SSH
|
||||||
|
|
||||||
|
- name: Deploy LAN password bypass config include
|
||||||
|
template:
|
||||||
|
src: templates/sshd/99-lan-bypass.conf.j2
|
||||||
|
dest: /etc/ssh/sshd_config.d/99-lan-bypass.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: Reload SSH
|
||||||
|
|
||||||
|
- name: Validate sshd configuration syntax
|
||||||
|
command: sshd -t
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- name: Reload SSH
|
||||||
|
service:
|
||||||
|
name: ssh
|
||||||
|
state: reloaded
|
18
playbooks/enable_user_password_reset.yml
Normal file
18
playbooks/enable_user_password_reset.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
- name: Allow user to set their own password
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
vars:
|
||||||
|
username: "{{ username }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Unlock password so user can run passwd
|
||||||
|
ansible.builtin.command: "passwd -d {{ username }}"
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Ensure user is not locked
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ username }}"
|
||||||
|
password_lock: false
|
22
playbooks/install-essential-tools.yml
Normal file
22
playbooks/install-essential-tools.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure essential tools are installed on all hosts
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
|
||||||
|
vars:
|
||||||
|
essential_packages:
|
||||||
|
- curl
|
||||||
|
- git
|
||||||
|
- jq
|
||||||
|
- htop
|
||||||
|
- unzip
|
||||||
|
- ca-certificates
|
||||||
|
- net-tools
|
||||||
|
- acl
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Install common tools
|
||||||
|
apt:
|
||||||
|
name: "{{ essential_packages }}"
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
146
playbooks/install-standard-docker.yml
Normal file
146
playbooks/install-standard-docker.yml
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
---
|
||||||
|
- name: Install Docker using official Docker documentation steps and set up /opt/docker and /srv/docker
|
||||||
|
hosts: docker
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
|
||||||
|
vars:
|
||||||
|
docker_keyring_path: /etc/apt/keyrings/docker.asc
|
||||||
|
docker_repo_list_path: /etc/apt/sources.list.d/docker.list
|
||||||
|
docker_acl_path: /opt/docker
|
||||||
|
srv_docker_path: /srv/docker
|
||||||
|
docker_data_user: dockeruser
|
||||||
|
docker_data_group: dockerdata
|
||||||
|
docker_data_uid: 2011
|
||||||
|
docker_data_gid: 2011
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
# --- Prereqs ---
|
||||||
|
- name: Ensure required packages are installed
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- ca-certificates
|
||||||
|
- curl
|
||||||
|
- acl # Required for setfacl
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Ensure keyring directory exists
|
||||||
|
file:
|
||||||
|
path: /etc/apt/keyrings
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Download Docker's official GPG key
|
||||||
|
get_url:
|
||||||
|
url: https://download.docker.com/linux/ubuntu/gpg
|
||||||
|
dest: "{{ docker_keyring_path }}"
|
||||||
|
mode: "0644"
|
||||||
|
register: docker_key_download
|
||||||
|
|
||||||
|
- name: Get native architecture (dpkg --print-architecture)
|
||||||
|
command: dpkg --print-architecture
|
||||||
|
register: dpkg_arch_result
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Add Docker repository to Apt sources
|
||||||
|
copy:
|
||||||
|
dest: "{{ docker_repo_list_path }}"
|
||||||
|
content: |
|
||||||
|
deb [arch={{ dpkg_arch_result.stdout }} signed-by={{ docker_keyring_path }}] https://download.docker.com/linux/ubuntu {{ ansible_lsb.codename }} stable
|
||||||
|
notify: Update apt cache
|
||||||
|
|
||||||
|
- name: Flush handlers to update apt cache before install
|
||||||
|
meta: flush_handlers
|
||||||
|
|
||||||
|
# --- Docker Install ---
|
||||||
|
- name: Install Docker packages
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- docker-ce
|
||||||
|
- docker-ce-cli
|
||||||
|
- containerd.io
|
||||||
|
- docker-buildx-plugin
|
||||||
|
- docker-compose-plugin
|
||||||
|
state: present
|
||||||
|
update_cache: no
|
||||||
|
|
||||||
|
- name: Ensure docker group exists
|
||||||
|
group:
|
||||||
|
name: docker
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Ensure Docker service is enabled and running
|
||||||
|
systemd:
|
||||||
|
name: docker
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
|
||||||
|
# --- ACL & Folder Standardization ---
|
||||||
|
- name: Ensure Docker base folder exists with correct ownership
|
||||||
|
file:
|
||||||
|
path: "{{ docker_acl_path }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: docker
|
||||||
|
mode: "0775"
|
||||||
|
|
||||||
|
- name: Set setgid bit on /opt/docker so group is inherited
|
||||||
|
file:
|
||||||
|
path: "{{ docker_acl_path }}"
|
||||||
|
mode: "2775"
|
||||||
|
|
||||||
|
- name: Check for existing default ACL on Docker folder
|
||||||
|
command: getfacl --access --default {{ docker_acl_path }}
|
||||||
|
register: facl_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Set default ACL for docker group if not already present
|
||||||
|
command: setfacl -d -m g:docker:rwx {{ docker_acl_path }}
|
||||||
|
when: "'group:docker:rwx' not in facl_check.stdout"
|
||||||
|
|
||||||
|
# --- New: Dedicated Docker Data User/Group and /srv/docker Setup ---
|
||||||
|
- name: Create docker data group with fixed GID
|
||||||
|
group:
|
||||||
|
name: "{{ docker_data_group }}"
|
||||||
|
gid: "{{ docker_data_gid }}"
|
||||||
|
state: present
|
||||||
|
system: yes
|
||||||
|
|
||||||
|
- name: Create docker data user with fixed UID and GID
|
||||||
|
user:
|
||||||
|
name: "{{ docker_data_user }}"
|
||||||
|
uid: "{{ docker_data_uid }}"
|
||||||
|
group: "{{ docker_data_group }}"
|
||||||
|
shell: /usr/sbin/nologin
|
||||||
|
create_home: no
|
||||||
|
system: yes
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Ensure /srv/docker exists with correct ownership
|
||||||
|
file:
|
||||||
|
path: "{{ srv_docker_path }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ docker_data_user }}"
|
||||||
|
group: "{{ docker_data_group }}"
|
||||||
|
mode: "0770"
|
||||||
|
|
||||||
|
- name: Set setgid bit on /srv/docker so group is inherited
|
||||||
|
file:
|
||||||
|
path: "{{ srv_docker_path }}"
|
||||||
|
mode: "2770"
|
||||||
|
|
||||||
|
- name: Set default ACL for dockerdata group on /srv/docker
|
||||||
|
ansible.posix.acl:
|
||||||
|
path: "{{ srv_docker_path }}"
|
||||||
|
entity: "{{ docker_data_group }}"
|
||||||
|
etype: group
|
||||||
|
permissions: rwx
|
||||||
|
default: yes
|
||||||
|
state: present
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- name: Update apt cache
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
39
playbooks/ntpdig-check.yml
Normal file
39
playbooks/ntpdig-check.yml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
- name: Check time synchronization using ntpdig (modern method)
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
gather_facts: false
|
||||||
|
vars:
|
||||||
|
ntp_check_target: "pool.ntp.org"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: Remove legacy ntpdate package (if present)
|
||||||
|
apt:
|
||||||
|
name: ntpdate
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Ensure ntpsec-ntpdate is installed (provides ntpdig)
|
||||||
|
apt:
|
||||||
|
name: ntpsec-ntpdate
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Query time offset using ntpdig from {{ ntp_check_target }}
|
||||||
|
command: "ntpdig {{ ntp_check_target }}"
|
||||||
|
register: ntpdig_output
|
||||||
|
changed_when: false
|
||||||
|
failed_when: ntpdig_output.rc != 0
|
||||||
|
|
||||||
|
- name: Parse correct offset and error from ntpdig output
|
||||||
|
set_fact:
|
||||||
|
ntpdig_offset: "{{ ntpdig_output.stdout | regex_search('[+-][0-9]+\\.[0-9]+(?=\\s+\\+/-)', '\\0') | default('N/A') }}"
|
||||||
|
ntpdig_error: "{{ ntpdig_output.stdout | regex_search('\\+/-\\s+([0-9]+\\.[0-9]+)', '\\1') | default('N/A') }}"
|
||||||
|
|
||||||
|
- name: Show parsed ntpdig result
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
[{{ inventory_hostname }}]
|
||||||
|
Offset: {{ ntpdig_offset }} sec
|
||||||
|
Estimated error: ±{{ ntpdig_error }} sec
|
||||||
|
Raw output:
|
||||||
|
{{ ntpdig_output.stdout_lines | join('\n') }}
|
9
playbooks/reboot.yml
Normal file
9
playbooks/reboot.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
- name: Reboot system immediately
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
tasks:
|
||||||
|
- name: Reboot the machine
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
msg: "Rebooting"
|
||||||
|
reboot_timeout: 600
|
2
playbooks/requirements.yml
Normal file
2
playbooks/requirements.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Empty role list
|
||||||
|
roles: []
|
1
playbooks/templates/ntp/atomic.sources
Normal file
1
playbooks/templates/ntp/atomic.sources
Normal file
@@ -0,0 +1 @@
|
|||||||
|
server atomicmidnight.internal.purpleraft.com iburst prefer
|
3
playbooks/templates/ntp/fallback.sources
Normal file
3
playbooks/templates/ntp/fallback.sources
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pool 0.pool.ntp.org iburst
|
||||||
|
pool 1.pool.ntp.org iburst
|
||||||
|
pool 2.pool.ntp.org iburst
|
2
playbooks/templates/ntp/navy.sources
Normal file
2
playbooks/templates/ntp/navy.sources
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
server tick.usno.navy.mil iburst prefer
|
||||||
|
server tock.usno.navy.mil iburst
|
25
playbooks/templates/sshd/00-global.conf.j2
Normal file
25
playbooks/templates/sshd/00-global.conf.j2
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
Port 22
|
||||||
|
AddressFamily inet
|
||||||
|
PermitRootLogin no
|
||||||
|
|
||||||
|
PasswordAuthentication no
|
||||||
|
KbdInteractiveAuthentication no
|
||||||
|
ChallengeResponseAuthentication no
|
||||||
|
PermitEmptyPasswords no
|
||||||
|
|
||||||
|
UsePAM yes
|
||||||
|
AllowGroups {{ ssh_access_group | default('sshusers') }}
|
||||||
|
|
||||||
|
PubkeyAuthentication yes
|
||||||
|
AuthorizedKeysFile .ssh/authorized_keys
|
||||||
|
|
||||||
|
X11Forwarding no
|
||||||
|
PrintMotd no
|
||||||
|
PrintLastLog yes
|
||||||
|
|
||||||
|
LoginGraceTime 30s
|
||||||
|
MaxAuthTries 3
|
||||||
|
MaxSessions 2
|
||||||
|
|
||||||
|
AcceptEnv LANG LC_*
|
||||||
|
Subsystem sftp /usr/lib/openssh/sftp-server
|
11
playbooks/templates/sshd/99-lan-bypass.conf.j2
Normal file
11
playbooks/templates/sshd/99-lan-bypass.conf.j2
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Match Address 10.0.0.0/8
|
||||||
|
PasswordAuthentication yes
|
||||||
|
|
||||||
|
Match Address 192.168.0.0/16
|
||||||
|
PasswordAuthentication yes
|
||||||
|
|
||||||
|
Match Address 206.202.209.9/32
|
||||||
|
PasswordAuthentication yes
|
||||||
|
|
||||||
|
Match Address 100.64.0.0/10
|
||||||
|
PasswordAuthentication yes
|
4
playbooks/templates/sshd/sshd_config.j2
Normal file
4
playbooks/templates/sshd/sshd_config.j2
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Base sshd_config — managed by Ansible
|
||||||
|
# Delegates all settings to config fragments
|
||||||
|
|
||||||
|
Include /etc/ssh/sshd_config.d/*.conf
|
13
playbooks/test.yml
Normal file
13
playbooks/test.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
- name: Semaphore connection test
|
||||||
|
hosts: all
|
||||||
|
gather_facts: false
|
||||||
|
become: true
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Print the hostname
|
||||||
|
command: hostname
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Show result
|
||||||
|
debug:
|
||||||
|
msg: "Connected to {{ inventory_hostname }} (hostname: {{ result.stdout }})"
|
13
playbooks/update-upgrade.yml
Normal file
13
playbooks/update-upgrade.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
- name: Update APT packages
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
tasks:
|
||||||
|
- name: Update package cache
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Upgrade packages
|
||||||
|
apt:
|
||||||
|
upgrade: safe
|
||||||
|
autoremove: yes
|
||||||
|
autoclean: yes
|
Reference in New Issue
Block a user