Skip to content
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

* **role:icingaweb2_module_grafana**: Add JWT support
* **role:grafana**: Add JWT support
* Add `playbooks/README.md` documenting all playbooks with their roles in execution order and available skip variables
* **role:apache_httpd**: Add platform-specific behavior section, wsgi example, and document localhost endpoints in README
* **role:apache_httpd**: Add skip variables section to README linking to relevant playbooks
Expand Down
6 changes: 6 additions & 0 deletions roles/grafana/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ grafana__root_url: 'https://monitoring.example.com/grafana'
| `grafana__auth_anonymous_enabled` | Whether to allow anonymous (passwordless) access or not. Possible options: `true` or `false` | `false` |
| `grafana__auth_anonymous_org_name` | The organization name that should be used for unauthenticated users. | `'Main Org.'` |
| `grafana__auth_anonymous_org_role` | The role for unauthenticated users. | `'Viewer'` |
| `grafana__auth_jwt` | Enable JWT-based authentication for Grafana requests. | `false` |
| `grafana__auth_jwt__priv_key_file` | Path to the private key file used to verify JWT signatures for Grafana authentication. | `'/etc/grafana/jwt.key.priv'` |
| `grafana__auth_jwt__pub_key_file` | Path to the public key file used to verify JWT signatures for Grafana authentication. | `'/etc/grafana/jwt.key.pub'` |
| `grafana__bitwarden_collection_id` | Will be used to store the token of the created service accounts to this Bitwarden Collection. Can be obtained from the URL in Bitwarden WebGUI. | `'{{ lfops__bitwarden_collection_id | default() }}'` |
| `grafana__bitwarden_organization_id` | Will be used to store the token of the created service accounts to this Bitwarden Organization. Can be obtained from the URL in Bitwarden WebGUI. | `'{{ lfops__bitwarden_organization_id | default() }}'` |
| `grafana__cookie_samesite` | The [SameSite cookie attribute](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite). Possible options:<br> * disabled<br> * lax<br> * none<br> * strict | `'lax'` |
Expand All @@ -71,6 +74,9 @@ grafana__api_url: 'https://grafana01.example.com/grafana'
grafana__auth_anonymous_enabled: false
grafana__auth_anonymous_org_name: 'Main Org.'
grafana__auth_anonymous_org_role: 'Viewer'
grafana__auth_jwt: false
grafana__auth_jwt__priv_key_file: '/etc/grafana/jwt.key.priv'
grafana__auth_jwt__pub_key_file: '/etc/grafana/jwt.key.pub'
grafana__cookie_samesite: 'lax'
grafana__https_config:
cert_file: '/etc/ssl/ssl-certificate.crt'
Expand Down
4 changes: 4 additions & 0 deletions roles/grafana/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ grafana__api_url: '{{ grafana__root_url }}'
grafana__auth_anonymous_enabled: false
grafana__auth_anonymous_org_name: 'Main Org.'
grafana__auth_anonymous_org_role: 'Viewer'
grafana__auth_jwt: false
grafana__auth_jwt__priv_key_file: '/etc/grafana/jwt.key.priv'
grafana__auth_jwt__pub_key_file: '/etc/grafana/jwt.key.pub'
grafana__bitwarden_collection_id: '{{ lfops__bitwarden_collection_id | default() }}'
grafana__bitwarden_organization_id: '{{ lfops__bitwarden_organization_id | default() }}'
grafana__cookie_samesite: 'lax'
Expand Down Expand Up @@ -58,3 +61,4 @@ grafana__serve_from_sub_path: false
grafana__service_enabled: true
grafana__skip_token_to_bitwarden: false
grafana__validate_certs: true

19 changes: 19 additions & 0 deletions roles/grafana/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,25 @@
when:
- 'grafana__https_config is defined and grafana__https_config | length > 0'

- name: 'generate JWT RSA private key'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only generate if grafana__auth_jwt is true?

community.crypto.openssl_privatekey:
path: '{{ grafana__auth_jwt__priv_key_file }}'
size: 2048
type: 'RSA'
owner: 'root'
group: 'grafana'
mode: 0o644
when: 'grafana__auth_jwt | bool'

- name: 'generate JWT RSA public key'
community.crypto.openssl_publickey:
path: '{{ grafana__auth_jwt__pub_key_file }}'
privatekey_path: '{{ grafana__auth_jwt__priv_key_file }}'
owner: 'root'
group: 'grafana'
mode: 0o644
when: 'grafana__auth_jwt | bool'

- name: 'deploy /etc/grafana/grafana.ini'
ansible.builtin.template:
backup: true
Expand Down
16 changes: 9 additions & 7 deletions roles/grafana/templates/etc/grafana/grafana.ini.j2
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# {{ ansible_managed }}
# 2024031901
# 2026032701

##################### Grafana Configuration Example #####################
#
Expand Down Expand Up @@ -606,16 +606,18 @@ hide_version = true

#################################### Auth JWT ##########################
[auth.jwt]
;enabled = true
;header_name = X-JWT-Assertion
;email_claim = sub
;username_claim = sub
enabled = {{ grafana__auth_jwt | lower }}
header_name = X-JWT-Assertion
email_claim = sub
username_claim = sub
;jwk_set_url = https://foo.bar/.well-known/jwks.json
;jwk_set_file = /path/to/jwks.json
;cache_ttl = 60m
;expected_claims = {"aud": ["foo", "bar"]}
;key_file = /path/to/key/file
;auto_sign_up = false
key_file = {{ grafana__auth_jwt__pub_key_file }}
auto_sign_up = false
url_login = true
skip_org_role_sync = true

