Skip to content

Commit 70f78ef

Browse files
feat(roles/grafana): Add JWT support
1 parent aaf5d60 commit 70f78ef

8 files changed

Lines changed: 89 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818

1919
### Added
2020

21+
* **role:icingaweb2_module_grafana**: Add JWT support
22+
* **role:grafana**: Add JWT support
2123
* **role:mariadb_server**: Add `mariadb_server__cnf_wsrep_log_conflicts` and `mariadb_server__cnf_wsrep_retry_autocommit` variables
2224
* **role:mariadb_server**: Add `mariadb_server__cnf_wsrep_gtid_mode` variable to configure `wsrep_gtid_mode` for Galera
2325
* **role:openvpn_server**: Add `openvpn_server:crl` tag to allow deploying the certificate revocation list independently

roles/grafana/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ grafana__root_url: 'https://monitoring.example.com/grafana'
4747
| `grafana__auth_anonymous_enabled` | Whether to allow anonymous (passwordless) access or not. Possible options: `true` or `false` | `false` |
4848
| `grafana__auth_anonymous_org_name` | The organization name that should be used for unauthenticated users. | `'Main Org.'` |
4949
| `grafana__auth_anonymous_org_role` | The role for unauthenticated users. | `'Viewer'` |
50+
| `grafana__auth_jwt` | Enable JWT-based authentication for Grafana requests. | `false` |
51+
| `grafana__auth_jwt_key_file` | Path to the public key file used to verify JWT signatures for Grafana authentication. | `/etc/grafana/icinga.pem` |
5052
| `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() }}'` |
5153
| `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() }}'` |
5254
| `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'` |
@@ -71,6 +73,8 @@ grafana__api_url: 'https://grafana01.example.com/grafana'
7173
grafana__auth_anonymous_enabled: false
7274
grafana__auth_anonymous_org_name: 'Main Org.'
7375
grafana__auth_anonymous_org_role: 'Viewer'
76+
grafana__auth_jwt: false
77+
grafana__auth_jwt_key_file: '/etc/grafana/icinga.pem'
7478
grafana__cookie_samesite: 'lax'
7579
grafana__https_config:
7680
cert_file: '/etc/ssl/ssl-certificate.crt'

roles/grafana/defaults/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ grafana__auth_anonymous_org_role: 'Viewer'
66
grafana__bitwarden_collection_id: '{{ lfops__bitwarden_collection_id | default() }}'
77
grafana__bitwarden_organization_id: '{{ lfops__bitwarden_organization_id | default() }}'
88
grafana__cookie_samesite: 'lax'
9+
grafana__auth_jwt: false
10+
grafana__auth_jwt_key_file: '/etc/grafana/icinga.pem'
911
grafana__plugins__dependent_var: []
1012
grafana__plugins__group_var: []
1113
grafana__plugins__host_var: []
@@ -58,3 +60,4 @@ grafana__serve_from_sub_path: false
5860
grafana__service_enabled: true
5961
grafana__skip_token_to_bitwarden: false
6062
grafana__validate_certs: true
63+

roles/grafana/templates/etc/grafana/grafana.ini.j2

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# {{ ansible_managed }}
2-
# 2024031901
2+
# 2026032301
33

44
##################### Grafana Configuration Example #####################
55
#
@@ -1217,3 +1217,32 @@ interval_year = YYYY
12171217

12181218
# Enable or disable loading other base map layers
12191219
;enable_custom_baselayers = true
1220+
1221+
{% if grafana__auth_jwt %}
1222+
[auth.jwt]
1223+
# By default, auth.jwt is disabled.
1224+
enabled = true
1225+
1226+
# HTTP header to look into to get a JWT token.
1227+
header_name = X-JWT-Assertion
1228+
1229+
# Specify a claim to use as a username to sign in.
1230+
username_claim = sub
1231+
1232+
# Specify a claim to use as an email to sign in.
1233+
email_claim = sub
1234+
1235+
# enable JWT authentication in the URL
1236+
url_login = true
1237+
1238+
# PEM-encoded key file in PKIX, PKCS #1, PKCS #8 or SEC 1 format.
1239+
key_file = {{ grafana__auth_jwt_key_file }}
1240+
1241+
# This can be seen as a required "subset" of a JWT Claims Set.
1242+
# expect_claims = {"iss": "https://icinga.yourdomain"}
1243+
1244+
# role_attribute_path = contains(roles[*], 'admin') && 'Admin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer'
1245+
1246+
# To skip the assignment of roles and permissions upon login via JWT and handle them via other mechanisms like the user interface, we can skip the organization role synchronization with the following configuration.
1247+
skip_org_role_sync = true
1248+
{% endif %}

