fix(homarr): salt column, bcrypt newline, transaction safety
This commit is contained in:
parent
23ea8dafc9
commit
c060d6136a
1 changed files with 78 additions and 141 deletions
|
|
@ -3,7 +3,22 @@
|
||||||
# tasks file for homarr
|
# tasks file for homarr
|
||||||
|
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
# 1. VORBEREITUNG: Pakete und Verzeichnisse VOR Container-Start
|
# 0. VALIDATION
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
- name: Validate encryption key
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- homarr_secret_encryption_key | length == 64
|
||||||
|
- homarr_secret_encryption_key is match('^[a-f0-9]+$')
|
||||||
|
fail_msg: >-
|
||||||
|
homarr_secret_encryption_key must be a 64-character hex string.
|
||||||
|
Generate with: openssl rand -hex 32
|
||||||
|
Provide via OpenBao, Ansible Vault or extra-vars.
|
||||||
|
success_msg: Encryption key validation passed
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# 1. PREPARATION: packages and directories before container start
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
|
|
||||||
- name: Ensure required packages are installed
|
- name: Ensure required packages are installed
|
||||||
|
|
@ -11,7 +26,6 @@
|
||||||
name:
|
name:
|
||||||
- sqlite3
|
- sqlite3
|
||||||
- python3-docker
|
- python3-docker
|
||||||
- python3-bcrypt
|
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Create docker compose directory
|
- name: Create docker compose directory
|
||||||
|
|
@ -37,7 +51,7 @@
|
||||||
register: db_exists
|
register: db_exists
|
||||||
|
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
# 2. CONTAINER STARTEN
|
# 2. START CONTAINER
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
|
|
||||||
- name: Create docker-compose file for homarr
|
- name: Create docker-compose file for homarr
|
||||||
|
|
@ -52,7 +66,7 @@
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
# 3. AUF DATENBANK WARTEN
|
# 3. WAIT FOR DATABASE
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
|
|
||||||
- name: Wait for database to be created by Homarr
|
- name: Wait for database to be created by Homarr
|
||||||
|
|
@ -63,71 +77,69 @@
|
||||||
when: not db_exists.stat.exists
|
when: not db_exists.stat.exists
|
||||||
|
|
||||||
- name: Wait for database schema to be initialized
|
- name: Wait for database schema to be initialized
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.command:
|
||||||
i=0
|
cmd: sqlite3 "{{ homarr_db_dir }}" "SELECT name FROM sqlite_master WHERE type='table' AND name='board';"
|
||||||
while [ $i -lt 30 ]; do
|
|
||||||
if sqlite3 "{{ homarr_db_dir }}" "SELECT name FROM sqlite_master WHERE type='table' AND name='board';" 2>/dev/null | grep -q board; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
sleep 2
|
|
||||||
i=$((i + 1))
|
|
||||||
done
|
|
||||||
exit 1
|
|
||||||
register: schema_check
|
register: schema_check
|
||||||
|
until: schema_check.stdout == "board"
|
||||||
|
retries: 30
|
||||||
|
delay: 2
|
||||||
changed_when: false
|
changed_when: false
|
||||||
when: not db_exists.stat.exists
|
when: not db_exists.stat.exists
|
||||||
|
|
||||||
- name: Ensure python3-bcrypt is installed
|
# =====================================================================
|
||||||
ansible.builtin.package:
|
# 4. GENERATE BCRYPT HASH (on controller, not on target)
|
||||||
name: python3-bcrypt
|
# =====================================================================
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Generate bcrypt hash for admin password
|
- name: Generate bcrypt hash for admin password
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.shell:
|
||||||
python3 -c "
|
cmd: python3 -c "import bcrypt, sys; print(bcrypt.hashpw(sys.stdin.read().encode(), bcrypt.gensalt(rounds=10)).decode())"
|
||||||
import bcrypt
|
stdin: "{{ homarr_admin_password }}"
|
||||||
password = '{{ homarr_admin_password }}'.encode()
|
stdin_add_newline: false
|
||||||
salt = bcrypt.gensalt(rounds=10)
|
delegate_to: localhost
|
||||||
hashed = bcrypt.hashpw(password, salt)
|
become: false
|
||||||
print(salt.decode())
|
register: bcrypt_result
|
||||||
print(hashed.decode())
|
|
||||||
"
|
|
||||||
register: bcrypt_output
|
|
||||||
changed_when: false
|
changed_when: false
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
|
- name: Set bcrypt hash fact
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
homarr_bcrypt_hash: "{{ bcrypt_result.stdout }}"
|
||||||
|
no_log: true
|
||||||
|
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
# 4. DATENBANK SEEDEN (nur wenn Onboarding noch nicht abgeschlossen)
|
# 5. SEED DATABASE (only if local admin user does not exist yet)
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
|
|
||||||
- name: Check if onboarding is already completed
|
- name: Check if local admin user exists
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.command:
|
||||||
sqlite3 "{{ homarr_db_dir }}" "SELECT step FROM onboarding WHERE step='finish';" 2>/dev/null
|
cmd: sqlite3 "{{ homarr_db_dir }}" "SELECT id FROM user WHERE id='user-local-admin';"
|
||||||
register: onboarding_status
|
register: admin_exists
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
||||||
- name: Seed Homarr database
|
- name: Seed Homarr database
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.shell: |
|
||||||
sqlite3 "{{ homarr_db_dir }}" << 'SEEDSQL'
|
sqlite3 "{{ homarr_db_dir }}" << 'SEEDSQL'
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
-- SERVER SETTINGS
|
-- SERVER SETTINGS
|
||||||
INSERT OR REPLACE INTO serverSetting (setting_key, value)
|
INSERT OR REPLACE INTO serverSetting (setting_key, value)
|
||||||
VALUES
|
VALUES
|
||||||
('analytics', '{"json": {"enableGeneral": false, "enableWidgetData": false, "enableIntegrationData": false}}'),
|
('analytics', '{"json": {"enableGeneral": false, "enableWidgetData": false, "enableIntegrationData": false, "enableUserData": false}}'),
|
||||||
('culture', '{"json": {"defaultLocale": "de"}}'),
|
('culture', '{"json": {"defaultLocale": "de"}}'),
|
||||||
('crawling', '{"json": {"crawlingEnabled": false}}'),
|
('crawling', '{"json": {"crawlingEnabled": false}}'),
|
||||||
('board', '{"json": {"defaultBoardId": "board-default"}}');
|
('board', '{"json": {"homeBoardId": "board-default", "mobileHomeBoardId": "board-default", "enableStatusByDefault": true, "forceDisableStatus": false, "defaultBoardId": "board-default"}}');
|
||||||
|
|
||||||
-- ONBOARDING ÜBERSPRINGEN
|
-- SKIP ONBOARDING
|
||||||
UPDATE onboarding SET step = 'finish', previous_step = 'settings';
|
UPDATE onboarding SET step = 'finish', previous_step = 'settings';
|
||||||
|
|
||||||
-- =====================================================================
|
-- =================================================================
|
||||||
-- GRUPPEN (müssen VOR groupMember existieren)
|
-- GROUPS (must exist before groupMember)
|
||||||
-- =====================================================================
|
-- =================================================================
|
||||||
|
|
||||||
-- OIDC-ADMIN GRUPPE
|
-- OIDC admin group
|
||||||
INSERT OR IGNORE INTO "group" (id, name, owner_id, position)
|
INSERT OR IGNORE INTO "group" (id, name, owner_id, position)
|
||||||
VALUES ('group-oidc-admins', '{{ oidc_admin_group | default("homarr-admins") }}', NULL, 0);
|
VALUES ('group-oidc-admins', '{{ homarr_oidc_admin_group }}', NULL, 0);
|
||||||
|
|
||||||
INSERT OR IGNORE INTO groupPermission (group_id, permission)
|
INSERT OR IGNORE INTO groupPermission (group_id, permission)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
@ -137,7 +149,7 @@
|
||||||
('group-oidc-admins', 'integration-create'),
|
('group-oidc-admins', 'integration-create'),
|
||||||
('group-oidc-admins', 'integration-full-access');
|
('group-oidc-admins', 'integration-full-access');
|
||||||
|
|
||||||
-- CREDENTIALS-ADMIN GRUPPE
|
-- Credentials admin group
|
||||||
INSERT OR IGNORE INTO "group" (id, name, owner_id, position)
|
INSERT OR IGNORE INTO "group" (id, name, owner_id, position)
|
||||||
VALUES ('group-credentials-admin', 'credentials-admin', NULL, 1);
|
VALUES ('group-credentials-admin', 'credentials-admin', NULL, 1);
|
||||||
|
|
||||||
|
|
@ -149,31 +161,29 @@
|
||||||
('group-credentials-admin', 'integration-create'),
|
('group-credentials-admin', 'integration-create'),
|
||||||
('group-credentials-admin', 'integration-full-access');
|
('group-credentials-admin', 'integration-full-access');
|
||||||
|
|
||||||
-- =====================================================================
|
-- =================================================================
|
||||||
-- LOKALER ADMIN USER (Passwort wird via CLI gesetzt)
|
-- LOCAL ADMIN USER
|
||||||
-- =====================================================================
|
-- =================================================================
|
||||||
|
|
||||||
INSERT OR IGNORE INTO user (id, name, email, password, salt, email_verified, provider)
|
INSERT OR IGNORE INTO user (id, name, email, password, email_verified, provider)
|
||||||
VALUES (
|
VALUES (
|
||||||
'user-local-admin',
|
'user-local-admin',
|
||||||
'{{ homarr_admin_username | default("admin") }}',
|
'{{ homarr_admin_username }}',
|
||||||
'{{ homarr_admin_email | default("admin@digitalboard.ch") }}',
|
'{{ homarr_admin_email }}',
|
||||||
'{{ bcrypt_output.stdout_lines[1] }}',
|
'{{ homarr_bcrypt_hash }}',
|
||||||
'{{ bcrypt_output.stdout_lines[0] }}',
|
|
||||||
1,
|
1,
|
||||||
'credentials'
|
'credentials'
|
||||||
);
|
);
|
||||||
|
|
||||||
-- ADMIN-USER DEN GRUPPEN ZUWEISEN (Gruppen existieren jetzt)
|
-- Assign admin user to groups
|
||||||
|
|
||||||
INSERT OR IGNORE INTO groupMember (group_id, user_id)
|
INSERT OR IGNORE INTO groupMember (group_id, user_id)
|
||||||
VALUES
|
VALUES
|
||||||
('group-credentials-admin', 'user-local-admin'),
|
('group-credentials-admin', 'user-local-admin'),
|
||||||
('group-oidc-admins', 'user-local-admin');
|
('group-oidc-admins', 'user-local-admin');
|
||||||
|
|
||||||
-- =====================================================================
|
-- =================================================================
|
||||||
-- BOARD
|
-- BOARD
|
||||||
-- =====================================================================
|
-- =================================================================
|
||||||
|
|
||||||
INSERT OR IGNORE INTO board (
|
INSERT OR IGNORE INTO board (
|
||||||
id, name, is_public,
|
id, name, is_public,
|
||||||
|
|
@ -183,8 +193,8 @@
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
'board-default',
|
'board-default',
|
||||||
'{{ default_board_name | default("Dashboard") }}',
|
'{{ homarr_default_board_name }}',
|
||||||
{% if default_board_public | default(true) %}1{% else %}0{% endif %},
|
{% if homarr_default_board_public %}1{% else %}0{% endif %},
|
||||||
'#fa5252',
|
'#fa5252',
|
||||||
'#fd7e14',
|
'#fd7e14',
|
||||||
100,
|
100,
|
||||||
|
|
@ -195,18 +205,18 @@
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
-- LAYOUTS
|
-- Layouts
|
||||||
INSERT OR IGNORE INTO layout (id, name, board_id, column_count, breakpoint)
|
INSERT OR IGNORE INTO layout (id, name, board_id, column_count, breakpoint)
|
||||||
VALUES
|
VALUES
|
||||||
('layout-desktop', 'Desktop', 'board-default', 10, 0),
|
('layout-desktop', 'Desktop', 'board-default', 10, 0),
|
||||||
('layout-tablet', 'Tablet', 'board-default', 6, 768),
|
('layout-tablet', 'Tablet', 'board-default', 6, 768),
|
||||||
('layout-mobile', 'Mobile', 'board-default', 2, 480);
|
('layout-mobile', 'Mobile', 'board-default', 2, 480);
|
||||||
|
|
||||||
-- HOME BOARD FÜR ADMIN SETZEN (Board existiert jetzt)
|
-- Set home board for admin user (board exists now)
|
||||||
UPDATE user SET home_board_id = 'board-default', mobile_home_board_id = 'board-default'
|
UPDATE user SET home_board_id = 'board-default', mobile_home_board_id = 'board-default'
|
||||||
WHERE id = 'user-local-admin';
|
WHERE id = 'user-local-admin';
|
||||||
|
|
||||||
-- SEKTION
|
-- Section
|
||||||
DELETE FROM section_layout WHERE section_id = 'section-apps';
|
DELETE FROM section_layout WHERE section_id = 'section-apps';
|
||||||
DELETE FROM item_layout WHERE section_id = 'section-apps';
|
DELETE FROM item_layout WHERE section_id = 'section-apps';
|
||||||
DELETE FROM section WHERE id = 'section-apps';
|
DELETE FROM section WHERE id = 'section-apps';
|
||||||
|
|
@ -218,7 +228,7 @@
|
||||||
'empty',
|
'empty',
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
'Anwendungen',
|
'Applications',
|
||||||
'{"json": {}}'
|
'{"json": {}}'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -228,15 +238,15 @@
|
||||||
('section-apps', 'layout-tablet', NULL, 0, 0, 6, 4),
|
('section-apps', 'layout-tablet', NULL, 0, 0, 6, 4),
|
||||||
('section-apps', 'layout-mobile', NULL, 0, 0, 2, 6);
|
('section-apps', 'layout-mobile', NULL, 0, 0, 2, 6);
|
||||||
|
|
||||||
-- BOARD-BERECHTIGUNG
|
-- Board permissions
|
||||||
INSERT OR IGNORE INTO boardGroupPermission (board_id, group_id, permission)
|
INSERT OR IGNORE INTO boardGroupPermission (board_id, group_id, permission)
|
||||||
VALUES
|
VALUES
|
||||||
('board-default', 'group-oidc-admins', 'full-access'),
|
('board-default', 'group-oidc-admins', 'full-access'),
|
||||||
('board-default', 'group-credentials-admin', 'full-access');
|
('board-default', 'group-credentials-admin', 'full-access');
|
||||||
|
|
||||||
-- =====================================================================
|
-- =================================================================
|
||||||
-- APPS
|
-- APPS
|
||||||
-- =====================================================================
|
-- =================================================================
|
||||||
|
|
||||||
-- Nextcloud
|
-- Nextcloud
|
||||||
INSERT OR IGNORE INTO app (id, name, description, icon_url, href)
|
INSERT OR IGNORE INTO app (id, name, description, icon_url, href)
|
||||||
|
|
@ -312,85 +322,12 @@
|
||||||
('item-mailman', 'section-apps', 'layout-desktop', 4, 0, 2, 1),
|
('item-mailman', 'section-apps', 'layout-desktop', 4, 0, 2, 1),
|
||||||
('item-mailman', 'section-apps', 'layout-tablet', 4, 0, 2, 1),
|
('item-mailman', 'section-apps', 'layout-tablet', 4, 0, 2, 1),
|
||||||
('item-mailman', 'section-apps', 'layout-mobile', 0, 1, 1, 1);
|
('item-mailman', 'section-apps', 'layout-mobile', 0, 1, 1, 1);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
SEEDSQL
|
SEEDSQL
|
||||||
args:
|
args:
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
register: seed_result
|
register: seed_result
|
||||||
changed_when: seed_result.rc == 0
|
changed_when: seed_result.rc == 0
|
||||||
when: onboarding_status.stdout is not defined or 'finish' not in onboarding_status.stdout
|
when: admin_exists.stdout == ""
|
||||||
|
notify: restart homarr
|
||||||
# =====================================================================
|
|
||||||
# 5. RESTART, HEALTH-CHECK, DANN CLI
|
|
||||||
# =====================================================================
|
|
||||||
|
|
||||||
- name: Restart Homarr to apply database changes
|
|
||||||
ansible.builtin.shell:
|
|
||||||
cmd: docker compose restart
|
|
||||||
chdir: "{{ homarr_docker_compose_dir }}"
|
|
||||||
when: seed_result is changed
|
|
||||||
|
|
||||||
- name: Wait for Homarr to be ready
|
|
||||||
ansible.builtin.shell:
|
|
||||||
cmd: docker compose exec -T {{ homarr_service_name }} wget -qO /dev/null "http://localhost:7575" 2>&1
|
|
||||||
chdir: "{{ homarr_docker_compose_dir }}"
|
|
||||||
retries: 30
|
|
||||||
delay: 5
|
|
||||||
register: homarr_ready
|
|
||||||
until: homarr_ready.rc == 0
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Display completion message
|
|
||||||
ansible.builtin.debug:
|
|
||||||
msg: |
|
|
||||||
============================================================
|
|
||||||
Homarr deployed!
|
|
||||||
URL: {{ homarr_base_url }}
|
|
||||||
Admin-User: {{ homarr_admin_username }}
|
|
||||||
Admin-Passwort: {{ homarr_admin_password }}
|
|
||||||
(Bitte sofort ändern!)
|
|
||||||
============================================================
|
|
||||||
when: not db_exists.stat.exists
|
|
||||||
|
|
||||||
# =====================================================================
|
|
||||||
# 6. ABSCHLUSS
|
|
||||||
# =====================================================================
|
|
||||||
|
|
||||||
- name: Display admin credentials
|
|
||||||
ansible.builtin.debug:
|
|
||||||
msg: |
|
|
||||||
============================================
|
|
||||||
LOKALER ADMIN PASSWORT (bitte sofort ändern!)
|
|
||||||
{{ admin_password_output.stdout }}
|
|
||||||
============================================
|
|
||||||
when:
|
|
||||||
- admin_password_output is defined
|
|
||||||
- admin_password_output.stdout is defined
|
|
||||||
- admin_password_output.stdout | length > 0
|
|
||||||
|
|
||||||
- name: Display completion message
|
|
||||||
ansible.builtin.debug:
|
|
||||||
msg: |
|
|
||||||
============================================================
|
|
||||||
Homarr wurde erfolgreich deployed!
|
|
||||||
============================================================
|
|
||||||
|
|
||||||
URL: {{ homarr_base_url }}
|
|
||||||
|
|
||||||
OIDC Konfiguration:
|
|
||||||
- Issuer: {{ oidc_issuer }}
|
|
||||||
- Client ID: {{ oidc_client_id }}
|
|
||||||
- Admin-Gruppe: {{ oidc_admin_group }}
|
|
||||||
|
|
||||||
Nächste Schritte:
|
|
||||||
1. Stelle sicher, dass in Keycloak die Gruppe "{{ oidc_admin_group }}" existiert
|
|
||||||
2. Füge deinen User zur Gruppe "{{ oidc_admin_group }}" hinzu
|
|
||||||
3. Öffne {{ homarr_base_url }}
|
|
||||||
4. Du solltest automatisch via OIDC eingeloggt werden
|
|
||||||
|
|
||||||
Das Standard-Board "{{ default_board_name }}" wurde erstellt mit:
|
|
||||||
- Nextcloud App
|
|
||||||
- Keycloak App
|
|
||||||
- Mailman App
|
|
||||||
|
|
||||||
Weitere Apps kannst du direkt in der Homarr UI hinzufügen.
|
|
||||||
============================================================
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue