Compare commits
12
Commits
master
...
6034238bca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6034238bca | ||
|
|
12ab5a96a2 | ||
|
|
ab24414656 | ||
|
|
f690c6cb3c | ||
|
|
a9d09acbbc | ||
|
|
6ede4604e1 | ||
|
|
cef71dcd1b | ||
|
|
f8a5505047 | ||
|
|
0249f34ddf | ||
|
|
e3b60540b0 | ||
|
|
5febb427e6 | ||
|
|
45ccd6a25f |
@@ -1,3 +1,5 @@
|
||||
hosts
|
||||
proxmox.*
|
||||
.vscode
|
||||
inventory
|
||||
.vault_pass
|
||||
+8
-1
@@ -1,3 +1,10 @@
|
||||
[defaults]
|
||||
host_key_checking = False
|
||||
roles_path = ./roles:/etc/ansible/roles
|
||||
roles_path = ./roles:/etc/ansible/roles
|
||||
group_vars = ./group_vars
|
||||
forks = 20
|
||||
strategy = free
|
||||
|
||||
[ssh_connection]
|
||||
ssh_args = -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPersist=1800s
|
||||
pipelining = True
|
||||
@@ -0,0 +1,18 @@
|
||||
- hosts: all
|
||||
become: true
|
||||
remote_user: "{{ user|default('admin') }}"
|
||||
tasks:
|
||||
- name: Verify if system is Debian
|
||||
debug:
|
||||
msg: "This playbook is running on a Debian system."
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
|
||||
- name: Stop playbook if system is not Debian
|
||||
fail:
|
||||
msg: "This playbook only supports Debian."
|
||||
when: ansible_facts['os_family'] != "Debian"
|
||||
|
||||
- name: Include Bootstrap role
|
||||
import_role:
|
||||
name: bootstrap
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
@@ -0,0 +1,34 @@
|
||||
FROM debian:trixie-slim
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=Europe/Berlin
|
||||
ENV ANSIBLE_VERSION=2.20.6
|
||||
ENV PIP_BREAK_SYSTEM_PACKAGES=1
|
||||
|
||||
RUN apt update && apt install -y --no-install-recommends \
|
||||
nano \
|
||||
git \
|
||||
wget \
|
||||
unzip \
|
||||
curl \
|
||||
python3-pip \
|
||||
tzdata \
|
||||
openssh-client \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN mkdir -p /etc/ssh/ssh_config.d \
|
||||
&& printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /etc/ssh/ssh_config.d/99-no-hostkey-check.conf
|
||||
|
||||
RUN pip3 install --no-cache-dir --upgrade \
|
||||
ansible-core~=${ANSIBLE_VERSION}
|
||||
|
||||
RUN mkdir -p /root/.bashrc.d
|
||||
COPY ansible-functs.sh /root/.bashrc.d/ansible-functs.sh
|
||||
RUN chmod +x /root/.bashrc.d/ansible-functs.sh \
|
||||
&& printf '\n[ -f /root/.bashrc.d/ansible-functs.sh ] && . /root/.bashrc.d/ansible-functs.sh\n' >> /root/.bashrc
|
||||
|
||||
COPY requirements.yml /ansible/requirements.yml
|
||||
RUN ansible-galaxy collection install -r /ansible/requirements.yml
|
||||
|
||||
WORKDIR /ansible
|
||||
|
||||
CMD ["ansible-playbook", "--version"]
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
# Useful bashrc functions for ansible in docker
|
||||
|
||||
alias ll='ls -alF'
|
||||
alias la='ls -A'
|
||||
alias l='ls -CF'
|
||||
|
||||
alias ap='ansible-playbook'
|
||||
alias ag='ansible-galaxy'
|
||||
alias av='ansible-vault'
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
collections:
|
||||
- name: ansible.posix
|
||||
version: 2.2.0
|
||||
- name: community.general
|
||||
version: 13.0.1
|
||||
- name: community.docker
|
||||
version: 5.2.0
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
|
||||
defaultimage="ansible:deb13"
|
||||
|
||||
export ANSIBLE_HOST_KEY_CHECKING=False
|
||||
export ANSIBLE_SSH_ARGS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
||||
export ANSIBLE_CONFIG=./ansible.cfg
|
||||
|
||||
# Ermittle den nächsten freien Container-Namen
|
||||
base_name="ansible"
|
||||
network_name="ansible-dualstack"
|
||||
counter=1
|
||||
while docker ps -a --format '{{.Names}}' | grep -q "^${base_name}-${counter}$"; do
|
||||
counter=$((counter + 1))
|
||||
done
|
||||
container_name="${base_name}-${counter}"
|
||||
|
||||
if docker network inspect "$network_name" >/dev/null 2>&1; then
|
||||
network_ipv6_enabled=$(docker network inspect -f '{{.EnableIPv6}}' "$network_name" 2>/dev/null)
|
||||
if [ "$network_ipv6_enabled" != "true" ]; then
|
||||
echo "Docker-Netzwerk '$network_name' existiert bereits ohne IPv6-Unterstuetzung." >&2
|
||||
echo "Bitte Netzwerk entfernen oder einen anderen Netzwerknamen verwenden." >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if ! docker network create --driver bridge --ipv6 "$network_name" >/dev/null; then
|
||||
echo "Docker-Netzwerk '$network_name' mit IPv6 konnte nicht erstellt werden." >&2
|
||||
echo "Pruefe, ob Docker IPv6 fuer benutzerdefinierte Bridge-Netze unterstuetzt." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
docker run --rm -dit \
|
||||
--name "$container_name" \
|
||||
--hostname "$container_name" \
|
||||
--network "$network_name" \
|
||||
-e ANSIBLE_HOST_KEY_CHECKING=False \
|
||||
-e ANSIBLE_SSH_ARGS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' \
|
||||
-e ANSIBLE_CONFIG=./ansible.cfg \
|
||||
-v "$(pwd):/ansible" \
|
||||
-v ansible_ssh_keys:/root/.ssh \
|
||||
-w /ansible \
|
||||
$defaultimage \
|
||||
"/bin/bash"
|
||||
|
||||
docker exec "$container_name" sh -lc "mkdir -p /root/.ssh && chmod 700 /root/.ssh && printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /root/.ssh/config && chmod 600 /root/.ssh/config"
|
||||
|
||||
container_ipv4=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .IPAddress}}{{.IPAddress}}{{end}}{{end}}' "$container_name" 2>/dev/null)
|
||||
container_ipv6=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .GlobalIPv6Address}}{{.GlobalIPv6Address}}{{end}}{{end}}' "$container_name" 2>/dev/null)
|
||||
container_os=$(docker exec "$container_name" sh -c 'grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d "\"" 2>/dev/null')
|
||||
|
||||
echo "-----------------------------------"
|
||||
echo "Container Name : $container_name"
|
||||
echo "Container IPv4 : ${container_ipv4:-n/a}"
|
||||
echo "Container IPv6 : ${container_ipv6:-n/a}"
|
||||
echo "Container OS : ${container_os:-n/a}"
|
||||
echo "-----------------------------------"
|
||||
|
||||
docker attach "$container_name"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
- hosts: all
|
||||
user: admin
|
||||
become: true
|
||||
tasks:
|
||||
- name: Verify if system is Debian
|
||||
debug:
|
||||
msg: "This playbook is running on a Debian system."
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
|
||||
- name: Stop playbook if system is not Debian
|
||||
fail:
|
||||
msg: "This playbook only supports Debian."
|
||||
when: ansible_facts['os_family'] != "Debian"
|
||||
|
||||
- name: Include Docker setup role
|
||||
import_role:
|
||||
name: docker
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
@@ -2,5 +2,6 @@
|
||||
# vars:
|
||||
# good_keys: "{{ lookup('env', 'good_keys') | from_json }}"
|
||||
# bad_keys: "{{ lookup('env', 'bad_keys') | from_json }}"
|
||||
user: admin
|
||||
roles:
|
||||
- role: manage-ssh-keys
|
||||
@@ -0,0 +1,18 @@
|
||||
- hosts: all
|
||||
user: admin
|
||||
become: true
|
||||
tasks:
|
||||
- name: Verify if system is Debian
|
||||
debug:
|
||||
msg: "This playbook is running on a Debian system."
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
|
||||
- name: Stop playbook if system is not Debian
|
||||
fail:
|
||||
msg: "This playbook only supports Debian."
|
||||
when: ansible_facts['os_family'] != "Debian"
|
||||
|
||||
- name: Include monitoring role
|
||||
import_role:
|
||||
name: monitoring
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
@@ -1,17 +1,18 @@
|
||||
- hosts: all
|
||||
user: admin
|
||||
become: true
|
||||
tasks:
|
||||
- name: Verify if system is Debian
|
||||
debug:
|
||||
msg: "This playbook is running on a Debian system."
|
||||
when: ansible_os_family == "Debian"
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
|
||||
- name: Stop playbook if system is not Debian
|
||||
fail:
|
||||
msg: "This playbook only supports Debian."
|
||||
when: ansible_os_family != "Debian"
|
||||
when: ansible_facts['os_family'] != "Debian"
|
||||
|
||||
- name: Include OS update role
|
||||
include_role:
|
||||
name: os-updates
|
||||
when: ansible_os_family == "Debian"
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
# SSH authorized keys for admin user
|
||||
# Format: key and optional comment
|
||||
admin_authorized_keys:
|
||||
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/XwF0Na+YH7lRqGtwEcyIMVGTQZetNDrC9sZ8ofjC5 niklas@Linkman-PC"
|
||||
comment: "Niklas - Linkman-PC"
|
||||
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINPHSP1qvaoJDwMtka6UV9aOw24cKHBOa2Eyx7JBmhEg dennis@DESKTOP-V99ARL9"
|
||||
comment: "Dennis - DESKTOP-V99ARL9"
|
||||
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA+EvtGavPlXfv7b00jSYsXX2+IEsqFWupEs6Rzf5z9q root@ansible"
|
||||
comment: "Generic Ansible Key"
|
||||
|
||||
# Admin user password (hashed with SHA-512)
|
||||
admin_password: "$6$NmIxM3ZbJDsbC1E6$BO8ag1ZyBqbhELjk0ppKV0CLnYXhHDp9oZc.jmkc62N9hjwbXihF1FmvsYgMKKINVcwaE73u2dRO8pnE6yEGH/"
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Restart sshd
|
||||
service:
|
||||
name: "{{ ssh_service_name | default('sshd') }}"
|
||||
state: restarted
|
||||
remote_user: admin
|
||||
|
||||
- name: Reload keyboard layout
|
||||
shell: setupcon
|
||||
ignore_errors: yes
|
||||
remote_user: admin
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
- name: Create .ssh directory for admin user
|
||||
file:
|
||||
path: /home/admin/.ssh
|
||||
state: directory
|
||||
owner: admin
|
||||
group: admin
|
||||
mode: '0700'
|
||||
|
||||
- name: Deploy authorized SSH keys for admin user
|
||||
template:
|
||||
src: authorized_keys.j2
|
||||
dest: /home/admin/.ssh/authorized_keys
|
||||
owner: admin
|
||||
group: admin
|
||||
mode: '0600'
|
||||
when: admin_authorized_keys is defined and admin_authorized_keys | length > 0
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Configure SSH daemon
|
||||
template:
|
||||
src: sshd.conf.j2
|
||||
dest: /etc/ssh/sshd_config
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0600'
|
||||
validate: /usr/sbin/sshd -T -f %s
|
||||
notify: Restart sshd
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
- name: Configure swappiness to reduce swap usage
|
||||
become: yes
|
||||
ansible.posix.sysctl:
|
||||
name: vm.swappiness
|
||||
value: 10
|
||||
state: present
|
||||
reload: yes
|
||||
when: ansible_facts['virtualization_type'] != "lxc"
|
||||
@@ -6,10 +6,20 @@
|
||||
shell: /bin/bash
|
||||
createhome: yes
|
||||
state: present
|
||||
password: "{{ admin_password }}"
|
||||
password_lock: no
|
||||
|
||||
- name: Create sudoers.d directory if not exists
|
||||
file:
|
||||
path: /etc/sudoers.d
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Set sudo privileges for admin user
|
||||
lineinfile:
|
||||
path: /etc/sudoers.d/10-admin
|
||||
line: "admin ALL=(ALL) NOPASSWD:ALL"
|
||||
validate: 'visudo -cf %s'
|
||||
state: present
|
||||
template:
|
||||
src: sudoers-admin.j2
|
||||
dest: /etc/sudoers.d/10-admin
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0440'
|
||||
validate: 'visudo -cf %s'
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
- name: Install basic packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- fastfetch
|
||||
- htop
|
||||
- curl
|
||||
- wget
|
||||
- git
|
||||
- sudo
|
||||
- console-setup
|
||||
- qemu-guest-agent
|
||||
- cron
|
||||
- net-tools
|
||||
- tcpdump
|
||||
- locales-all
|
||||
update_cache: yes
|
||||
install_recommends: no
|
||||
state: present
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Remove openssh-client if ssh package is installed
|
||||
package:
|
||||
name: ssh
|
||||
state: absent
|
||||
|
||||
- name: Install OpenSSH server
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- openssh-server
|
||||
- openssh-client
|
||||
update_cache: yes
|
||||
state: present
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
- name: Install sudo
|
||||
apt:
|
||||
name: sudo
|
||||
state: present
|
||||
become: yes
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
- import_tasks: install-basicpackages.yml
|
||||
|
||||
- import_tasks: create-admin-user.yml
|
||||
|
||||
- import_tasks: set-motd.yml
|
||||
tags: motd
|
||||
|
||||
- import_tasks: set-keyboardlayout.yml
|
||||
|
||||
- import_tasks: install-openssh.yml
|
||||
tags: ssh
|
||||
|
||||
- import_tasks: configure-ssh.yml
|
||||
tags: ssh
|
||||
|
||||
- import_tasks: add-ssh-keys.yml
|
||||
tags: ssh
|
||||
|
||||
- import_tasks: setup-bashrc.yml
|
||||
tags: bashrc
|
||||
|
||||
- import_tasks: configure-sysctl.yml
|
||||
tags: sysctl
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
- name: Set keyboard layout to QWERTZ
|
||||
template:
|
||||
src: keyboard.j2
|
||||
dest: /etc/default/keyboard
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
notify: Reload keyboard layout
|
||||
@@ -0,0 +1,19 @@
|
||||
- name: Set MOTD to display fastfetch on login
|
||||
copy:
|
||||
content: |
|
||||
#!/bin/bash
|
||||
# Managed by Ansible - Do not edit manually
|
||||
if [[ -z "${FASTFETCH_MOTD_SHOWN:-}" && -z "${SUDO_USER:-}" ]]; then
|
||||
fastfetch -s os:kernel:uptime:packages:shell:disk:cpu:memory:localip:colors
|
||||
export FASTFETCH_MOTD_SHOWN=1
|
||||
fi
|
||||
dest: /etc/profile.d/motd.sh
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0755'
|
||||
|
||||
- name: Remove default MOTD file if it exists
|
||||
file:
|
||||
path: /etc/motd
|
||||
state: absent
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
- name: Get all regular users from /etc/passwd (including root)
|
||||
shell: |
|
||||
getent passwd | awk -F: '($3 >= 1000 && $3 < 65534 && $7 !~ /nologin|false/) || $3 == 0 {print $1":"$6}'
|
||||
register: system_users
|
||||
changed_when: false
|
||||
|
||||
- name: Create user list with home directories
|
||||
set_fact:
|
||||
user_list: "{{ system_users.stdout_lines | map('split', ':') | list }}"
|
||||
|
||||
- name: Ensure .bashrc exists for all users
|
||||
file:
|
||||
path: "{{ item[1] }}/.bashrc"
|
||||
state: touch
|
||||
owner: "{{ item[0] }}"
|
||||
mode: '0644'
|
||||
modification_time: preserve
|
||||
access_time: preserve
|
||||
loop: "{{ user_list }}"
|
||||
when: item[1] is defined and item[1] != ""
|
||||
|
||||
- name: Add useful aliases to .bashrc
|
||||
blockinfile:
|
||||
path: "{{ item[1] }}/.bashrc"
|
||||
marker: "# {mark} ANSIBLE MANAGED ALIASES"
|
||||
block: |
|
||||
# Useful Aliases
|
||||
alias ll='ls -la'
|
||||
alias la='ls -A'
|
||||
alias l='ls -CF'
|
||||
alias ..='cd ..'
|
||||
alias ...='cd ../..'
|
||||
alias grep='grep --color=auto'
|
||||
alias fgrep='fgrep --color=auto'
|
||||
alias egrep='egrep --color=auto'
|
||||
|
||||
# Additional useful shortcuts
|
||||
alias df='df -h'
|
||||
alias du='du -h'
|
||||
alias free='free -h'
|
||||
owner: "{{ item[0] }}"
|
||||
mode: '0644'
|
||||
create: no
|
||||
loop: "{{ user_list }}"
|
||||
when: item[1] is defined and item[1] != ""
|
||||
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
# This file is managed by Ansible. Do not edit it manually.
|
||||
{% for key_entry in admin_authorized_keys %}
|
||||
{% if key_entry.comment is defined %}
|
||||
# {{ key_entry.comment }}
|
||||
{% endif %}
|
||||
{{ key_entry.key }}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
# This file is managed by Ansible. Do not edit it manually.
|
||||
XKBMODEL="pc105"
|
||||
XKBLAYOUT="de"
|
||||
XKBVARIANT=""
|
||||
XKBOPTIONS=""
|
||||
|
||||
BACKSPACE="guess"
|
||||
@@ -0,0 +1,42 @@
|
||||
# {{ ansible_managed }}
|
||||
# This file is managed by Ansible. Do not edit it manually.
|
||||
# This is the ssh server system-wide configuration file.
|
||||
# See sshd_config(5) for more information.
|
||||
|
||||
Port 22
|
||||
AddressFamily any
|
||||
ListenAddress 0.0.0.0
|
||||
ListenAddress ::
|
||||
|
||||
# HostKeys
|
||||
HostKey /etc/ssh/ssh_host_ed25519_key
|
||||
HostKey /etc/ssh/ssh_host_rsa_key
|
||||
|
||||
# Authentication
|
||||
PermitRootLogin no
|
||||
PubkeyAuthentication yes
|
||||
PasswordAuthentication no
|
||||
PermitEmptyPasswords no
|
||||
AuthenticationMethods publickey
|
||||
MaxAuthTries 3
|
||||
|
||||
# SFTP
|
||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||
|
||||
# Security
|
||||
X11Forwarding no
|
||||
PermitTunnel no
|
||||
AllowAgentForwarding no
|
||||
AllowTcpForwarding yes
|
||||
PermitOpen any
|
||||
ClientAliveInterval 300
|
||||
ClientAliveCountMax 2
|
||||
Compression no
|
||||
UseDNS no
|
||||
|
||||
# Logging
|
||||
SyslogFacility AUTH
|
||||
LogLevel VERBOSE
|
||||
|
||||
# Accept locale-related environment variables
|
||||
AcceptEnv LANG LC_*
|
||||
@@ -0,0 +1,5 @@
|
||||
# Sudoers configuration for admin user
|
||||
# {{ ansible_managed }}
|
||||
# This file is managed by Ansible. Do not edit it manually.
|
||||
|
||||
admin ALL=(ALL) NOPASSWD:ALL
|
||||
@@ -0,0 +1,8 @@
|
||||
docker_mirror: https://download.docker.com/linux/debian
|
||||
os_version_codename: "{{ ansible_facts['distribution_release'] | lower }}"
|
||||
docker_packages:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
- docker-buildx-plugin
|
||||
- docker-compose-plugin
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
- name: Restart Docker
|
||||
ansible.builtin.systemd:
|
||||
name: docker
|
||||
state: restarted
|
||||
daemon_reload: yes
|
||||
|
||||
- name: Reload Docker
|
||||
ansible.builtin.systemd:
|
||||
name: docker
|
||||
state: reloaded
|
||||
|
||||
- name: Start Docker
|
||||
ansible.builtin.systemd:
|
||||
name: docker
|
||||
state: started
|
||||
enabled: yes
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
- name: Update apt cache
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Install required packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- ca-certificates
|
||||
- curl
|
||||
state: present
|
||||
|
||||
- name: Create keyrings directory
|
||||
ansible.builtin.file:
|
||||
path: /etc/apt/keyrings
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Download Docker GPG key
|
||||
ansible.builtin.get_url:
|
||||
url: "{{ docker_mirror }}/gpg"
|
||||
dest: /etc/apt/keyrings/docker.asc
|
||||
mode: '0644'
|
||||
|
||||
- name: Add Docker repository
|
||||
ansible.builtin.template:
|
||||
src: sources.list.j2
|
||||
dest: /etc/apt/sources.list.d/docker.sources
|
||||
mode: '0644'
|
||||
|
||||
- name: Update apt cache after adding repository
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
|
||||
- name: Install Docker packages
|
||||
ansible.builtin.apt:
|
||||
name: "{{ docker_packages }}"
|
||||
state: present
|
||||
notify: Start Docker
|
||||
@@ -0,0 +1,6 @@
|
||||
- name: Include Docker installation tasks
|
||||
ansible.builtin.include_tasks: install-docker.yml
|
||||
when: docker_check is failed
|
||||
|
||||
- name: Include Docker APT migration tasks
|
||||
ansible.builtin.include_tasks: migrate-apt.yml
|
||||
@@ -0,0 +1,23 @@
|
||||
- name: Remove old Docker APT repo list files (legacy deb format)
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- /etc/apt/sources.list.d/docker.list
|
||||
- /etc/apt/sources.list.d/docker-ce.list
|
||||
- /etc/apt/sources.list.d/download_docker_com_linux_ubuntu.list
|
||||
register: docker_apt_sources_cleanup
|
||||
failed_when: false
|
||||
|
||||
- name: Remove legacy Docker repo entries from /etc/apt/sources.list
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/apt/sources.list
|
||||
regexp: '^deb\s+.*download\.docker\.com/linux/.*$'
|
||||
state: absent
|
||||
register: docker_sources_list_cleanup
|
||||
failed_when: false
|
||||
|
||||
- name: Update apt cache after legacy Docker repo cleanup
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
when: docker_apt_sources_cleanup is changed or docker_sources_list_cleanup is changed
|
||||
@@ -0,0 +1,7 @@
|
||||
# {{ ansible_managed }}
|
||||
# Package sources for Docker for Codename {{ os_version_codename }}. This file is generated by Ansible using the docker role.
|
||||
Types: deb
|
||||
URIs: {{ docker_mirror }}
|
||||
Suites: {{ os_version_codename }}
|
||||
Components: stable
|
||||
Signed-By: /etc/apt/keyrings/docker.asc
|
||||
@@ -1,12 +1,11 @@
|
||||
---
|
||||
ssh_user: "root"
|
||||
authorized_keys_file: >-
|
||||
{{ "/root/.ssh/authorized_keys" if ssh_user == "root" else "/home/{{ ssh_user }}/.ssh/authorized_keys" }}
|
||||
ssh_user: "admin"
|
||||
|
||||
# Liste der erwünschten (Good) Keys
|
||||
good_keys:
|
||||
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/XwF0Na+YH7lRqGtwEcyIMVGTQZetNDrC9sZ8ofjC5 niklas@Linkman-PC"
|
||||
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINPHSP1qvaoJDwMtka6UV9aOw24cKHBOa2Eyx7JBmhEg dennis@DESKTOP-V99ARL9"
|
||||
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA+EvtGavPlXfv7b00jSYsXX2+IEsqFWupEs6Rzf5z9q root@ansible"
|
||||
|
||||
# Liste der unerwünschten (Bad) Keys
|
||||
bad_keys:
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
- name: Füge Good Keys hinzu
|
||||
import_tasks: add-goodkeys.yml
|
||||
when: good_keys
|
||||
when: good_keys.defined and good_keys | length > 0
|
||||
|
||||
- name: Entferne Bad Keys
|
||||
import_tasks: remove-badkeys.yml
|
||||
when: bad_keys
|
||||
when: bad_keys.defined and bad_keys | length > 0
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
- name: Stelle sicher, dass das .ssh-Verzeichnis existiert
|
||||
- name: Prüfe das .ssh-Verzeichnis des eingeloggten Users
|
||||
file:
|
||||
path: "{{ authorized_keys_file | dirname }}"
|
||||
path: "{{ ansible_env.HOME }}/.ssh"
|
||||
state: directory
|
||||
owner: "{{ ssh_user }}"
|
||||
group: "{{ ssh_user }}"
|
||||
owner: "{{ ansible_user_id }}"
|
||||
group: "{{ ansible_user_gid | default(ansible_user_id) }}"
|
||||
mode: '0700'
|
||||
@@ -0,0 +1,15 @@
|
||||
monitoring_zabbix_version: "7.0"
|
||||
monitoring_zabbix_release_package: "zabbix-release_latest_{{ monitoring_zabbix_version }}+debian{{ ansible_distribution_major_version }}_all.deb"
|
||||
monitoring_zabbix_release_url: "https://repo.zabbix.com/zabbix/{{ monitoring_zabbix_version }}/debian/pool/main/z/zabbix-release/{{ monitoring_zabbix_release_package }}"
|
||||
monitoring_zabbix_release_path: "/tmp/{{ monitoring_zabbix_release_package }}"
|
||||
monitoring_zabbix_agent_package: zabbix-agent2
|
||||
monitoring_zabbix_agent_service: zabbix-agent2
|
||||
monitoring_zabbix_config_file: /etc/zabbix/zabbix_agent2.conf
|
||||
monitoring_zabbix_agent_user: zabbix
|
||||
monitoring_zabbix_passive_servers: ["192.168.212.1"]
|
||||
monitoring_zabbix_active_servers: ""
|
||||
monitoring_zabbix_listen_port: 10050
|
||||
monitoring_zabbix_docker_group: docker
|
||||
monitoring_zabbix_docker_socket_path: /var/run/docker.sock
|
||||
monitoring_zabbix_docker_plugin_config_file: /etc/zabbix/zabbix_agent2.d/plugins.d/docker.conf
|
||||
monitoring_zabbix_docker_endpoint: "unix://{{ monitoring_zabbix_docker_socket_path }}"
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
- name: Restart Zabbix Agent
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ monitoring_zabbix_agent_service }}"
|
||||
state: restarted
|
||||
daemon_reload: yes
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
- name: Configure Zabbix agent
|
||||
ansible.builtin.template:
|
||||
src: zabbix_agent2.conf.j2
|
||||
dest: "{{ monitoring_zabbix_config_file }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
notify: Restart Zabbix Agent
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
- name: Gather Docker group entries
|
||||
ansible.builtin.getent:
|
||||
database: group
|
||||
key: "{{ monitoring_zabbix_docker_group }}"
|
||||
failed_when: false
|
||||
|
||||
- name: Check whether Docker socket exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ monitoring_zabbix_docker_socket_path }}"
|
||||
register: monitoring_docker_socket
|
||||
|
||||
- name: Ensure Zabbix agent can access Docker socket
|
||||
ansible.builtin.user:
|
||||
name: "{{ monitoring_zabbix_agent_user }}"
|
||||
groups: "{{ monitoring_zabbix_docker_group }}"
|
||||
append: yes
|
||||
when:
|
||||
- monitoring_docker_socket.stat.exists
|
||||
- monitoring_zabbix_docker_group in (ansible_facts.getent_group | default({}))
|
||||
notify: Restart Zabbix Agent
|
||||
|
||||
- name: Ensure Docker plugin configuration directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ monitoring_zabbix_docker_plugin_config_file | dirname }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0755'
|
||||
when: monitoring_docker_socket.stat.exists
|
||||
|
||||
- name: Configure Docker plugin endpoint
|
||||
ansible.builtin.template:
|
||||
src: docker.conf.j2
|
||||
dest: "{{ monitoring_zabbix_docker_plugin_config_file }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
when: monitoring_docker_socket.stat.exists
|
||||
notify: Restart Zabbix Agent
|
||||
|
||||
- name: Remove Docker plugin configuration when Docker socket is absent
|
||||
ansible.builtin.file:
|
||||
path: "{{ monitoring_zabbix_docker_plugin_config_file }}"
|
||||
state: absent
|
||||
when: not monitoring_docker_socket.stat.exists
|
||||
notify: Restart Zabbix Agent
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Install Zabbix agent package
|
||||
ansible.builtin.apt:
|
||||
name: "{{ monitoring_zabbix_agent_package }}"
|
||||
state: present
|
||||
|
||||
- name: Ensure Zabbix agent service is enabled and started
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ monitoring_zabbix_agent_service }}"
|
||||
state: started
|
||||
enabled: yes
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
- name: Install repository prerequisites
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- ca-certificates
|
||||
state: present
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Download Zabbix release package
|
||||
ansible.builtin.get_url:
|
||||
url: "{{ monitoring_zabbix_release_url }}"
|
||||
dest: "{{ monitoring_zabbix_release_path }}"
|
||||
mode: '0644'
|
||||
|
||||
- name: Install Zabbix release package
|
||||
ansible.builtin.apt:
|
||||
deb: "{{ monitoring_zabbix_release_path }}"
|
||||
|
||||
- name: Update apt cache after Zabbix repository setup
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
@@ -0,0 +1,14 @@
|
||||
- import_tasks: validate.yml
|
||||
tags: monitoring
|
||||
|
||||
- import_tasks: install-repository.yml
|
||||
tags: monitoring
|
||||
|
||||
- import_tasks: install-agent.yml
|
||||
tags: monitoring
|
||||
|
||||
- import_tasks: configure-docker.yml
|
||||
tags: monitoring
|
||||
|
||||
- import_tasks: configure-agent.yml
|
||||
tags: monitoring
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Stop playbook if system is not Debian
|
||||
ansible.builtin.fail:
|
||||
msg: "This role only supports Debian."
|
||||
when: ansible_facts['os_family'] != "Debian"
|
||||
|
||||
- name: Ensure Zabbix passive servers are defined
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- monitoring_zabbix_passive_servers | length > 0
|
||||
fail_msg: "Set monitoring_zabbix_passive_servers to the IPs, CIDRs or DNS names allowed to query the agent."
|
||||
@@ -0,0 +1,2 @@
|
||||
# {{ ansible_managed }}
|
||||
Plugins.Docker.Endpoint={{ monitoring_zabbix_docker_endpoint }}
|
||||
@@ -0,0 +1,11 @@
|
||||
# {{ ansible_managed }}
|
||||
PidFile=/run/zabbix/zabbix_agent2.pid
|
||||
LogFile=/var/log/zabbix/zabbix_agent2.log
|
||||
LogFileSize=0
|
||||
Server={{ monitoring_zabbix_passive_servers | join(',') }}
|
||||
{% if monitoring_zabbix_active_servers | length > 0 %}
|
||||
ServerActive={{ monitoring_zabbix_active_servers | join(',') }}
|
||||
{% endif %}
|
||||
HostnameItem=system.hostname
|
||||
ListenPort={{ monitoring_zabbix_listen_port }}
|
||||
Include=/etc/zabbix/zabbix_agent2.d/*.conf
|
||||
@@ -5,5 +5,9 @@ os_update_mirrors:
|
||||
# Role needs two mirros to use for the sources.list.j2 Template
|
||||
- "http://deb.debian.org/debian" # Enter a main mirror here (not security)
|
||||
- "http://security.debian.org/debian-security" # Enter a security mirror here
|
||||
os_update_major_version: false # Can either be true or false | To toggle if systems need to be upgraded to newer codename
|
||||
os_update_version_codename: "{{ ansible_distribution_release }}" # KEEP UNTOUCHED!! | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on
|
||||
os_update_version_codename: "{{ ansible_distribution_release }}" # KEEP UNTOUCHED!! | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on
|
||||
os_update_debian_codenames:
|
||||
# Only these suites are considered Debian codenames and will be rewritten in sources.list.d
|
||||
- trixie
|
||||
- bookworm
|
||||
- bullseye
|
||||
@@ -8,4 +8,4 @@
|
||||
async: 1
|
||||
poll: 0
|
||||
ignore_errors: true
|
||||
when: reboot_required.stdout == "yes"
|
||||
when: reboot_required == "yes"
|
||||
@@ -3,10 +3,5 @@
|
||||
include_tasks: update_mirrors.yml
|
||||
ignore_errors: true
|
||||
|
||||
- name: Upgrade to new major version if enabled
|
||||
when: os_update_major_version
|
||||
include_tasks: update_major_version.yml
|
||||
ignore_errors: true
|
||||
|
||||
- name: Upgrade all packages
|
||||
include_tasks: upgrade_packages.yml
|
||||
@@ -1,44 +0,0 @@
|
||||
- name: Backup existing sources in /etc/apt
|
||||
copy:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ item }}.bak"
|
||||
remote_src: yes
|
||||
loop: "{{ lookup('ansible.builtin.fileglob', '/etc/apt/sources.list.d/*.list') + ['/etc/apt/sources.list'] }}"
|
||||
when: item | file
|
||||
|
||||
- name: Update sources.list for new major version
|
||||
template:
|
||||
src: sources.list.j2
|
||||
dest: /etc/apt/sources.list
|
||||
vars:
|
||||
os_update_version_codename: "{{ new_version_codename }}" # Variable gets passed by main.yml task
|
||||
|
||||
- name: Update additional repositories in /etc/apt/sources.list.d (deb822 format)
|
||||
replace:
|
||||
path: "{{ item }}"
|
||||
regexp: '^(Suites:.*\s)({{ os_update_version_codename }})(\s|$)'
|
||||
replace: '\1{{ new_version_codename }}\3'
|
||||
loop: "{{ lookup('ansible.builtin.fileglob', '/etc/apt/sources.list.d/*.sources') }}"
|
||||
when: item | file
|
||||
ignore_errors: true
|
||||
|
||||
- name: Update additional repositories in /etc/apt/sources.list.d (old format fallback)
|
||||
lineinfile:
|
||||
path: "{{ item }}"
|
||||
regexp: '^(deb .* )({{ os_update_version_codename }})'
|
||||
replace: '\1{{ new_version_codename }}'
|
||||
loop: "{{ lookup('ansible.builtin.fileglob', '/etc/apt/sources.list.d/*.list') }}"
|
||||
when: item | file
|
||||
ignore_errors: true
|
||||
|
||||
- name: Update apt cache
|
||||
apt:
|
||||
update_cache: yes
|
||||
|
||||
- name: Perform distribution upgrade
|
||||
apt:
|
||||
upgrade: yes
|
||||
allow_unauthenticated: yes
|
||||
notify:
|
||||
- Reboot system
|
||||
- apt cleanup
|
||||
@@ -1,20 +1,66 @@
|
||||
- name: Run last dist upgrade before changing codename
|
||||
apt:
|
||||
update_cache: yes
|
||||
upgrade: dist
|
||||
when: ansible_facts['distribution_release'] != os_update_version_codename
|
||||
|
||||
- name: Backup existing sources.list
|
||||
copy:
|
||||
src: /etc/apt/sources.list
|
||||
dest: /etc/apt/sources.list.bak
|
||||
remote_src: yes
|
||||
force: yes
|
||||
ignore_errors: true
|
||||
when: ansible_facts['distribution_version'] is version('13', '<=') # Only apply under Debian 13 and newer
|
||||
|
||||
- name: Remove existing debian.sources file from LXC image
|
||||
- name: Remove existing sources.list to avoid conflicts with new deb822 format
|
||||
file:
|
||||
path: /etc/apt/sources.list.d/debian.sources
|
||||
path: /etc/apt/sources.list
|
||||
state: absent
|
||||
when: ansible_facts['distribution_version'] is version('13', '>=') # Only apply for Debian 13 and newer
|
||||
|
||||
- name: Update sources.list with new mirrors
|
||||
- name: Update sources.list.d with new mirrors
|
||||
template:
|
||||
src: sources.list-deb822.j2
|
||||
dest: /etc/apt/sources.list.d/debian.sources
|
||||
when: ansible_facts['distribution_version'] is version('13', '>=') # Only apply for Debian 13 and newer
|
||||
register: cache_update_needed
|
||||
|
||||
- name: Update sources.list with new mirrors for older Debian versions
|
||||
template:
|
||||
src: sources.list.j2
|
||||
dest: /etc/apt/sources.list
|
||||
when: ansible_facts['distribution_version'] is version('13', '<') # Only apply for Debian versions older than 13
|
||||
register: cache_update_needed
|
||||
|
||||
- name: Find sources list fragments
|
||||
find:
|
||||
paths: /etc/apt/sources.list.d
|
||||
patterns: "*.list,*.sources"
|
||||
file_type: file
|
||||
register: apt_sources_list_fragments
|
||||
|
||||
- name: Align suite codenames in sources.list.d for .list files
|
||||
replace:
|
||||
path: "{{ item.path }}"
|
||||
backup: yes
|
||||
regexp: '^(deb(?:-src)?\s+(?:\[[^\]]+\]\s+)?\S+\s+)({{ os_update_debian_codenames | join("|") }})(-[^\s]+)?(\s+.+)$'
|
||||
replace: '\1{{ os_update_version_codename }}\3\4'
|
||||
loop: "{{ apt_sources_list_fragments.files }}"
|
||||
when: (item.path | regex_search('\.list$')) is not none
|
||||
register: cache_update_needed
|
||||
|
||||
- name: Align suite codenames in sources.list.d for .sources files
|
||||
replace:
|
||||
path: "{{ item.path }}"
|
||||
backup: yes
|
||||
regexp: '^(Suites:\s+)({{ os_update_debian_codenames | join("|") }})(-[^\s]+)?(.*)$'
|
||||
replace: '\1{{ os_update_version_codename }}\3\4'
|
||||
loop: "{{ apt_sources_list_fragments.files }}"
|
||||
when: (item.path | regex_search('\.sources$')) is not none
|
||||
register: cache_update_needed
|
||||
|
||||
- name: Update apt cache
|
||||
apt:
|
||||
update_cache: yes
|
||||
update_cache: yes
|
||||
when: cache_update_needed is changed
|
||||
@@ -16,12 +16,15 @@
|
||||
echo "{{ latest_kernel.stdout }}" | grep -c $(uname -r)
|
||||
register: kernel_match
|
||||
changed_when: false
|
||||
ignore_errors: true
|
||||
when: ansible_virtualization_type != 'lxc'
|
||||
failed_when: false
|
||||
when: ansible_facts['virtualization_type'] != 'lxc'
|
||||
|
||||
- name: Mark reboot required if a new kernel is installed
|
||||
set_fact:
|
||||
reboot_required: "yes"
|
||||
changed_when: true
|
||||
notify:
|
||||
- Reboot system
|
||||
when:
|
||||
- ansible_virtualization_type != 'lxc'
|
||||
- kernel_match.stdout == "0"
|
||||
- ansible_facts['virtualization_type'] != 'lxc'
|
||||
- (kernel_match.stdout | int) == 0
|
||||
@@ -0,0 +1,26 @@
|
||||
# {{ ansible_managed }}
|
||||
# Package sources for Debian {{ os_update_version_codename }}. This file is generated by Ansible using the os-updates role.
|
||||
# Using deb822 format for sources.list as it is the new standard in Debian 13 and newer. This file is placed in /etc/apt/sources.list.d/debian.sources to avoid conflicts with older sources.list files and to allow coexistence during transition.
|
||||
Types: deb
|
||||
URIs: {{ os_update_mirrors[0] }}
|
||||
Suites: {{ os_update_version_codename }}
|
||||
Components: main contrib non-free non-free-firmware
|
||||
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||
|
||||
Types: deb
|
||||
URIs: {{ os_update_mirrors[0] }}
|
||||
Suites: {{ os_update_version_codename }}-updates
|
||||
Components: main contrib non-free non-free-firmware
|
||||
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||
|
||||
Types: deb
|
||||
URIs: {{ os_update_mirrors[0] }}
|
||||
Suites: {{ os_update_version_codename }}-backports
|
||||
Components: main contrib non-free non-free-firmware
|
||||
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||
|
||||
Types: deb
|
||||
URIs: {{ os_update_mirrors[1] }}
|
||||
Suites: {{ os_update_version_codename }}-security
|
||||
Components: main contrib non-free non-free-firmware
|
||||
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||
@@ -1,20 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
Types: deb
|
||||
URIs: {{ os_update_mirrors[0] }}
|
||||
Suites: {{ os_update_version_codename }}
|
||||
Components: main contrib non-free non-free-firmware
|
||||
# {{ ansible_managed }} | This file is managed by Ansible. Do not edit it manually.
|
||||
# Package sources for Debian {{ os_update_version_codename }}. This file is generated by Ansible using the os-updates role.
|
||||
|
||||
Types: deb
|
||||
URIs: {{ os_update_mirrors[0] }}
|
||||
Suites: {{ os_update_version_codename }}-updates
|
||||
Components: main contrib non-free non-free-firmware
|
||||
deb {{ os_update_mirrors[0] }} {{ os_update_version_codename }} main contrib non-free non-free-firmware
|
||||
deb {{ os_update_mirrors[0] }} {{ os_update_version_codename }}-updates main contrib non-free non-free-firmware
|
||||
deb {{ os_update_mirrors[0] }} {{ os_update_version_codename }}-backports main contrib non-free non-free-firmware
|
||||
|
||||
Types: deb
|
||||
URIs: {{ os_update_mirrors[0] }}
|
||||
Suites: {{ os_update_version_codename }}-backports
|
||||
Components: main contrib non-free non-free-firmware
|
||||
|
||||
Types: deb
|
||||
URIs: {{ os_update_mirrors[1] }}
|
||||
Suites: {{ os_update_version_codename }}-security
|
||||
Components: main contrib non-free non-free-firmware
|
||||
deb {{ os_update_mirrors[1] }} {{ os_update_version_codename }}-security main contrib non-free non-free-firmware
|
||||
@@ -0,0 +1,5 @@
|
||||
export PROXMOX_URL=https://192.168.212.10:8006/
|
||||
export PROXMOX_USERNAME=ansible@pve
|
||||
export PROXMOX_PASSWORD=u0H1GQMsAuSYZJ
|
||||
export PROXMOX_INVALID_CERT=False
|
||||
export EXCLUDE_LIST="docker.*;br-*;veth*"
|
||||
@@ -0,0 +1,9 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
34323331303232653139313063663566323064373330346237653366363965303235376230396534
|
||||
3364383031333064336239653661313066383534626565320a666433333038303938333163363030
|
||||
65623133356566313263616564626166396635343863353065646538343333383066333839666239
|
||||
3739643861393534360a353837636662303065623735373063313937633731636338643631623435
|
||||
65613634316432373837393638636165326231616563353765376533313336373165313436353566
|
||||
65346536316533343966323531333866626162363837653762383265366632323330646665643635
|
||||
62653238353738613937393632336132646364633962646637353331613061363564346234333439
|
||||
63356431373962343737
|
||||
Reference in New Issue
Block a user