roles/icingaweb2_module_grafana/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Additionally, it deploys the the graph configuration for the [Linuxfabrik Monito
55

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

8-
* 3.0.1
8+
* 3.1.3
99

1010

1111
## Mandatory Requirements
@@ -36,14 +36,15 @@ Example:
3636
```yaml
3737
# mandatory
3838
icingaweb2_module_grafana__monitoring_plugins_version: '1.2.0.11'
39-
icingaweb2_module_grafana__version: 'v3.1.1'
39+
icingaweb2_module_grafana__version: 'v3.1.3'
4040
```
4141
4242
4343
## Optional Role Variables
4444
4545
| Variable | Description | Default Value |
4646
| -------- | ----------- | ------------- |
47+
| `icingaweb2_module_grafana__auth_jwt` | Enable JWT-based authentication for Grafana requests | `false` |
4748
| `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) | `''` |
4849
| `icingaweb2_module_grafana__default_dashboard` | Name of the default Grafana dashboard | `'Default'` |
4950
| `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` |
@@ -53,6 +54,7 @@ icingaweb2_module_grafana__version: 'v3.1.1'
5354
Example:
5455
```yaml
5556
# optional
57+
icingaweb2_module_grafana__auth_jwt: false
5658
icingaweb2_module_grafana__custom_graphs_config: |-
5759
[icingacli-x509]
5860
dashboard = "Default"

roles/icingaweb2_module_grafana/defaults/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ icingaweb2_module_grafana__monitoring_plugins_version: '{{ lfops__monitoring_plu
44
icingaweb2_module_grafana__skip_monitoring_plugins_graphs_config: false
55
icingaweb2_module_grafana__theme: 'light'
66
icingaweb2_module_grafana__url: '{{ grafana__root_url }}'
7+
icingaweb2_module_grafana__auth_jwt: '{{ grafana__auth_jwt }}'
78

89
# -----------------------------------------------------------------------------
910

roles/icingaweb2_module_grafana/tasks/main.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,41 @@
8787
group: 'icingaweb2'
8888
mode: 0o660
8989

90+
- name: 'generate JWT RSA private key'
91+
community.crypto.openssl_privatekey:
92+
path: '/etc/icingaweb2/modules/grafana/jwt.key.priv'
93+
size: 2048
94+
type: 'RSA'
95+
owner: 'apache'
96+
group: 'icingaweb2'
97+
mode: '0640'
98+
when: icingaweb2_module_grafana__auth_jwt
99+
100+
- name: 'generate JWT RSA public key'
101+
community.crypto.openssl_publickey:
102+
path: '/etc/icingaweb2/modules/grafana/jwt.key.pub'
103+
privatekey_path: '/etc/icingaweb2/modules/grafana/jwt.key.priv'
104+
owner: 'apache'
105+
group: 'icingaweb2'
106+
mode: '0644'
107+
when: icingaweb2_module_grafana__auth_jwt
108+
109+
- name: 'copy /etc/icingaweb2/modules/grafana/jwt.key.pub to /etc/grafana/icinga.pem'
110+
ansible.builtin.copy:
111+
src: '/etc/icingaweb2/modules/grafana/jwt.key.pub'
112+
dest: '/etc/grafana/icinga.pem'
113+
remote_src: true
114+
owner: 'root'
115+
group: 'root'
116+
mode: '0644'
117+
when: icingaweb2_module_grafana__auth_jwt
118+
119+
- name: 'restart grafana'
120+
ansible.builtin.systemd:
121+
name: 'grafana-server'
122+
state: 'restarted'
123+
when: icingaweb2_module_grafana__auth_jwt
124+
90125
tags:
91126
- 'icingaweb2_module_grafana'
92127
- 'icingaweb2_module_grafana:configure'

roles/icingaweb2_module_grafana/templates/etc/icingaweb2/modules/grafana/config.ini.j2

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; {{ ansible_managed }}
2-
; 2023050802
2+
; 2026032301
33

44
[grafana]
55
accessmode = "iframe"
@@ -15,3 +15,12 @@ shadows = "0"
1515
theme = "{{ icingaweb2_module_grafana__theme }}"
1616
timerange = "2d"
1717
timerangeAll = "1w/w"
18+
ssl_verifypeer = "0"
19+
ssl_verifyhost = "0"
20+
dashboardlink = "0"
21+
{% if icingaweb2_module_grafana__auth_jwt %}
22+
jwtEnable = "1"
23+
jwtUser = "grafana-admin"
24+
jwtIssuer = "https://{{ (icingaweb2_module_grafana__url | split('://'))[1] }}"
25+
jwtExpires = "30"
26+
{% endif %}

0 commit comments

Comments
 (0)