Add support for LDAP authentication
This patch adds support for LDAP authentication. It also adds support to manage authorization. It is now possible to enable several kind of authentication like LDAP and basic auth. So we introduce a new schema for allowing it: auth: basic: enabled: true ldap: enabled: true [...] instead of auth: engine: basic The former declaration is still valid for basic, anonymous and proxy authentication.
This commit is contained in:
parent
884f1a179e
commit
377c14cca0
5 changed files with 224 additions and 11 deletions
77
README.rst
77
README.rst
|
@ -44,6 +44,83 @@ Server installed with PostgreSQL database
|
|||
user: grafana
|
||||
password: passwd
|
||||
|
||||
Server installed with LDAP authentication and all authenticated users are
|
||||
administrators
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
grafana:
|
||||
server:
|
||||
enabled: true
|
||||
admin:
|
||||
user: admin
|
||||
password: passwd
|
||||
auth:
|
||||
ldap:
|
||||
enabled: true
|
||||
host: '127.0.0.1'
|
||||
port: 389
|
||||
use_ssl: false
|
||||
bind_dn: "cn=admin,dc=grafana,dc=org"
|
||||
bind_password: "grafana"
|
||||
user_search_filter: "(cn=%s)"
|
||||
user_search_base_dns:
|
||||
- "dc=grafana,dc=org"
|
||||
|
||||
Server installed with LDAP and basic authentication
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
grafana:
|
||||
server:
|
||||
enabled: true
|
||||
admin:
|
||||
user: admin
|
||||
password: passwd
|
||||
auth:
|
||||
basic:
|
||||
enabled: true
|
||||
ldap:
|
||||
enabled: true
|
||||
host: '127.0.0.1'
|
||||
port: 389
|
||||
use_ssl: false
|
||||
bind_dn: "cn=admin,dc=grafana,dc=org"
|
||||
bind_password: "grafana"
|
||||
user_search_filter: "(cn=%s)"
|
||||
user_search_base_dns:
|
||||
- "dc=grafana,dc=org"
|
||||
|
||||
Server installed with LDAP for authentication and authorization
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
grafana:
|
||||
server:
|
||||
enabled: true
|
||||
admin:
|
||||
user: admin
|
||||
password: passwd
|
||||
auth:
|
||||
ldap:
|
||||
enabled: true
|
||||
host: '127.0.0.1'
|
||||
port: 389
|
||||
use_ssl: false
|
||||
bind_dn: "cn=admin,dc=grafana,dc=org"
|
||||
bind_password: "grafana"
|
||||
user_search_filter: "(cn=%s)"
|
||||
user_search_base_dns:
|
||||
- "dc=grafana,dc=org"
|
||||
group_search_filter: "(&(objectClass=posixGroup)(memberUid=%s))"
|
||||
group_search_base_dns:
|
||||
- "ou=groups,dc=grafana,dc=org"
|
||||
authorization:
|
||||
enabled: true
|
||||
admin_group: "admins"
|
||||
editor_group: "editors"
|
||||
viewer_group: "viewers"
|
||||
|
||||
Server installed with default StackLight JSON dashboards. This will
|
||||
be replaced by the possibility for a service to provide its own dashboard
|
||||
using salt-mine.
|
||||
|
|
|
@ -144,15 +144,15 @@ auto_assign_org_role = {{ server.auto_assign_role }}
|
|||
|
||||
#################################### Anonymous Auth ##########################
|
||||
[auth.anonymous]
|
||||
{%- if server.auth.engine == 'anonymous' %}
|
||||
{%- if server.auth.engine == 'anonymous' or server.auth.get('anonymous', {}).get('enabled', False) %}
|
||||
enabled = true
|
||||
|
||||
{%- if server.auth.organization is defined %}
|
||||
org_name = {{ server.auth.organization }}
|
||||
{%- if server.auth.organization is defined or server.auth.anonymous.organization is defined %}
|
||||
org_name = {{ server.auth.get('organization', server.auth.anonymous.organization) }}
|
||||
{%- endif %}
|
||||
|
||||
{%- if server.auth.role is defined %}
|
||||
org_name = {{ server.auth.role }}
|
||||
{%- if server.auth.role is defined or server.auth.anonymous.role is defined %}
|
||||
org_name = {{ server.auth.get('role', server.auth.anonymous.role) }}
|
||||
{%- endif %}
|
||||
|
||||
{%- else %}
|
||||
|
@ -193,16 +193,16 @@ org_name = {{ server.auth.role }}
|
|||
|
||||
#################################### Auth Proxy ##########################
|
||||
[auth.proxy]
|
||||
{%- if server.auth.engine == 'proxy' %}
|
||||
{%- if server.auth.engine == 'proxy' or server.auth.get('proxy', {}).get('enabled', False) %}
|
||||
enabled = true
|
||||
header_name = {{ server.auth.get('header', 'X-Forwarded-User') }}
|
||||
header_property = {{ server.auth.get('header_property', 'username') }}
|
||||
header_name = {{ server.auth.get('proxy', {}).get('header', server.auth.get('header', 'X-Forwarded-User')) }}
|
||||
header_property = {{ server.auth.get('proxy', {}).get('header_property', server.auth.get('header_property', 'username')) }}
|
||||
auto_sign_up = true
|
||||
{%- endif %}
|
||||
|
||||
#################################### Basic Auth ##########################
|
||||
[auth.basic]
|
||||
{%- if server.auth.engine == 'basic' %}
|
||||
{%- if server.auth.engine == 'basic' or server.auth.get('basic', {}).get('enabled', False) %}
|
||||
enabled = true
|
||||
{%- else %}
|
||||
enabled = false
|
||||
|
@ -210,8 +210,12 @@ enabled = false
|
|||
|
||||
#################################### Auth LDAP ##########################
|
||||
[auth.ldap]
|
||||
;enabled = false
|
||||
;config_file = /etc/grafana/ldap.toml
|
||||
{%- if server.auth.get('ldap', {}).get('enabled', False) %}
|
||||
enabled = true
|
||||
config_file = /etc/grafana/ldap.toml
|
||||
{%- else %}
|
||||
enabled = false
|
||||
{%- endif %}
|
||||
|
||||
#################################### SMTP / Emailing ##########################
|
||||
[smtp]
|
||||
|
|
108
grafana/files/ldap.toml
Normal file
108
grafana/files/ldap.toml
Normal file
|
@ -0,0 +1,108 @@
|
|||
{%- from "grafana/map.jinja" import server with context %}
|
||||
{%- set ldap_params = server.auth.ldap %}
|
||||
# Set to true to log user information returned from LDAP
|
||||
verbose_logging = false
|
||||
|
||||
[[servers]]
|
||||
# Ldap server host (specify multiple hosts space separated)
|
||||
host = "{{ ldap_params.host }}"
|
||||
# Default port is 389 or 636 if use_ssl = true
|
||||
port = {{ ldap_params.port }}
|
||||
# Set to true if ldap server supports TLS
|
||||
use_ssl = {{ ldap_params.use_ssl|lower }}
|
||||
|
||||
# Set to true if connect ldap server with STARTTLS pattern (create connection in insecure, then upgrade to secure connection with TLS)
|
||||
start_tls = false
|
||||
# set to true if you want to skip ssl cert validation
|
||||
ssl_skip_verify = false
|
||||
# set to the path to your root CA certificate or leave unset to use system defaults
|
||||
# root_ca_cert = /path/to/certificate.crt
|
||||
|
||||
# Search user bind dn
|
||||
bind_dn = "{{ ldap_params.bind_dn }}"
|
||||
# Search user bind password
|
||||
bind_password = "{{ ldap_params.bind_password }}"
|
||||
|
||||
# User search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" or "(uid=%s)"
|
||||
search_filter = "{{ ldap_params.user_search_filter }}"
|
||||
|
||||
# An array of base dns to search through
|
||||
search_base_dns = {{ ldap_params.user_search_base_dns }}
|
||||
|
||||
# In POSIX LDAP schemas, without memberOf attribute a secondary query must be made for groups.
|
||||
# This is done by enabling group_search_filter below. You must also set member_of= "cn"
|
||||
# in [servers.attributes] below.
|
||||
|
||||
# Users with nested/recursive group membership and an LDAP server that supports LDAP_MATCHING_RULE_IN_CHAIN
|
||||
# can set group_search_filter, group_search_filter_user_attribute, group_search_base_dns and member_of
|
||||
# below in such a way that the user's recursive group membership is considered.
|
||||
#
|
||||
# Nested Groups + Active Directory (AD) Example:
|
||||
#
|
||||
# AD groups store the Distinguished Names (DNs) of members, so your filter must
|
||||
# recursively search your groups for the authenticating user's DN. For example:
|
||||
#
|
||||
# group_search_filter = "(member:1.2.840.113556.1.4.1941:=%s)"
|
||||
# group_search_filter_user_attribute = "distinguishedName"
|
||||
# group_search_base_dns = ["ou=groups,dc=grafana,dc=org"]
|
||||
#
|
||||
# [servers.attributes]
|
||||
# ...
|
||||
# member_of = "distinguishedName"
|
||||
|
||||
## Group search filter, to retrieve the groups of which the user is a member (only set if memberOf attribute is not available)
|
||||
# group_search_filter = "(&(objectClass=posixGroup)(memberUid=%s))"
|
||||
## Group search filter user attribute defines what user attribute gets substituted for %s in group_search_filter.
|
||||
## Defaults to the value of username in [server.attributes]
|
||||
## Valid options are any of your values in [servers.attributes]
|
||||
## If you are using nested groups you probably want to set this and member_of in
|
||||
## [servers.attributes] to "distinguishedName"
|
||||
# group_search_filter_user_attribute = "distinguishedName"
|
||||
## An array of the base DNs to search through for groups. Typically uses ou=groups
|
||||
# group_search_base_dns = ["ou=groups,dc=grafana,dc=org"]
|
||||
# Specify names of the ldap attributes your ldap uses
|
||||
|
||||
{%- if ldap_params.group_search_filter is defined %}
|
||||
group_search_filter = "{{ ldap_params.group_search_filter }}"
|
||||
{%- endif %}
|
||||
{%- if ldap_params.group_search_base_dns is defined %}
|
||||
group_search_base_dns = {{ ldap_params.group_search_base_dns }}
|
||||
{%- endif %}
|
||||
|
||||
[servers.attributes]
|
||||
name = "givenName"
|
||||
surname = "sn"
|
||||
username = "cn"
|
||||
member_of = "memberOf"
|
||||
email = "email"
|
||||
|
||||
{%- if ldap_params.get('authorization', {}).get('enabled', False) %}
|
||||
|
||||
# Map ldap groups to grafana org roles
|
||||
{%- if ldap_params.authorization.admin_group is defined %}
|
||||
[[servers.group_mappings]]
|
||||
group_dn = "{{ ldap_params.authorization.admin_group }}"
|
||||
org_role = "Admin"
|
||||
# The Grafana organization database id, optional, if left out the default org (id 1) will be used
|
||||
# org_id = 1
|
||||
{%- endif %}
|
||||
|
||||
{%- if ldap_params.authorization.editor_group is defined %}
|
||||
[[servers.group_mappings]]
|
||||
group_dn = "{{ ldap_params.authorization.editor_group }}"
|
||||
org_role = "Editor"
|
||||
{%- endif %}
|
||||
|
||||
{%- if ldap_params.authorization.viewer_group is defined %}
|
||||
[[servers.group_mappings]]
|
||||
# If you want to match all (or no ldap groups) then you can use wildcard
|
||||
group_dn = "{{ ldap_params.authorization.viewer_group }}"
|
||||
org_role = "Viewer"
|
||||
{%- endif %}
|
||||
|
||||
{%- else %}
|
||||
{# Every user that can be authenticated is an admin #}
|
||||
[[servers.group_mappings]]
|
||||
group_dn = "*"
|
||||
org_role = "Admin"
|
||||
{%- endif %}
|
|
@ -11,6 +11,16 @@ Debian:
|
|||
engine: file
|
||||
auth:
|
||||
engine: application
|
||||
ldap:
|
||||
enabled: false
|
||||
host: '127.0.0.1'
|
||||
port: 389
|
||||
use_ssl: false
|
||||
bind_dn: "cn=admin,dc=grafana,dc=org"
|
||||
bind_password: "grafana"
|
||||
user_search_filter: "(cn=%s)"
|
||||
user_search_base_dns:
|
||||
- "dc=grafana,dc=org"
|
||||
admin:
|
||||
user: admin
|
||||
password: admin
|
||||
|
|
|
@ -14,6 +14,20 @@ grafana_packages:
|
|||
- require:
|
||||
- pkg: grafana_packages
|
||||
|
||||
{%- if server.auth.get('ldap', {}).get('enabled', False) %}
|
||||
/etc/grafana/ldap.toml:
|
||||
file.managed:
|
||||
- source: salt://grafana/files/ldap.toml
|
||||
- template: jinja
|
||||
- user: grafana
|
||||
- group: grafana
|
||||
- require:
|
||||
- pkg: grafana_packages
|
||||
- watch_in:
|
||||
- service: grafana_service
|
||||
{%- endif %}
|
||||
|
||||
|
||||
{%- if server.dashboards.enabled %}
|
||||
|
||||
grafana_copy_default_dashboards:
|
||||
|
|
Loading…
Reference in a new issue