feat: enable Lix admins to admin the Buildbot properly

This removes the need for a proxy and rely on the `groups` property of
the `userDetails` passed at the authentication layer.

To add a certain role, add the group `buildbot-$role` to that user via
Keycloak.

Signed-off-by: Raito Bezarius <raito@lix.systems>
This commit is contained in:
raito 2024-06-09 17:01:32 +02:00
parent 45135d249b
commit f2d7f25f86

View file

@ -9,6 +9,7 @@ from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING, Any
import buildbot
from buildbot.configurators import ConfiguratorBase
from buildbot.plugins import reporters, schedulers, secrets, steps, util, worker
from buildbot.process import buildstep, logobserver, remotecommand
@ -17,7 +18,6 @@ from buildbot.process.properties import Interpolate, Properties
from buildbot.process.results import ALL_RESULTS, statusToString
from buildbot.steps.trigger import Trigger
from buildbot.util import asyncSleep
from buildbot.www.authz.endpointmatchers import EndpointMatcherBase, Match
from buildbot.www.oauth2 import OAuth2Auth
from buildbot.changes.gerritchangesource import GerritChangeSource
from buildbot.reporters.utils import getURLForBuild
@ -27,6 +27,7 @@ from buildbot.process.buildstep import EXCEPTION
from buildbot.process.buildstep import SUCCESS
from buildbot.process.results import worst_status
from buildbot_nix.binary_cache import LocalSigner
import requests
if TYPE_CHECKING:
from buildbot.process.log import Log
@ -46,11 +47,33 @@ log = Logger()
class LixSystemsOAuth2(OAuth2Auth):
name = 'Lix'
faIcon = 'fa-login'
resourceEndpoint = "https://identity.lix.systems"
# is passing scope necessary?
resourceEndpoint = "https://identity.lix.systems/realms/lix-project/protocol/openid-connect"
sslVerify = True
debug = False
authUri = 'https://identity.lix.systems/realms/lix-project/protocol/openid-connect/auth'
tokenUri = 'https://identity.lix.systems/realms/lix-project/protocol/openid-connect/token'
def createSessionFromToken(self, token):
s = requests.Session()
s.headers = {
'Authorization': 'Bearer ' + token['access_token'],
'User-Agent': f'buildbot/{buildbot.version}',
}
if self.debug:
log.info("Token obtained: {}".format(token))
s.verify = self.sslVerify
return s
def getUserInfoFromOAuthClient(self, c):
userinfo_resp = c.get("https://identity.lix.systems/realms/lix-project/protocol/openid-connect/userinfo")
log.info("Userinfo request to Lix OAuth2: {}".format(userinfo_resp.status_code))
if userinfo_resp.status_code != 200:
log.info("Userinfo failure: {}".format(userinfo_resp.headers["www-authenticate"]))
userinfo_data = userinfo_resp.json()
return {
'groups': userinfo_data['buildbot_roles']
}
class BuildbotNixError(Exception):
pass
@ -901,3 +924,18 @@ class GerritNixConfigurator(ConfiguratorBase):
if "auth" not in config["www"]:
config["www"]["auth"] = LixSystemsOAuth2('buildbot', read_secret_file('buildbot-oauth2-secret'), autologin=True)
if "authz" not in config["www"]:
config["www"]["authz"] = util.Authz(
allowRules=[
util.AnyEndpointMatcher(role="admin", defaultDeny=False),
util.StopBuildEndpointMatcher(role="owner"),
util.AnyControlEndpointMatcher(role="admin"),
],
roleMatchers=[
# A user must have buildbot-<something> to have the role <something>
# e.g. buildbot-admin to be admin.
util.RolesFromGroups(groupPrefix="buildbot-"),
util.RolesFromOwner(role="owner")
],
)