Nested Active Directory Group Membership in Grafana

I am currently in the process of onboarding several teams into our Grafana environment. While we were just POC'ing Grafana, it was all fine and dandy to just have "Grafana Viewer", "Grafana Editor", and "Grafana Admin" groups because not that many people would be in any of them. However, as our environment is growing, it has quickly become clear that managing this additional group membership would be a pain.

When I first set up Grafana, I was unable to get nested group membership working but didn't care enough at the time to troubleshoot much – after all, only myself and a few others would be using it. Now that I've gone back and actually figured out how it works, I want to share what I've learned.

Note: these instructions presume that you are using Active Directory, but the concepts should be transferable to other LDAP providers.

Presumably, you've already configured your Grafana environment to use LDAP as your authentication provider with this bit in your configuration file:

[auth.ldap]
enabled = true
config_file = /etc/grafana/ldap.toml

The instructions on Grafana's site do a good job of getting you up and running with what you'll need in that /etc/grafana/ldap.toml file. However, we need to expand upon that by not just getting what groups a user is a member of, but also what groups those groups are a member of (nested group membership).

To do this, you need to specify a group_search_filter in addition to your plain search_filter. This is in supplement to search_filter, and not a replacement for it – it's required. Your group_search_filter is an LDAP query that essentially tells AD to find all groups that a user is a member of within the group_search_base_dns.

This group_search_filter looks like:

(member:1.2.840.113556.1.4.1941:=CN=%s,OU=Users,OU=FSA,DC=example,DC=domain,DC=com)

Those random looking numbers are an important OID to enable LDAP_MATCHING_RULE_IN_CHAIN, which is what lets us find nested group memberships, too.

When it's configured, it should look like:

## 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 = "(member:1.2.840.113556.1.4.1941:=CN=%s,OU=Users,OU=FSA,DC=example,DC=domain,DC=com)"
## An array of the base DNs to search through for groups. Typically uses ou=groups
group_search_base_dns = ["OU=Admin Groups,OU=Security Groups,OU=FSA,DC=example,DC=domain,DC=com"]
group_search_filter_user_attribute = "sAMAccountName"

As a bonus tip when configuring this, make your group_search_base_dns as specific as possible, because that is what Grafana is going to loop through looking for your group memberships. For example, it was taking 15-20s to log me in when I used "Security Groups" as my base OU, but when I got more specific to use the "Admin Groups" OU (which is where my "Grafana Admin", "Grafana Viewer", and "Grafana Editor" groups are), the results were nearly instant.