From e9a8d5e238b22ed7f1245bd94d129b669c5f617f Mon Sep 17 00:00:00 2001 From: Donien <88634789+Donien@users.noreply.github.com> Date: Thu, 20 Aug 2026 13:49:04 +0200 Subject: [PATCH 1/3] Add Icinga Web module `totp` --- .../fragments/icingaweb2_module_totp.yml | 2 + doc/role-icingaweb2/module-totp.md | 40 ++++++++ roles/icingaweb2/meta/argument_specs.yml | 93 ++++++++++++++++++- roles/icingaweb2/tasks/modules/totp.yml | 61 ++++++++++++ roles/icingaweb2/vars/main.yml | 1 + 5 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/icingaweb2_module_totp.yml create mode 100644 doc/role-icingaweb2/module-totp.md create mode 100644 roles/icingaweb2/tasks/modules/totp.yml diff --git a/changelogs/fragments/icingaweb2_module_totp.yml b/changelogs/fragments/icingaweb2_module_totp.yml new file mode 100644 index 00000000..b3806451 --- /dev/null +++ b/changelogs/fragments/icingaweb2_module_totp.yml @@ -0,0 +1,2 @@ +minor_changes: + - "Add module `Icinga TOTP Web `__ to Icinga Web." diff --git a/doc/role-icingaweb2/module-totp.md b/doc/role-icingaweb2/module-totp.md new file mode 100644 index 00000000..707043a2 --- /dev/null +++ b/doc/role-icingaweb2/module-totp.md @@ -0,0 +1,40 @@ +## Module TOTP + +TOTP module for Icinga Web for use in two-factor authentication. + +## Configuration + +This module needs a database to work properly, so you will want to also add a database resource definition to `icingaweb2_resources`. + +```yaml +icingaweb2_resources: + totp_db: + type: db + db: mysql + host: localhost + dbname: totp + username: totp_username + password: totp_password +``` + +The general module parameter like `enabled` and `source` can be applied here. + +```yaml +icingaweb2_modules: + totp: + enabled: true + source: package + config: + database: + resource: totp_db + settings: + issuer: Icinga Web 2 + leeway: 15 + database: + import_schema: true + host: localhost + type: mysql + name: totp + user: totp_username + password: totp_password +``` diff --git a/roles/icingaweb2/meta/argument_specs.yml b/roles/icingaweb2/meta/argument_specs.yml index 95c76878..9b4f3085 100644 --- a/roles/icingaweb2/meta/argument_specs.yml +++ b/roles/icingaweb2/meta/argument_specs.yml @@ -456,7 +456,7 @@ argument_specs: ### Currently does not do anything. Schema is applied via kickstart (unprivileged user could not apply schema). import_schema: description: - - Whether the Director's database schema should be initially imported initially. + - Whether the Director's database schema should be imported initially. type: bool required: false run_kickstart: @@ -979,3 +979,94 @@ argument_specs: - "Example: C(icingaweb2_modules.vspheredb.config: { db: { resource: vspheredb_db } })" type: dict required: false + totp: + description: + - This configures the L(Icinga TOTP Web module, https://icinga.com/docs/icinga-totp/latest/). + type: dict + options: + enabled: *module_enabled + source: *module_source + config: + description: + - Defines the general module settings. + - Each key defines a section of the INI configuration. Each subkey defines an option to that section. + - "Example: C(icingaweb2_modules.totp.config: { database: { resource: totp_db } })" + type: dict + options: + database: + description: + - Defines the C(database) section of the C(config.ini) configuration file. + type: dict + options: + resource: + description: + - Defines the database resource to be used. + type: str + settings: + description: + - Defines the C(settings) section of the C(config.ini) configuration file. + - "Example: C(icingaweb2_modules.totp.config: { settings: { issuer: icingaweb, leeway: 20 } })" + type: dict + database: + description: + - This defines variables necessary to apply the schema to the database. + type: dict + options: + import_schema: + description: + - Whether the database schema should be applied. + type: bool + type: + description: + - The type of database to be used. + type: str + choices: + - mysql + - pgsql + host: + description: + - The database host to be used. + type: str + default: localhost + port: + description: + - The database port to be used. + type: str + name: + description: + - The name of the database to be used. + type: str + default: totp + user: + description: + - The database user to be used. + type: str + default: totp + password: + description: + - The database password to be used. + type: str + ssl_mode: + description: + - Clients attempt to connect using encryption, falling back to an unencrypted connection if an encrypted connection cannot be established. + type: str + ssl_ca: + description: + - Defines the path to the ca certificate for client authentication. + type: str + ssl_cert: + description: + - Defines the path to the certificate for client authentication. + type: str + ssl_key: + description: + - Defines the path to the certificate key for client key authentication. + type: str + ssl_cipher: + description: + - Ciphers for the client authentication. + type: str + ssl_extra_options: + description: + - Extra options for the client authentication. + type: str diff --git a/roles/icingaweb2/tasks/modules/totp.yml b/roles/icingaweb2/tasks/modules/totp.yml new file mode 100644 index 00000000..efcffb88 --- /dev/null +++ b/roles/icingaweb2/tasks/modules/totp.yml @@ -0,0 +1,61 @@ +--- + +- name: Module TOTP | Ensure config directory + ansible.builtin.file: + state: directory + dest: "{{ icingaweb2_modules_config_dir }}/totp" + owner: "{{ icingaweb2_httpd_user }}" + group: "{{ icingaweb2_group }}" + mode: "2770" + +- name: Module TOTP | Manage config files + ansible.builtin.include_tasks: manage_module_config.yml + loop: "{{ _files }}" + loop_control: + loop_var: _file + when: icingaweb2_modules[_module][_file] is defined + vars: + _module: "{{ item.key }}" + _files: + - config + +- name: Module TOTP | Manage Schema + when: icingaweb2_modules[_module]['database']['import_schema'] | default(false) + vars: + _module: "{{ item.key }}" + block: + - name: Module TOTP | Prepare _db information + ansible.builtin.set_fact: + _db: + host: "{{ icingaweb2_modules[_module]['database']['host'] | default('localhost') }}" + port: "{{ icingaweb2_modules[_module]['database']['port'] | default('3306') }}" + user: "{{ icingaweb2_modules[_module]['database']['user'] | default('totp') }}" + password: "{{ icingaweb2_modules[_module]['database']['password'] | default(omit) }}" + name: "{{ icingaweb2_modules[_module]['database']['name'] | default('totp') }}" + ssl_mode: "{{ icingaweb2_modules[_module]['database']['ssl_mode'] | default(omit) }}" + ssl_ca: "{{ icingaweb2_modules[_module]['database']['ssl_ca'] | default(omit) }}" + ssl_cert: "{{ icingaweb2_modules[_module]['database']['ssl_cert'] | default(omit) }}" + ssl_key: "{{ icingaweb2_modules[_module]['database']['ssl_key'] | default(omit) }}" + ssl_cipher: "{{ icingaweb2_modules[_module]['database']['ssl_cipher'] | default(omit) }}" + ssl_extra_options: "{{ icingaweb2_modules[_module]['database']['ssl_extra_options'] | default(omit) }}" + schema_path_mysql: "/usr/share/icingaweb2/modules/totp/schema/mysql/schema.sql" + schema_path_pgsql: "/usr/share/icingaweb2/modules/totp/schema/pgsql/schema.sql" + select_query: "SELECT * FROM totp_schema" + type: "{{ icingaweb2_modules[_module]['database']['type'] | default(omit) }}" + + - name: Module TOTP | Check if database type is provided + when: icingaweb2_modules[_module]['database']['type'] is not defined + ansible.builtin.fail: + msg: No database type was provided + + - name: Module TOTP | Import MySQL Schema + when: _db.type == 'mysql' + ansible.builtin.include_tasks: ../manage_mysql_imports.yml + + - name: Module TOTP | Import PostgresQL Schema + when: _db.type == 'pgsql' + ansible.builtin.include_tasks: ../manage_pgsql_imports.yml + + - name: Module TOTP | empty _db var + ansible.builtin.set_fact: + _db: {} diff --git a/roles/icingaweb2/vars/main.yml b/roles/icingaweb2/vars/main.yml index f18e6c12..10137dc7 100644 --- a/roles/icingaweb2/vars/main.yml +++ b/roles/icingaweb2/vars/main.yml @@ -20,3 +20,4 @@ icingaweb2_module_packages: perfdatagraphsprometheus: icingaweb2-module-perfdatagraphs-prometheus perfdatagraphselasticsearch: icingaweb2-module-perfdatagraphs-elasticsearch sso: icinga-sso-web + totp: icinga-totp-web From 22e9656960b412af32f299a0d8e4b8cdabb77d8d Mon Sep 17 00:00:00 2001 From: Donien <88634789+Donien@users.noreply.github.com> Date: Fri, 21 Aug 2026 15:38:29 +0200 Subject: [PATCH 2/3] Add hints about `issuer` and `leeway` --- doc/role-icingaweb2/module-totp.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/role-icingaweb2/module-totp.md b/doc/role-icingaweb2/module-totp.md index 707043a2..a2648732 100644 --- a/doc/role-icingaweb2/module-totp.md +++ b/doc/role-icingaweb2/module-totp.md @@ -38,3 +38,6 @@ icingaweb2_modules: user: totp_username password: totp_password ``` + +> The `issuer` is what is presented to users as the name for their account within their TOTP authenticator app. +> The `leeway` is the accepted clock drift in seconds and must be between 0 and 29. From 2e02a4eed680bc7a8db13a955d5bb581afeea767 Mon Sep 17 00:00:00 2001 From: Donien <88634789+Donien@users.noreply.github.com> Date: Fri, 21 Aug 2026 16:06:44 +0200 Subject: [PATCH 3/3] Use same values for examples in argument_specs and doc --- roles/icingaweb2/meta/argument_specs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/icingaweb2/meta/argument_specs.yml b/roles/icingaweb2/meta/argument_specs.yml index 9b4f3085..4924cb39 100644 --- a/roles/icingaweb2/meta/argument_specs.yml +++ b/roles/icingaweb2/meta/argument_specs.yml @@ -1005,7 +1005,7 @@ argument_specs: settings: description: - Defines the C(settings) section of the C(config.ini) configuration file. - - "Example: C(icingaweb2_modules.totp.config: { settings: { issuer: icingaweb, leeway: 20 } })" + - "Example: C(icingaweb2_modules.totp.config: { settings: { issuer: Icinga Web 2, leeway: 15 } })" type: dict database: description: