MadEngineX / grafana-teams-sync

Sync roles from Keycloak to Grafana
2 stars 0 forks source link

Invalid character '<' looking for beginning of value #1

Open paulbruzz opened 1 month ago

paulbruzz commented 1 month ago

Hello! First and foremost, thank you for your useful tool and for making it available for free. I have a question: after setting the environment variables, I tried to run main.go but all I got was this:

time="2024-07-11T10:49:42+02:00" level=info msg=Starting...
time="2024-07-11T10:49:42+02:00" level=fatal msg="Unable to initialize Keycloak client: oauth2: cannot parse json: invalid character '<' looking for beginning of value"

This would suggest that it's receiving HTML instead of JSON as a response, possibly due to an error page being created. Do you think there is a way to inspect the response, e.g. by printing it to screen during the process, in order to better trace the problem? I have tried to edit the script to serve this purpose, but I can't get it to work like I intend to. Thank you in advance for your consideration.

MadEngineX commented 1 month ago

Hi! Thank you for your feedback.

The token retrieval happens in the "golang/oauth2" library, so you can add a simple fmt.Println(string(body)) in your local library (path will be like ~/go/pkg/mod/golang.org/x/oauth2@v0.19.0/internal/token.go )

Here is the line of code after which you can add the Print statement: #L260

Alternatively, you can set a debug breakpoint at this line and run the code through a debugger, allowing you to see the exact message returned by Keycloak.

I also want to add that I was considering switching the Keycloak client to Nerzal/gocloak to avoid having to manually define paths and handle REST calls myself. We can consider this option if it helps solve your problem.

paulbruzz commented 1 month ago

@MadEngineX thank you very much for your prompt response :) Yes, of course, we can consider the switch to GoCloak as a viable solution. Please let me know!

paulbruzz commented 1 month ago

Hi @MadEngineX sorry for disturbing you again, but I would need further clarification on what KEYCLOAK_MASTER_CLIENT_NAME and KEYCLOAK_MASTER_CLIENT_SECRET represent... I have tried generating the secret for my client in the Master Realm on Keycloak and set the name of the client as KEYCLOAK_MASTER_CLIENT_NAME and the secret as KEYCLOAK_MASTER_CLIENT_SECRET. Could you please confirm it's the correct way? Thank you in advance.

MadEngineX commented 1 month ago

Hi @paulbruzz ! Yes, you are right.

Perhaps I didn’t go deep enough into working with the x/oauth2 library, but without a Сlient in Master Realm I couldn’t set up receiving a token.

Here's the preparation work:

1) In Keycloak in the Master Realm, create a Сlient (in my case,named tech-client). Set the Сlient name in the variable KEYCLOAK_MASTER_CLIENT_NAME. image

2) For the tech-client, configure Authorization and find the Client Secret in the Credentials tab. Pass the Client Secret to the variable KEYCLOAK_MASTER_CLIENT_SECRET. image

3) The Client for Grafana, like other Clients, is located in a separate Realm. Let's assume KEYCLOAK_REALM=business.

4) In the business Realm, create a Client named grafana-dev. Set KEYCLOAK_CLIENT_NAME=grafana-dev

5) In the grafana-dev Client, also enable Authorization and get the Client Secret (KEYCLOAK_CLIENT_SECRET)

6) To obtain a token, you need to provide Keycloak credentials: KEYCLOAK_USER=user KEYCLOAK_PASSWORD=DKmfsp9sdj

7) To authorize in Grafana, you need to provide Grafana credentials: GRAFANA_USER=admin GRAFANA_PASSWORD=csrWWfFDc4cd7Qafaf

Thus, the full list of variables looks like this:

GRAFANA_URL=https://grafana.dev.yourcompany.com/
KEYCLOAK_URL=https://keycloak-dev.yourcompany.com

LOG_LEVEL=debug

## Grafana team sync will filter roles in Keycloak based on this regular expressions.
ROLES_REGEX_RO=-ro ##
ROLES_REGEX_RW=-rw

## How often get updates from Keycloak, Grafana
KEYCLOAK_MONITOR_INTERVAL=1m 
GRAFANA_MONITOR_INTERVAL=1m
## How often to sync Keycloak state to Grafana state
SYNC_INTERVAL=1m

## Basic auth admin creds
GRAFANA_USER=admin
GRAFANA_PASSWORD=csrWWfFDc4cd7Qafaf

## Basic auth admin creds
KEYCLOAK_USER=user
KEYCLOAK_PASSWORD=DKmfsp9sdj 

KEYCLOAK_CLIENT_NAME=grafana-dev
KEYCLOAK_CLIENT_SECRET=QQdfknfeaiouawiefnVaY9T1VcM
KEYCLOAK_MASTER_CLIENT_NAME=tech-client
KEYCLOAK_MASTER_CLIENT_SECRET=EBnDasdoijfewalkn

## Realm, where located Client for Grafana
KEYCLOAK_REALM=business

#

Here is the translation:

I also configured Grafana for OIDC authorization through Keycloak. Here is an excerpt from grafana.ini:

[auth.generic_oauth]
allow_assign_grafana_admin = true
allow_sign_up = true
api_url = https://keycloak-dev.yourcompany.com/realms/business/protocol/openid-connect/userinfo
auth_url = https://keycloak-dev.yourcompany.com/realms/business/protocol/openid-connect/auth
client_id = grafana-dev
client_secret = QQdfknfeaiouawiefnVaY9T1VcM
email_attribute_path = email
enabled = true
login_attribute_path = username
name = Keycloak-OAuth
name_attribute_path = full_name
role_attribute_path = (contains(resource_access."grafana-dev".roles[], 'grafanaadmin') && 'GrafanaAdmin') || (contains(resource_access."grafana-dev".roles[], 'admin') && 'Admin') || (contains(resource_access."grafana-dev".roles[], 'editor') && 'Editor') || 'Viewer'
scopes = openid email profile offline_access roles
token_url = https://keycloak-dev.yourcompany.com/realms/business/protocol/openid-connect/token

Thus, people log in to Grafana using their domain account. By default, they are assigned the Viewer role for everything, but they do not see the folders managed by the grafana-team-sync tool. The grafana-team-sync sees the new OIDC user in Grafana and synchronizes their permissions by adding them to a Grafana Team.

I also configured weisdd/lfgw tool so that users in Grafana cannot receive metrics from other Kubernetes namespaces (not allowed) in their dashboards (you can find the Helm chart for lfgw among my projects).

As a result: 1) User logs into Grafana through OIDC and has the Viewer role. 2) User can see folders with shared dashboards but cannot see the graphs because the metrics are filtered by weisdd/lfgw. 3) When a User is given a role, such as wallets-dev-rw, he gain the permissions to create/delete/edit Dashboards in the wallets-dev folder in Grafana. 4) Finally, thanks to weisdd/lfgw: the User gets access to metrics from the wallets-dev namespace and can view graphs in the shared Dashboards.

If you need we can link in Discord so I can help you with the setup.

paulbruzz commented 1 month ago

@MadEngineX thank you once again for your swift and complete response! Of course we can link in Discord. Is your nickname the same as here?