#################################### Auth LDAP ##########################
[auth.ldap]
Expand Down
8 changes: 6 additions & 2 deletions roles/icingaweb2_module_grafana/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Additionally, it deploys the the graph configuration for the [Linuxfabrik Monito

This role is tested with the following IcingaWeb2 Grafana Module versions:

* 3.0.1
* 3.1.3


## Mandatory Requirements
Expand Down Expand Up @@ -36,14 +36,16 @@ Example:
```yaml
# mandatory
icingaweb2_module_grafana__monitoring_plugins_version: '1.2.0.11'
icingaweb2_module_grafana__version: 'v3.1.1'
icingaweb2_module_grafana__version: 'v3.1.3'
```


## Optional Role Variables

| Variable | Description | Default Value |
| -------- | ----------- | ------------- |
| `icingaweb2_module_grafana__auth_jwt` | Enable JWT-based authentication for Grafana requests | `'{{ grafana__auth_jwt }}'` |
| `icingaweb2_module_grafana__auth_jwt__priv_key_file` | Path to the private key file used for JWT-based Grafana authentication | `'{{ grafana__auth_jwt__priv_key_file }}'` |
| `icingaweb2_module_grafana__custom_graphs_config` | Multiline string. Custom configuration for the Grafana Graphs, will be deployed to `/etc/icingweb2/modules/grafana/graphs.ini` along with the configuration for the [Linuxfabrik Monitoring Plugins](https://github.com/Linuxfabrik/monitoring-plugins) | `''` |
| `icingaweb2_module_grafana__default_dashboard` | Name of the default Grafana dashboard | `'Default'` |
| `icingaweb2_module_grafana__skip_monitoring_plugins_graphs_config` | Skip the deployment of the graph configuration for [Linuxfabrik Monitoring Plugins](https://github.com/Linuxfabrik/monitoring-plugins). | `false` |
Expand All @@ -53,6 +55,8 @@ icingaweb2_module_grafana__version: 'v3.1.1'
Example:
```yaml
# optional
icingaweb2_module_grafana__auth_jwt: false
icingaweb2_module_grafana__auth_jwt__priv_key_file: '/etc/grafana/jwt.key.priv'
icingaweb2_module_grafana__custom_graphs_config: |-
[icingacli-x509]
dashboard = "Default"
Expand Down
2 changes: 2 additions & 0 deletions roles/icingaweb2_module_grafana/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
icingaweb2_module_grafana__auth_jwt: '{{ grafana__auth_jwt }}'
icingaweb2_module_grafana__auth_jwt__priv_key_file: '{{ grafana__auth_jwt__priv_key_file }}'
icingaweb2_module_grafana__custom_graphs_config: ''
icingaweb2_module_grafana__default_dashboard: 'Default'
icingaweb2_module_grafana__monitoring_plugins_version: '{{ lfops__monitoring_plugins_version | default() }}'
Expand Down
10 changes: 10 additions & 0 deletions roles/icingaweb2_module_grafana/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@
group: 'icingaweb2'
mode: 0o660

- name: 'copy {{ icingaweb2_module_grafana__auth_jwt__priv_key_file }} to /etc/icingaweb2/modules/grafana/jwt.key.priv'
ansible.builtin.copy:
src: '{{ icingaweb2_module_grafana__auth_jwt__priv_key_file }}'
dest: '/etc/icingaweb2/modules/grafana/jwt.key.priv'
remote_src: true
owner: 'apache'
group: 'icingaweb2'
mode: 0o644
when: 'icingaweb2_module_grafana__auth_jwt'

tags:
- 'icingaweb2_module_grafana'
- 'icingaweb2_module_grafana:configure'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; {{ ansible_managed }}
; 2023050802
; 2026032601

[grafana]
accessmode = "iframe"
Expand All @@ -9,9 +9,18 @@ defaultdashboard = "{{ icingaweb2_module_grafana__default_dashboard }}"
defaultdashboardpanelid = "1"
defaultdashboarduid = "default"
defaultorgid = "1"
host = "{{ (icingaweb2_module_grafana__url | split('://'))[1] }}"
protocol = "{{ (icingaweb2_module_grafana__url | split('://'))[0] }}"
host = "{{ icingaweb2_module_grafana__url | ansible.builtin.urlsplit('hostname') }}{{ icingaweb2_module_grafana__url | ansible.builtin.urlsplit('path') }}"
protocol = "{{ icingaweb2_module_grafana__url | ansible.builtin.urlsplit('scheme') }}"
shadows = "0"
theme = "{{ icingaweb2_module_grafana__theme }}"
timerange = "2d"
timerangeAll = "1w/w"
ssl_verifypeer = "0"
ssl_verifyhost = "0"
dashboardlink = "0"
{% if icingaweb2_module_grafana__auth_jwt %}
jwtEnable = "1"
jwtUser = "grafana-admin"
jwtIssuer = "{{ icingaweb2_module_grafana__url }}"
jwtExpires = "30"
{% endif %}
Loading