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 pathlib import Path
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
import buildbot
from buildbot.configurators import ConfiguratorBase from buildbot.configurators import ConfiguratorBase
from buildbot.plugins import reporters, schedulers, secrets, steps, util, worker from buildbot.plugins import reporters, schedulers, secrets, steps, util, worker
from buildbot.process import buildstep, logobserver, remotecommand 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.process.results import ALL_RESULTS, statusToString
from buildbot.steps.trigger import Trigger from buildbot.steps.trigger import Trigger
from buildbot.util import asyncSleep from buildbot.util import asyncSleep
from buildbot.www.authz.endpointmatchers import EndpointMatcherBase, Match
from buildbot.www.oauth2 import OAuth2Auth from buildbot.www.oauth2 import OAuth2Auth
from buildbot.changes.gerritchangesource import GerritChangeSource from buildbot.changes.gerritchangesource import GerritChangeSource
from buildbot.reporters.utils import getURLForBuild 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.buildstep import SUCCESS
from buildbot.process.results import worst_status from buildbot.process.results import worst_status
from buildbot_nix.binary_cache import LocalSigner from buildbot_nix.binary_cache import LocalSigner
import requests
if TYPE_CHECKING: if TYPE_CHECKING:
from buildbot.process.log import Log from buildbot.process.log import Log
@ -46,11 +47,33 @@ log = Logger()
class LixSystemsOAuth2(OAuth2Auth): class LixSystemsOAuth2(OAuth2Auth):
name = 'Lix' name = 'Lix'
faIcon = 'fa-login' faIcon = 'fa-login'
resourceEndpoint = "https://identity.lix.systems" resourceEndpoint = "https://identity.lix.systems/realms/lix-project/protocol/openid-connect"
# is passing scope necessary? sslVerify = True
debug = False
authUri = 'https://identity.lix.systems/realms/lix-project/protocol/openid-connect/auth' authUri = 'https://identity.lix.systems/realms/lix-project/protocol/openid-connect/auth'
tokenUri = 'https://identity.lix.systems/realms/lix-project/protocol/openid-connect/token' 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): class BuildbotNixError(Exception):
pass pass
@ -901,3 +924,18 @@ class GerritNixConfigurator(ConfiguratorBase):
if "auth" not in config["www"]: if "auth" not in config["www"]:
config["www"]["auth"] = LixSystemsOAuth2('buildbot', read_secret_file('buildbot-oauth2-secret'), autologin=True) 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")
],
)