feat: initial commit
This commit is contained in:
commit
072a1ed764
36 changed files with 1089 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*.retry
|
||||
.ansible/
|
53
README.md
Normal file
53
README.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
<h1 align="center">
|
||||
<br>
|
||||
<img src="https://guardianproject.dev/irl/.profile/raw/branch/main/header.png" alt="irl.xyz">
|
||||
<br>
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://docs.ansible.com/">
|
||||
<img alt="Language: Ansible" src="https://img.shields.io/badge/Language-Ansible-CC0001?style=flat-square&label=Language">
|
||||
</a>
|
||||
<a href="https://opensource.org/licenses/BSD-2-Clause">
|
||||
<img alt="Licence: BSD 2-Clause" src="https://img.shields.io/badge/License-BSD%202--Clause-orange?style=flat-square">
|
||||
</a>
|
||||
<img alt="Lifecycle: Experimental" src="https://img.shields.io/badge/Lifecycle-Experimental-339999?style=flat-square">
|
||||
</p>
|
||||
|
||||
## ansible-collection-wip
|
||||
|
||||
This is the home of Ansible roles and playbooks that have been put together for one reason or another, but have not yet
|
||||
been polished for publication. No guarantee is made that anything here will be maintained, however some challenges may
|
||||
have been overcome in producing these so there may be some lessons to learn from the YAML herein.
|
||||
|
||||
Generally roles will be targeting the latest release of Debian GNU/Linux. As new releases are approaching, sometimes
|
||||
I'll jump the gun and start targeting the unreleased next version as it is usually ready for production anyway. The
|
||||
Debian people just like to get everything perfect before they hit the release button.
|
||||
|
||||
### Usage
|
||||
|
||||
Use these as examples, but I would strongly recommend you do not include these directly in your IaC.
|
||||
If something here fits your needs really well, maybe [get in touch](https://irl.xyz/contact/) with me and check if I'm
|
||||
planning to maintain that role or playbook.
|
||||
Sometimes a bit of external motivation is the push I need to get something finished, otherwise you can always
|
||||
[hire me to do it](https://www.sr2.uk/).
|
||||
|
||||
### Licence
|
||||
|
||||
Copyright © 2022-2025 irl.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
7
roles/podman_forgejo/defaults/main.yml
Normal file
7
roles/podman_forgejo/defaults/main.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
podman_forgejo_mariadb_database: forgejo
|
||||
# podman_forgejo_mariadb_password:
|
||||
# podman_forgejo_mariadb_root_password:
|
||||
podman_forgejo_mariadb_user: forgejo
|
||||
podman_forgejo_podman_rootless_user: forge
|
||||
podman_forgejo_web_hostname: "{{ inventory_hostname }}"
|
24
roles/podman_forgejo/handlers/main.yml
Normal file
24
roles/podman_forgejo/handlers/main.yml
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
- name: restart forgejo
|
||||
ansible.builtin.systemd_service:
|
||||
name: forgejo
|
||||
state: restarted
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
|
||||
- name: restart mariadb
|
||||
ansible.builtin.systemd_service:
|
||||
name: forgejo
|
||||
state: restarted
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
|
||||
- name: restart sshd
|
||||
service:
|
||||
name: sshd
|
||||
state: restarted
|
||||
become: true
|
88
roles/podman_forgejo/tasks/main.yml
Normal file
88
roles/podman_forgejo/tasks/main.yml
Normal file
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
- name: setup alternate SSH port
|
||||
lineinfile:
|
||||
dest: "/etc/ssh/sshd_config"
|
||||
regexp: "^Port"
|
||||
line: "Port 2222"
|
||||
notify: restart sshd
|
||||
become: true
|
||||
|
||||
- name: create service configuration directories
|
||||
ansible.builtin.file:
|
||||
path: "/home/{{ podman_forgejo_podman_rootless_user }}/{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
group: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
mode: "0755"
|
||||
become: true
|
||||
with_items:
|
||||
- mysql
|
||||
- forgejo
|
||||
|
||||
- name: install podman quadlet for rootless podman user
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "/home/{{ podman_forgejo_podman_rootless_user }}/.config/containers/systemd/{{ item }}"
|
||||
owner: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
mode: "0400"
|
||||
with_items:
|
||||
- forgejo.container
|
||||
- mariadb.container
|
||||
notify:
|
||||
- "restart {{ item | split('.') | first }}"
|
||||
become: true
|
||||
|
||||
- name: install network quadlets for rootless podman user
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "/home/{{ podman_forgejo_podman_rootless_user }}/.config/containers/systemd/{{ item }}"
|
||||
owner: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
mode: "0400"
|
||||
with_items:
|
||||
- frontend.network
|
||||
- forgejo.network
|
||||
become: true
|
||||
|
||||
- name: verify quadlets are correctly defined
|
||||
ansible.builtin.command: /usr/libexec/podman/quadlet -dryrun -user
|
||||
register: podman_forgejo_quadlet_result
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
become: true
|
||||
become_user: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
|
||||
- name: assert that the quadlet verification succeeded
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- podman_forgejo_quadlet_result.rc == 0
|
||||
fail_msg: "'/usr/libexec/podman/quadlet -dryrun -user' failed! Output withheld to prevent leaking secrets."
|
||||
|
||||
- name: start forgejo and mariadb
|
||||
ansible.builtin.systemd_service:
|
||||
name: "{{ item }}"
|
||||
state: started
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
with_items:
|
||||
- forgejo
|
||||
- mariadb
|
||||
|
||||
- name: set up nginx
|
||||
ansible.builtin.include_role:
|
||||
name: podman_nginx
|
||||
vars:
|
||||
podman_nginx_frontend_network: frontend
|
||||
podman_nginx_podman_rootless_user: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
podman_nginx_primary_hostname: "{{ podman_forgejo_web_hostname }}"
|
||||
|
||||
- name: create nginx configuration file
|
||||
ansible.builtin.template:
|
||||
src: nginx.conf
|
||||
dest: "/home/{{ podman_forgejo_podman_rootless_user }}/nginx/nginx.conf"
|
||||
owner: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
group: "{{ podman_forgejo_podman_rootless_user }}"
|
||||
mode: "0644"
|
||||
become: true
|
||||
notify: restart nginx
|
28
roles/podman_forgejo/templates/forgejo.container
Normal file
28
roles/podman_forgejo/templates/forgejo.container
Normal file
|
@ -0,0 +1,28 @@
|
|||
[Unit]
|
||||
Requires=mariadb.service
|
||||
After=mariadb.service
|
||||
|
||||
[Container]
|
||||
ContainerName=forgejo
|
||||
Environment=USER_UID=1000
|
||||
Environment=USER_GID=1000
|
||||
Environment=FORGEJO__database__DB_TYPE=mysql
|
||||
Environment=FORGEJO__database__HOST=mariadb:3306
|
||||
Environment=FORGEJO__database__NAME={{ podman_forgejo_mariadb_database }}
|
||||
Environment=FORGEJO__database__USER={{ podman_forgejo_mariadb_user }}
|
||||
Environment=FORGEJO__database__PASSWD={{ podman_forgejo_mariadb_password }}
|
||||
Environment=FORGEJO__oauth2_client__ENABLE_AUTO_REGISTRATION=true
|
||||
Environment=FORGEJO__server__LANDING_PAGE=/explore/repos
|
||||
Image=codeberg.org/forgejo/forgejo:11
|
||||
Network=frontend.network
|
||||
Network=forgejo.network
|
||||
PublishPort=22:22
|
||||
Volume=/home/forge/forgejo:/data
|
||||
Volume=/etc/timezone:/etc/timezone:ro
|
||||
Volume=/etc/localtime:/etc/localtime:ro
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
2
roles/podman_forgejo/templates/forgejo.network
Normal file
2
roles/podman_forgejo/templates/forgejo.network
Normal file
|
@ -0,0 +1,2 @@
|
|||
[Network]
|
||||
NetworkName=forgejo
|
2
roles/podman_forgejo/templates/frontend.network
Normal file
2
roles/podman_forgejo/templates/frontend.network
Normal file
|
@ -0,0 +1,2 @@
|
|||
[Network]
|
||||
NetworkName=frontend
|
15
roles/podman_forgejo/templates/mariadb.container
Normal file
15
roles/podman_forgejo/templates/mariadb.container
Normal file
|
@ -0,0 +1,15 @@
|
|||
[Container]
|
||||
ContainerName=mariadb
|
||||
Environment=MARIADB_ROOT_PASSWORD={{ podman_forgejo_mariadb_root_password }}
|
||||
Environment=MARIADB_USER={{ podman_forgejo_mariadb_user }}
|
||||
Environment=MARIADB_PASSWORD={{ podman_forgejo_mariadb_password }}
|
||||
Environment=MARIADB_DATABASE={{ podman_forgejo_mariadb_database }}
|
||||
Image=docker.io/mariadb:11
|
||||
Network=forgejo
|
||||
Volume=/home/{{ podman_forgejo_podman_rootless_user }}/mysql:/var/lib/mysql
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
42
roles/podman_forgejo/templates/nginx.conf
Normal file
42
roles/podman_forgejo/templates/nginx.conf
Normal file
|
@ -0,0 +1,42 @@
|
|||
# {{ ansible_managed }}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_name {{ podman_forgejo_web_hostname }};
|
||||
server_tokens off;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://{{ podman_forgejo_web_hostname }}$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
http2 on;
|
||||
|
||||
server_name {{ podman_forgejo_web_hostname }};
|
||||
server_tokens off;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/{{ podman_forgejo_web_hostname }}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/{{ podman_forgejo_web_hostname }}/privkey.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://forgejo:3000;
|
||||
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
client_max_body_size 512M;
|
||||
}
|
||||
}
|
3
roles/podman_host/defaults/main.yml
Normal file
3
roles/podman_host/defaults/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
podman_host_minimum_unpriv_port: "22"
|
||||
podman_host_rootless_users: ["podman"]
|
69
roles/podman_host/tasks/main.yml
Normal file
69
roles/podman_host/tasks/main.yml
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
- name: set unprivileged port minimum
|
||||
ansible.posix.sysctl:
|
||||
name: net.ipv4.ip_unprivileged_port_start
|
||||
value: "{{ podman_host_minimum_unpriv_port }}"
|
||||
sysctl_set: true
|
||||
sysctl_file: /etc/sysctl.d/zzz-podman-unpriv-port.conf
|
||||
reload: true
|
||||
become: true
|
||||
|
||||
- name: create users for rootless podman
|
||||
ansible.builtin.user:
|
||||
name: "{{ item }}"
|
||||
become: true
|
||||
with_items: "{{ podman_host_rootless_users }}"
|
||||
|
||||
- name: set XDG_RUNTIME_DIR in .profile for rootless users
|
||||
ansible.builtin.lineinfile:
|
||||
path: "/home/{{ item }}/.bashrc"
|
||||
line: "export XDG_RUNTIME_DIR=/run/user/$(id -u)"
|
||||
create: false
|
||||
become: true
|
||||
become_user: "{{ item }}"
|
||||
with_items: "{{ podman_host_rootless_users }}"
|
||||
|
||||
- name: enable linger for rootless users
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- /usr/bin/loginctl
|
||||
- enable-linger
|
||||
- "{{ item }}"
|
||||
creates: "/var/lib/systemd/linger/{{ item }}"
|
||||
become: true
|
||||
with_items: "{{ podman_host_rootless_users }}"
|
||||
|
||||
- name: create /etc/subuid and /etc/subgid
|
||||
ansible.builtin.template:
|
||||
dest: "/etc/{{ item }}"
|
||||
src: subXid.j2
|
||||
with_items:
|
||||
- subuid
|
||||
- subgid
|
||||
become: true
|
||||
|
||||
- name: install podman
|
||||
ansible.builtin.apt:
|
||||
pkg: podman
|
||||
state: latest
|
||||
become: true
|
||||
|
||||
- name: create quadlets directory
|
||||
ansible.builtin.file:
|
||||
path: "/home/{{ item }}/.config/containers/systemd"
|
||||
state: directory
|
||||
owner: "{{ item }}"
|
||||
group: "{{ item }}"
|
||||
mode: "0700"
|
||||
with_items: "{{ podman_host_rootless_users }}"
|
||||
become: true
|
||||
|
||||
- name: enable podman auto update timer for rootless users
|
||||
ansible.builtin.systemd_service:
|
||||
name: podman-auto-update.timer
|
||||
scope: user
|
||||
state: started
|
||||
enabled: true
|
||||
become: true
|
||||
become_user: "{{ item }}"
|
||||
with_items: "{{ podman_host_rootless_users }}"
|
4
roles/podman_host/templates/subXid.j2
Normal file
4
roles/podman_host/templates/subXid.j2
Normal file
|
@ -0,0 +1,4 @@
|
|||
# {{ ansible_managed }}
|
||||
{% for username in podman_host_rootless_users %}
|
||||
{{ username }}:{{ 100000 + ((loop.index - 1) * 65536) }}:65536
|
||||
{% endfor %}
|
17
roles/podman_identity/defaults/main.yml
Normal file
17
roles/podman_identity/defaults/main.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
podman_identity_certbot_testing: false
|
||||
# podman_identity_keycloak_admin_password:
|
||||
podman_identity_keycloak_admin_username: admin
|
||||
podman_identity_keycloak_hostname: "{{ inventory_hostname }}"
|
||||
podman_identity_keycloak_providers:
|
||||
- url: https://github.com/jacekkow/keycloak-protocol-cas/releases/download/26.1.2/keycloak-protocol-cas-26.1.2.jar
|
||||
sha256: de106e8b6b0018a5f121dfa04a14859743e35c5c7ef0abdb01e4a6018d1e2d84
|
||||
- url: https://github.com/sventorben/keycloak-restrict-client-auth/releases/download/v26.0.0/keycloak-restrict-client-auth.jar
|
||||
sha256: 69274e7864f1356f6e14c668787be0c4b8f4d1f4ed28b4e5fa540fa71c8df472
|
||||
# podman_identity_ldap_administrator_password:
|
||||
# podman_identity_ldap_directory_manager_password:
|
||||
# podman_identity_ldap_database_suffix_dn:
|
||||
podman_identity_podman_rootless_user: identity
|
||||
podman_identity_postgres_keycloak_database: keycloak
|
||||
# podman_identity_postgres_keycloak_password:
|
||||
podman_identity_postgres_keycloak_username: keycloak
|
27
roles/podman_identity/handlers/main.yml
Normal file
27
roles/podman_identity/handlers/main.yml
Normal file
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
- name: restart ldap
|
||||
ansible.builtin.systemd_service:
|
||||
name: ldap
|
||||
state: restarted
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ podman_identity_podman_rootless_user }}"
|
||||
|
||||
- name: restart postgres
|
||||
ansible.builtin.systemd_service:
|
||||
name: postgres
|
||||
state: restarted
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ podman_identity_podman_rootless_user }}"
|
||||
|
||||
- name: restart keycloak
|
||||
ansible.builtin.systemd_service:
|
||||
name: keycloak
|
||||
state: restarted
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ podman_identity_podman_rootless_user }}"
|
218
roles/podman_identity/tasks/main.yml
Normal file
218
roles/podman_identity/tasks/main.yml
Normal file
|
@ -0,0 +1,218 @@
|
|||
---
|
||||
# TODO: configure ufw
|
||||
|
||||
- name: create service configuration directories
|
||||
ansible.builtin.file:
|
||||
path: "/home/{{ podman_identity_podman_rootless_user }}/{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ podman_identity_podman_rootless_user }}"
|
||||
group: "{{ podman_identity_podman_rootless_user }}"
|
||||
mode: "0755"
|
||||
become: true
|
||||
with_items:
|
||||
- keycloak
|
||||
- ldap
|
||||
- postgres
|
||||
|
||||
- name: download keycloak providers
|
||||
ansible.builtin.get_url:
|
||||
url: "{{ item.url }}"
|
||||
dest: "/home/{{ podman_identity_podman_rootless_user }}/keycloak/{{ item.url | basename }}"
|
||||
checksum: "sha256:{{ item.sha256 }}"
|
||||
with_items: "{{ podman_identity_keycloak_providers }}"
|
||||
become: true
|
||||
become_user: "{{ podman_identity_podman_rootless_user }}"
|
||||
notify: restart keycloak
|
||||
|
||||
- name: install systemd units for rootless podman user
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "/home/{{ podman_identity_podman_rootless_user }}/.config/containers/systemd/{{ item }}"
|
||||
owner: "{{ podman_identity_podman_rootless_user }}"
|
||||
mode: "0400"
|
||||
with_items:
|
||||
- ldap.container
|
||||
- keycloak.container
|
||||
- postgres.container
|
||||
notify:
|
||||
- "restart {{ item | split('.') | first }}"
|
||||
become: true
|
||||
|
||||
- name: install network quadlets for rootless podman user
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "/home/{{ podman_identity_podman_rootless_user }}/.config/containers/systemd/{{ item }}"
|
||||
owner: "{{ podman_identity_podman_rootless_user }}"
|
||||
mode: "0400"
|
||||
with_items:
|
||||
- frontend.network
|
||||
- ldap.network
|
||||
- keycloak.network
|
||||
become: true
|
||||
|
||||
- name: verify quadlets are correctly defined
|
||||
ansible.builtin.command: /usr/libexec/podman/quadlet -dryrun -user
|
||||
register: podman_identity_quadlet_result
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
become: true
|
||||
become_user: "{{ podman_identity_podman_rootless_user }}"
|
||||
|
||||
- name: assert that the quadlet verification succeeded
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- podman_identity_quadlet_result.rc == 0
|
||||
fail_msg: "'/usr/libexec/podman/quadlet -dryrun -user' failed! Output withheld to prevent leaking secrets."
|
||||
|
||||
- name: start postgres and keycloak
|
||||
ansible.builtin.systemd_service:
|
||||
name: "{{ item }}"
|
||||
state: started
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ podman_identity_podman_rootless_user }}"
|
||||
with_items:
|
||||
- postgres
|
||||
- keycloak
|
||||
|
||||
- name: set up nginx
|
||||
ansible.builtin.import_role:
|
||||
name: podman_nginx
|
||||
vars:
|
||||
podman_nginx_podman_rootless_user: "{{ podman_identity_podman_rootless_user }}"
|
||||
podman_nginx_primary_hostname: "{{ podman_identity_keycloak_hostname }}"
|
||||
podman_nginx_frontend_network: frontend
|
||||
|
||||
- name: start ldap
|
||||
ansible.builtin.systemd_service:
|
||||
name: ldap
|
||||
state: started
|
||||
scope: user
|
||||
become: true
|
||||
become_user: "{{ podman_identity_podman_rootless_user }}"
|
||||
|
||||
- name: create nginx configuration file
|
||||
ansible.builtin.template:
|
||||
src: nginx.conf
|
||||
dest: "/home/{{ podman_identity_podman_rootless_user }}/nginx/nginx.conf"
|
||||
owner: "{{ podman_identity_podman_rootless_user }}"
|
||||
group: "{{ podman_identity_podman_rootless_user }}"
|
||||
mode: "0644"
|
||||
become: true
|
||||
notify: restart nginx
|
||||
|
||||
- name: wait 30 seconds for ldap server to start
|
||||
ansible.builtin.pause:
|
||||
seconds: 30
|
||||
|
||||
- name: create ldap suffix
|
||||
containers.podman.podman_container_exec:
|
||||
name: ldap
|
||||
argv:
|
||||
- dsconf
|
||||
- -v
|
||||
- localhost
|
||||
- backend
|
||||
- create
|
||||
- --suffix
|
||||
- "{{ podman_identity_ldap_database_suffix_dn }}"
|
||||
- --be-name
|
||||
- "{{ podman_identity_ldap_database_backend_name }}"
|
||||
- --create-suffix
|
||||
become: true
|
||||
become_user: "{{ podman_identity_podman_rootless_user }}"
|
||||
register: podman_identity_create_suffix
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
tags:
|
||||
- ldap
|
||||
|
||||
- name: create suffix result (only when changed)
|
||||
debug:
|
||||
msg: "Suffix was created"
|
||||
when: not podman_identity_create_suffix.failed
|
||||
changed_when: not podman_identity_create_suffix.failed
|
||||
|
||||
- name: ldap organisational units
|
||||
community.general.ldap_entry:
|
||||
dn: "ou={{ item }},{{ podman_identity_ldap_database_suffix_dn }}"
|
||||
objectClass:
|
||||
- top
|
||||
- organizationalUnit
|
||||
server_uri: ldaps://{{ inventory_hostname }}/
|
||||
bind_dn: "cn=Directory Manager"
|
||||
bind_pw: "{{ podman_identity_ldap_directory_manager_password }}"
|
||||
delegate_to: localhost
|
||||
with_items:
|
||||
- Administrators
|
||||
- People
|
||||
- Groups
|
||||
environment:
|
||||
- LDAPTLS_REQCERT: "{% if podman_identity_certbot_testing %}never{% else %}always{% endif %}"
|
||||
tags: ldap
|
||||
|
||||
- name: enable memberOf plugin
|
||||
containers.podman.podman_container_exec:
|
||||
name: ldap
|
||||
argv:
|
||||
- dsconf
|
||||
- -v
|
||||
- localhost
|
||||
- -D "cn=Directory Manager"
|
||||
- plugin
|
||||
- memberof
|
||||
- enable
|
||||
become: true
|
||||
become_user: "{{ podman_identity_podman_rootless_user }}"
|
||||
tags:
|
||||
- ldap
|
||||
|
||||
- name: disable anonymous bind
|
||||
containers.podman.podman_container_exec:
|
||||
name: ldap
|
||||
argv:
|
||||
- dsconf
|
||||
- -v
|
||||
- localhost
|
||||
- -D "cn=Directory Manager"
|
||||
- config
|
||||
- replace
|
||||
- nsslapd-allow-anonymous-access=off
|
||||
become: true
|
||||
become_user: "{{ podman_identity_podman_rootless_user }}"
|
||||
tags:
|
||||
- ldap
|
||||
|
||||
- name: ldap read-only administrator
|
||||
community.general.ldap_entry:
|
||||
dn: "uid=admin,ou=Administrators,{{ podman_identity_ldap_database_suffix_dn }}"
|
||||
objectClass:
|
||||
- top
|
||||
- person
|
||||
- organizationalPerson
|
||||
- inetOrgPerson
|
||||
attributes:
|
||||
cn: admin
|
||||
sn: admin
|
||||
userPassword: "{{ podman_identity_ldap_administrator_password }}"
|
||||
server_uri: ldaps://{{ inventory_hostname }}/
|
||||
bind_dn: "cn=Directory Manager"
|
||||
bind_pw: "{{ podman_identity_ldap_directory_manager_password }}"
|
||||
delegate_to: localhost
|
||||
environment:
|
||||
- LDAPTLS_REQCERT: "{% if podman_identity_certbot_testing %}never{% else %}always{% endif %}"
|
||||
tags: ldap
|
||||
|
||||
- name: ldap access control information
|
||||
community.general.ldap_attrs:
|
||||
dn: "{{ podman_identity_ldap_database_suffix_dn }}"
|
||||
attributes:
|
||||
aci: '(target="ldap:///{{ podman_identity_ldap_database_suffix_dn }}")(targetattr="*") (version 3.0; acl "readonly"; allow (search,read,compare) userdn="ldap:///uid=admin,ou=Administrators,{{ podman_identity_ldap_database_suffix_dn }}";)'
|
||||
server_uri: ldaps://{{ inventory_hostname }}/
|
||||
bind_dn: "cn=Directory Manager"
|
||||
bind_pw: "{{ podman_identity_ldap_directory_manager_password }}"
|
||||
delegate_to: localhost
|
||||
environment:
|
||||
- LDAPTLS_REQCERT: "{% if podman_identity_certbot_testing %}never{% else %}always{% endif %}"
|
||||
tags: ldap
|
5
roles/podman_identity/templates/frontend.network
Normal file
5
roles/podman_identity/templates/frontend.network
Normal file
|
@ -0,0 +1,5 @@
|
|||
[Network]
|
||||
Driver=bridge
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
33
roles/podman_identity/templates/keycloak.container
Normal file
33
roles/podman_identity/templates/keycloak.container
Normal file
|
@ -0,0 +1,33 @@
|
|||
[Unit]
|
||||
Requires=postgres.service
|
||||
After=postgres.service
|
||||
|
||||
[Container]
|
||||
AutoUpdate=registry
|
||||
ContainerName=keycloak
|
||||
Environment=\
|
||||
KC_DB=postgres \
|
||||
KC_DB_PASSWORD={{ podman_identity_postgres_keycloak_password }} \
|
||||
KC_DB_URL=jdbc:postgresql://postgres/{{ podman_identity_postgres_keycloak_database }} \
|
||||
KC_DB_USERNAME={{ podman_identity_postgres_keycloak_username }} \
|
||||
KC_HOSTNAME={{ podman_identity_keycloak_hostname }} \
|
||||
KC_HTTP_ENABLED=true \
|
||||
KC_HTTP_PORT=8080 \
|
||||
KC_PROXY_HEADERS=xforwarded \
|
||||
KC_BOOTSTRAP_ADMIN_USERNAME={{ podman_identity_keycloak_admin_username }} \
|
||||
KC_BOOTSTRAP_ADMIN_PASSWORD={{ podman_identity_keycloak_admin_password }} \
|
||||
PROXY_ADDRESS_FORWARDING=true
|
||||
Exec=start
|
||||
Image=quay.io/keycloak/keycloak:26.1
|
||||
Network=keycloak.network
|
||||
Network=ldap.network
|
||||
Network=frontend.network
|
||||
{% for provider in podman_identity_keycloak_providers %}
|
||||
Volume=/home/{{ podman_identity_podman_rootless_user }}/keycloak/{{ provider.url | basename }}:/opt/keycloak/providers/{{ provider.url | basename }}:ro
|
||||
{% endfor %}
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
5
roles/podman_identity/templates/keycloak.network
Normal file
5
roles/podman_identity/templates/keycloak.network
Normal file
|
@ -0,0 +1,5 @@
|
|||
[Network]
|
||||
Driver=bridge
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
17
roles/podman_identity/templates/ldap.container
Normal file
17
roles/podman_identity/templates/ldap.container
Normal file
|
@ -0,0 +1,17 @@
|
|||
[Container]
|
||||
ContainerName=ldap
|
||||
Environment=DS_DM_PASSWORD={{ podman_identity_ldap_directory_manager_password }}
|
||||
Image=quay.io/389ds/dirsrv:latest
|
||||
Network=ldap.network
|
||||
PublishPort=636:3636/tcp
|
||||
Volume=/home/{{ podman_identity_podman_rootless_user }}/ldap:/data:rw
|
||||
Volume=/home/{{ podman_identity_podman_rootless_user }}/certbot/conf/live/{{ podman_identity_keycloak_hostname }}/privkey.pem:/data/tls/server.key:ro
|
||||
Volume=/home/{{ podman_identity_podman_rootless_user }}/certbot/conf/live/{{ podman_identity_keycloak_hostname }}/cert.pem:/data/tls/server.crt:ro
|
||||
Volume=/home/{{ podman_identity_podman_rootless_user }}/certbot/conf/live/{{ podman_identity_keycloak_hostname }}/chain.pem:/data/tls/ca/chain.crt:ro
|
||||
|
||||
[Service]
|
||||
RuntimeMaxSec=604800
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
5
roles/podman_identity/templates/ldap.network
Normal file
5
roles/podman_identity/templates/ldap.network
Normal file
|
@ -0,0 +1,5 @@
|
|||
[Network]
|
||||
Driver=bridge
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
39
roles/podman_identity/templates/nginx.conf
Normal file
39
roles/podman_identity/templates/nginx.conf
Normal file
|
@ -0,0 +1,39 @@
|
|||
# {{ ansible_managed }}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_name {{ podman_identity_keycloak_hostname }};
|
||||
server_tokens off;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://{{ podman_identity_keycloak_hostname }}$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 default_server ssl;
|
||||
listen [::]:443 ssl;
|
||||
http2 on;
|
||||
|
||||
server_name {{ podman_identity_keycloak_hostname }};
|
||||
server_tokens off;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/{{ podman_identity_keycloak_hostname }}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/{{ podman_identity_keycloak_hostname }}/privkey.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://keycloak:8080/;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Port 443;
|
||||
}
|
||||
}
|
15
roles/podman_identity/templates/postgres.container
Normal file
15
roles/podman_identity/templates/postgres.container
Normal file
|
@ -0,0 +1,15 @@
|
|||
[Container]
|
||||
AutoUpdate=registry
|
||||
ContainerName=postgres
|
||||
Environment=\
|
||||
POSTGRES_DB={{ podman_identity_postgres_keycloak_database }} \
|
||||
POSTGRES_PASSWORD={{ podman_identity_postgres_keycloak_password }} \
|
||||
POSTGRES_USER={{ podman_identity_postgres_keycloak_username }} \
|
||||
POSTGRES_HOST_AUTH_METHOD=scram-sha-256 \
|
||||
POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256
|
||||
Image=docker.io/postgres:17.3
|
||||
Network=keycloak.network
|
||||
Volume=/home/{{ podman_identity_podman_rootless_user }}/postgres:/var/lib/postgresql/data:rw
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
6
roles/podman_nginx/defaults/main.yml
Normal file
6
roles/podman_nginx/defaults/main.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
podman_nginx_additional_hostnames: []
|
||||
podman_nginx_certbot_testing: false
|
||||
# podman_nginx_frontend_network:
|
||||
podman_nginx_podman_rootless_user: nginx
|
||||
# podman_nginx_primary_hostname:
|
18
roles/podman_nginx/handlers/main.yml
Normal file
18
roles/podman_nginx/handlers/main.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
- name: restart certbot-renew
|
||||
ansible.builtin.systemd_service:
|
||||
name: certbot-renew
|
||||
state: started
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ podman_nginx_podman_rootless_user }}"
|
||||
|
||||
- name: restart nginx
|
||||
ansible.builtin.systemd_service:
|
||||
name: nginx
|
||||
state: restarted
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ podman_nginx_podman_rootless_user }}"
|
110
roles/podman_nginx/tasks/main.yml
Normal file
110
roles/podman_nginx/tasks/main.yml
Normal file
|
@ -0,0 +1,110 @@
|
|||
---
|
||||
- name: create service configuration directories
|
||||
ansible.builtin.file:
|
||||
path: "/home/{{ podman_nginx_podman_rootless_user }}/{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ podman_nginx_podman_rootless_user }}"
|
||||
group: "{{ podman_nginx_podman_rootless_user }}"
|
||||
mode: "0755"
|
||||
become: true
|
||||
with_items:
|
||||
- .config/systemd/user
|
||||
- certbot/conf
|
||||
- certbot/www
|
||||
- nginx
|
||||
|
||||
- name: install podman quadlet for rootless podman user
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "/home/{{ podman_nginx_podman_rootless_user }}/.config/containers/systemd/{{ item }}"
|
||||
owner: "{{ podman_nginx_podman_rootless_user }}"
|
||||
mode: "0400"
|
||||
with_items:
|
||||
- certbot-renew.container
|
||||
- nginx.container
|
||||
notify:
|
||||
- "restart {{ item | split('.') | first }}"
|
||||
become: true
|
||||
|
||||
- name: install certbot renewal timer for rootless podman user
|
||||
ansible.builtin.template:
|
||||
src: "certbot-renew.timer"
|
||||
dest: "/home/{{ podman_nginx_podman_rootless_user }}/.config/systemd/user/certbot-renew.timer"
|
||||
owner: "{{ podman_nginx_podman_rootless_user }}"
|
||||
mode: "0400"
|
||||
become: true
|
||||
|
||||
- name: verify quadlets are correctly defined
|
||||
ansible.builtin.command: /usr/libexec/podman/quadlet -dryrun -user
|
||||
register: podman_nginx_quadlet_result
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
become: true
|
||||
become_user: "{{ podman_nginx_podman_rootless_user }}"
|
||||
|
||||
- name: check if certificate exists
|
||||
stat:
|
||||
path: "/home/{{ podman_nginx_podman_rootless_user }}/certbot/conf/live/{{ podman_nginx_primary_hostname }}/fullchain.pem"
|
||||
register: podman_nginx_cert_stat
|
||||
become: yes
|
||||
become_user: "{{ podman_nginx_podman_rootless_user }}"
|
||||
|
||||
- name: create temporary nginx configuration (no https)
|
||||
ansible.builtin.template:
|
||||
src: nginx.conf
|
||||
dest: "/home/{{ podman_nginx_podman_rootless_user }}/nginx/nginx.conf"
|
||||
owner: "{{ podman_nginx_podman_rootless_user }}"
|
||||
group: "{{ podman_nginx_podman_rootless_user }}"
|
||||
mode: "0644"
|
||||
become: true
|
||||
when: podman_nginx_cert_stat.stat.exists == false
|
||||
|
||||
- name: start nginx
|
||||
ansible.builtin.systemd_service:
|
||||
name: nginx
|
||||
state: started
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ podman_nginx_podman_rootless_user }}"
|
||||
|
||||
- name: run certbot container to create certificate
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
podman run --name certbot-generate
|
||||
--rm
|
||||
--volume /home/{{ podman_nginx_podman_rootless_user }}/certbot/www:/var/www/certbot:rw
|
||||
--volume /home/{{ podman_nginx_podman_rootless_user }}/certbot/conf:/etc/letsencrypt:rw
|
||||
docker.io/certbot/certbot:latest
|
||||
certonly
|
||||
--register-unsafely-without-email
|
||||
--agree-tos
|
||||
--webroot
|
||||
--webroot-path /var/www/certbot/
|
||||
-d "{{ podman_nginx_primary_hostname }}"
|
||||
{% for hostname in podman_nginx_additional_hostnames %} -d "{{ hostname }}"{% endfor %}
|
||||
{% if podman_nginx_certbot_testing %} --test-cert{% endif %}
|
||||
when: podman_nginx_cert_stat.stat.exists == false
|
||||
become: yes
|
||||
become_user: "{{ podman_nginx_podman_rootless_user }}"
|
||||
|
||||
- name: check if certificate exists
|
||||
stat:
|
||||
path: "/home/{{ podman_nginx_podman_rootless_user }}/certbot/conf/live/{{ podman_nginx_primary_hostname }}/fullchain.pem"
|
||||
register: podman_nginx_cert_stat
|
||||
become: yes
|
||||
become_user: "{{ podman_nginx_podman_rootless_user }}"
|
||||
|
||||
- name: ensure certificate exists now
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- podman_nginx_cert_stat.stat.exists
|
||||
fail_msg: "Failed to get a Lets Encrypt certificate."
|
||||
|
||||
- name: start certbot renewal timer
|
||||
ansible.builtin.systemd_service:
|
||||
name: "certbot-renew.timer"
|
||||
state: started
|
||||
scope: user
|
||||
become: true
|
||||
become_user: "{{ podman_nginx_podman_rootless_user }}"
|
13
roles/podman_nginx/templates/certbot-renew.container
Normal file
13
roles/podman_nginx/templates/certbot-renew.container
Normal file
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=Run certbot renew
|
||||
|
||||
[Container]
|
||||
AutoUpdate=registry
|
||||
ContainerName=certbot-renew
|
||||
Exec=renew
|
||||
Image=docker.io/certbot/certbot:latest
|
||||
Volume=/home/{{ podman_nginx_podman_rootless_user }}/certbot/www:/var/www/certbot
|
||||
Volume=/home/{{ podman_nginx_podman_rootless_user }}/certbot/conf:/etc/letsencrypt
|
||||
|
||||
[Service]
|
||||
Restart=no
|
9
roles/podman_nginx/templates/certbot-renew.timer
Normal file
9
roles/podman_nginx/templates/certbot-renew.timer
Normal file
|
@ -0,0 +1,9 @@
|
|||
[Unit]
|
||||
Description=Timer for certbot renewals
|
||||
|
||||
[Timer]
|
||||
OnCalendar=daily
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
17
roles/podman_nginx/templates/nginx.conf
Normal file
17
roles/podman_nginx/templates/nginx.conf
Normal file
|
@ -0,0 +1,17 @@
|
|||
# {{ ansible_managed }}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_name {{ podman_nginx_primary_hostname }};
|
||||
server_tokens off;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://{{ podman_nginx_primary_hostname }}$request_uri;
|
||||
}
|
||||
}
|
16
roles/podman_nginx/templates/nginx.container
Normal file
16
roles/podman_nginx/templates/nginx.container
Normal file
|
@ -0,0 +1,16 @@
|
|||
[Container]
|
||||
ContainerName=nginx
|
||||
Image=docker.io/nginx:latest
|
||||
{% if podman_nginx_frontend_network is defined %}Network={{ podman_nginx_frontend_network }}.network{% endif +%}
|
||||
PublishPort=80:80
|
||||
PublishPort=443:443
|
||||
Volume=/home/{{ podman_nginx_podman_rootless_user }}/certbot/www:/var/www/certbot/:ro
|
||||
Volume=/home/{{ podman_nginx_podman_rootless_user }}/certbot/conf/:/etc/letsencrypt/:ro
|
||||
Volume=/home/{{ podman_nginx_podman_rootless_user }}/nginx:/etc/nginx/conf.d/:ro
|
||||
|
||||
[Service]
|
||||
RuntimeMaxSec=604800
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
12
roles/system_baseline/defaults/main.yml
Normal file
12
roles/system_baseline/defaults/main.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
system_baseline_admin_users:
|
||||
- user: irl
|
||||
comment: irl
|
||||
ssh_public_key: "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJpoCJEax0XTNK6qfYfZV60euSwoc0RQ0bwFDQGMWYQnAAAABHNzaDo="
|
||||
system_baseline_admin_user_groups_debian:
|
||||
- adm
|
||||
- staff
|
||||
- sudo
|
||||
- systemd-journal
|
||||
system_baseline_retired_admin_users: []
|
||||
system_baseline_service_users: []
|
6
roles/system_baseline/handlers/main.yml
Normal file
6
roles/system_baseline/handlers/main.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
- name: reload sshd
|
||||
service:
|
||||
name: sshd
|
||||
state: reloaded
|
||||
become: true
|
29
roles/system_baseline/tasks/main.yml
Normal file
29
roles/system_baseline/tasks/main.yml
Normal file
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
- name: upgrade debian packages (apt)
|
||||
ansible.builtin.apt:
|
||||
upgrade: safe
|
||||
cache_valid_time: 3600
|
||||
become: true
|
||||
when: ansible_distribution == 'Debian'
|
||||
|
||||
- name: install system packages (dnf)
|
||||
dnf:
|
||||
name: "*"
|
||||
state: latest
|
||||
update_cache: true
|
||||
become: true
|
||||
when: ansible_distribution == 'AlmaLinux'
|
||||
|
||||
- name: setup users
|
||||
ansible.builtin.include_tasks:
|
||||
file: users.yml
|
||||
|
||||
- name: setup OpenSSH server
|
||||
ansible.builtin.include_tasks:
|
||||
file: sshd.yml
|
||||
|
||||
- name: remove root authorised keys
|
||||
ansible.builtin.file:
|
||||
path: /root/.ssh/authorized_keys
|
||||
state: absent
|
||||
become: true
|
24
roles/system_baseline/tasks/sshd.yml
Normal file
24
roles/system_baseline/tasks/sshd.yml
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
- name: sshd PermitRootLogin=no
|
||||
lineinfile:
|
||||
dest: "/etc/ssh/sshd_config"
|
||||
regexp: "^#?\\w*PermitRootLogin"
|
||||
line: "PermitRootLogin no"
|
||||
state: present
|
||||
become: true
|
||||
notify: "reload sshd"
|
||||
|
||||
- name: sshd PasswordAuthentication=no
|
||||
lineinfile:
|
||||
dest: "/etc/ssh/sshd_config"
|
||||
regexp: "^#?\\w*PasswordAuthentication"
|
||||
line: "PasswordAuthentication no"
|
||||
state: present
|
||||
become: true
|
||||
notify: "reload sshd"
|
||||
|
||||
- name: retrieve ssh host key
|
||||
fetch:
|
||||
src: "/etc/ssh/ssh_host_ed25519_key.pub"
|
||||
dest: "files/ssh_host_keys/{{ inventory_hostname }}_ed25519.pub"
|
||||
flat: yes
|
74
roles/system_baseline/tasks/users.yml
Normal file
74
roles/system_baseline/tasks/users.yml
Normal file
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
- name: create a group for admin users
|
||||
ansible.builtin.group:
|
||||
name: ops
|
||||
state: present
|
||||
become: true
|
||||
|
||||
- name: create admin users
|
||||
ansible.builtin.user:
|
||||
name: "{{ item.user }}"
|
||||
comment: "{{ item.comment | default(item.user) }}"
|
||||
group: ops
|
||||
with_items: "{{ system_baseline_admin_users }}"
|
||||
become: true
|
||||
|
||||
- name: remove retired admin users
|
||||
ansible.builtin.user:
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
with_items: "{{ system_baseline_retired_admin_users }}"
|
||||
become: true
|
||||
|
||||
- name: additional groups for admin users (Debian only)
|
||||
ansible.builtin.user:
|
||||
name: "{{ item.user }}"
|
||||
groups: "{{ system_baseline_admin_user_groups_debian }}"
|
||||
append: true
|
||||
with_items: "{{ system_baseline_admin_users }}"
|
||||
become: true
|
||||
when: ansible_distribution == 'Debian'
|
||||
|
||||
- name: install SSH keys for admin users
|
||||
ansible.posix.authorized_key:
|
||||
user: "{{ item.user }}"
|
||||
state: present
|
||||
key: "{{ item.ssh_public_key }}"
|
||||
exclusive: true
|
||||
with_items: "{{ system_baseline_admin_users }}"
|
||||
become: true
|
||||
|
||||
- name: allow passwordless sudo for sudo group (Debian only)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/sudoers
|
||||
state: present
|
||||
regexp: "^#?\\w*%sudo "
|
||||
line: "%sudo ALL=(ALL) NOPASSWD: ALL"
|
||||
validate: "/usr/sbin/visudo -cf %s"
|
||||
become: true
|
||||
when: ansible_distribution == 'Debian'
|
||||
|
||||
- name: create a group for service users
|
||||
ansible.builtin.group:
|
||||
name: services
|
||||
state: present
|
||||
become: true
|
||||
|
||||
- name: create service users
|
||||
ansible.builtin.user:
|
||||
name: "{{ item.user }}"
|
||||
comment: "{{ item.comment | default(item.user) }}"
|
||||
group: services
|
||||
with_items: "{{ system_baseline_service_users }}"
|
||||
become: true
|
||||
|
||||
- name: enable linger for service users
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- /usr/bin/loginctl
|
||||
- enable-linger
|
||||
- "{{ item.user }}"
|
||||
creates: "/var/lib/systemd/linger/{{ item.user }}"
|
||||
when: "ansible_distribution == 'Debian' and (item.linger is not defined or item.linger)"
|
||||
become: true
|
||||
with_items: "{{ system_baseline_service_users }}"
|
35
roles/vps/tasks/main.yml
Normal file
35
roles/vps/tasks/main.yml
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
# https://support.solusvm.com/hc/en-us/articles/21334950006807-How-to-install-Guest-Tools-manually-inside-a-VM-in-SolusVM-2
|
||||
|
||||
- name: install required packages
|
||||
apt:
|
||||
pkg:
|
||||
- qemu-guest-agent
|
||||
- cloud-init
|
||||
- tuned
|
||||
state: latest
|
||||
cache_valid_time: 3600
|
||||
become: true
|
||||
when: ansible_distribution == 'Debian'
|
||||
|
||||
- name: install required packages
|
||||
dnf:
|
||||
name:
|
||||
- qemu-guest-agent
|
||||
- cloud-init
|
||||
- tuned
|
||||
state: latest
|
||||
update_cache: true
|
||||
become: true
|
||||
when: ansible_distribution == 'AlmaLinux'
|
||||
|
||||
- name: check tuned profile
|
||||
command: tuned-adm active
|
||||
register: vps_tuned_profile
|
||||
become: true
|
||||
changed_when: false
|
||||
|
||||
- name: start tuned profile
|
||||
shell: tuned-adm profile virtual-guest
|
||||
become: true
|
||||
when: "'virtual-guest' not in vps_tuned_profile.stdout"
|
Loading…
Add table
Add a link
Reference in a new issue