Installing Gerrit and Keycloak for GDB
Table of Contents
Back in September, we had the GNU Tools Cauldron in the gorgeous city of Montréal (perhaps I should write a post specifically about it…). One of the sessions we had was the GDB BoF, where we discussed, among other things, how to improve our patch review system.
I have my own personal opinions about the current review system we use (mailing list-based, in a nutshell), and I haven’t felt very confident to express it during the discussion. Anyway, the outcome was that at least 3 global maintainers have used or are currently using the Gerrit Code Review system for other projects, are happy with it, and that we should give it a try. Then, when it was time to decide who wanted to configure and set things up for the community, I volunteered. Hey, I’m already running the Buildbot master for GDB, what is the problem to manage yet another service? Oh, well.
Before we dive into the details involved in configuring and running gerrit in a machine, let me first say that I don’t totally support the idea of migrating from mailing list to gerrit. I volunteered to set things up because I felt the community (or at least the its most active members) wanted to try it out. I don’t necessarily agree with the choice.
Ah, and I’m writing this post mostly because I want to be able to close the 300+ tabs I had to open on my Firefox during these last weeks, when I was searching how to solve the myriad of problems I faced during the set up!
The initial plan
My very initial plan after I left the session room was to talk to the sourceware.org folks and ask them if it would be possible to host our gerrit there. Surprisingly, they already have a gerrit instance up and running. It’s been set up back in 2016, it’s running an old version of gerrit, and is pretty much abandoned. Actually, saying that it has been configured is an overstatement: it doesn’t support authentication, user registration, barely supports projects, etc. It’s basically what you get from a pristine installation of the gerrit RPM package in RHEL 6.
I won’t go into details here, but after some discussion it was clear to me that the instance on sourceware would not be able to meet our needs (or at least what I had in mind for us), and that it would be really hard to bring it to the quality level I wanted. I decided to go look for other options.
The OSCI folks
Have I mentioned the OSCI project before? They are absolutely awesome. I really love working with them, because so far they’ve been able to meet every request I made! So, kudos to them! They’re the folks that host our GDB Buildbot master. Their infrastructure is quite reliable (I never had a single problem), and Marc Dequénes (Duck) is very helpful, friendly and quick when replying to my questions :-).
So, it shouldn’t come as a surprise the fact that when I decided to look for other another place to host gerrit, they were my first choice. And again, they delivered :-).
Now, it was time to start thinking about the gerrit set up.
User registration?
Over the course of these past 4 weeks, I had the opportunity to learn
a bit more about how gerrit does things. One of the first things that
negatively impressed me was the fact that gerrit doesn’t handle user
registration by itself. It is possible to have a very rudimentary
user registration “system”, but it relies on the site administration
manually registering the users (via htpasswd
) and managing
everything by him/herself.
It was quite obvious to me that we would need some kind of access control (we’re talking about a GNU project, with a copyright assignment requirement in place, after all), and the best way to implement it is by having registered users. And so my quest for the best user registration system began…
Gerrit supports some user authentication schemes, such as OpenID (not OpenID Connect!), OAuth2 (via plugin) and LDAP. I remembered hearing about FreeIPA a long time ago, and thought it made sense using it. Unfortunately, the project’s community told me that installing FreeIPA on a Debian system is really hard, and since our VM is running Debian, it quickly became obvious that I should look somewhere else. I felt a bit sad at the beginning, because I thought FreeIPA would really be our silver bullet here, but then I noticed that it doesn’t really offer a self-service user registration.
After exchanging a few emails with Marc, he told me about Keycloak. It’s a full-fledged Identity Management and Access Management software, supports OAuth2, LDAP, and provides a self-service user registration system, which is exactly what we needed! However, upon reading the description of the project, I noticed that it is written in Java (JBOSS, to be more specific), and I was afraid that it was going to be very demanding on our system (after all, gerrit is also a Java program). So I decided to put it on hold and take a look at using LDAP…
Oh, man. Where do I start? Actually, I think it’s enough to say that I just tried installing OpenLDAP, but gave up because it was too cumbersome to configure. Have you ever heard that LDAP is really complicated? I’m afraid this is true. I just didn’t feel like wasting a lot of time trying to understand how it works, only to have to solve the “user registration” problem later (because of course, OpenLDAP is just an LDAP server).
OK, so what now? Back to Keycloak it is. I decided that instead of thinking that it was too big, I should actually install it and check it for real. Best decision, by the way!
Setting up Keycloak
It’s pretty easy to set Keycloak up. The official website provides a
.tar.gz
file which contains the whole directory tree for the
project, along with helper scripts, .jar
files, configuration, etc.
From there, you just need to follow the documentation, edit the
configuration, and voilà.
For our specific setup I chose to use PostgreSQL instead of the built-in database. This is a bit more complicated to configure, because you need to download the JDBC driver, and install it in a strange way (at least for me, who is used to just editing a configuration file). I won’t go into details on how to do this here, because it’s easy to find on the internet. Bear in mind, though, that the official documentation is really incomplete when covering this topic! This is one of the guides I used, along with this other one (which covers MariaDB, but can be adapted to PostgreSQL as well).
Another interesting thing to notice is that Keycloak expects to be
running on its own virtual domain, and not under a subdirectory (e.g,
https://example.org
instead of https://example.org/keycloak
). For
that reason, I chose to run our instance on another port. It is
supposedly possible to configure Keycloak to run under a subdirectory,
but it involves editing a lot of files, and I confess I couldn’t make
it fully work.
A last thing worth mentioning: the official documentation says that Keycloak needs Java 8 to run, but I’ve been using OpenJDK 11 without problems so far.
Setting up Gerrit
The fun begins now!
The gerrit project also offers a .war
file ready to be deployed.
After you download it, you can execute it and initialize a gerrit
project (or application, as it’s called). Gerrit will create a
directory full of interesting stuff; the most important for us is the
etc/
subdirectory, which contains all of the configuration files for
the application.
After initializing everything, you can try starting gerrit to see if
it works. This is where I had my first trouble. Gerrit also requires
Java 8, but unlike Keycloak, it doesn’t work out of the box with
OpenJDK 11. I had to make a small but important addition in the file
etc/gerrit.config
:
[container]
...
javaOptions = "--add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED"
...
After that, I was able to start gerrit. And then I started trying to
set it up for OAuth2 authentication using Keycloak. This took a
very long time, unfortunately. I was having several problems with
Gerrit, and I wasn’t sure how to solve them. I
tried
asking for help on
the official mailing list, and was able to make some progress, but in
the end I figured out what was missing: I had forgotten to add the
AddEncodedSlashes On
in the Apache configuration file! This was
causing a very strange error on Gerrit (as you can see, a
java.lang.StringIndexOutOfBoundsException
!), which didn’t make
sense. In the end, my Apache config file looks like this:
<VirtualHost *:80>
ServerName gnutoolchain-gerrit.osci.io
RedirectPermanent / https://gnutoolchain-gerrit.osci.io/r/
</VirtualHost>
<VirtualHost *:443>
ServerName gnutoolchain-gerrit.osci.io
RedirectPermanent / /r/
SSLEngine On
SSLCertificateFile /path/to/cert.pem
SSLCertificateKeyFile /path/to/privkey.pem
SSLCertificateChainFile /path/to/chain.pem
# Good practices for SSL
# taken from: <https://mozilla.github.io/server-side-tls/ssl-config-generator/>
# intermediate configuration, tweak to your needs
SSLProtocol all -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on
SSLCompression off
SSLSessionTickets off
# OCSP Stapling, only in httpd 2.3.3 and later
#SSLUseStapling on
#SSLStaplingResponderTimeout 5
#SSLStaplingReturnResponderErrors off
#SSLStaplingCache shmcb:/var/run/ocsp(128000)
# HSTS (mod_headers is required) (15768000 seconds = 6 months)
Header always set Strict-Transport-Security "max-age=15768000"
ProxyRequests Off
ProxyVia Off
ProxyPreserveHost On
<Proxy *>
Require all granted
</Proxy>
AllowEncodedSlashes On
ProxyPass /r/ http://127.0.0.1:8081/ nocanon
#ProxyPassReverse /r/ http://127.0.0.1:8081/r/
</VirtualHost>
I confess I was almost giving up Keycloak when I finally found the problem…
Anyway, after that things went more smoothly. I was finally able to make the user authentication work, then I made sure Keycloak’s user registration feature also worked OK…
Ah, one interesting thing: the user logout wasn’t really working as expected. The user was able to logout from gerrit, but not from Keycloak, so when the user clicked on “Sign in”, Keycloak would tell gerrit that the user was already logged in, and gerrit would automatically log the user in again! I was able to solve this by redirecting the user to Keycloak’s logout page, like this:
[auth]
...
logoutUrl = https://keycloak-url:port/auth/realms/REALM/protocol/openid-connect/logout?redirect_uri=https://gerrit-url/
...
After that, it was already possible to start worrying about configure gerrit itself. I don’t know if I’ll write a post about that, but let me know if you want me to.
Conclusion
If you ask me if I’m totally comfortable with the way things are set up now, I can’t say that I am 100%. I mean, the set up seems robust enough that it won’t cause problems in the long run, but what bothers me is the fact that I’m using technologies that are alien to me. I’m used to setting up things written in Python, C, C++, with very simple yet powerful configuration mechanisms, and an easy to discover what’s wrong when something bad happens.
I am reasonably satisfied with the Keycloak logs things, but Gerrit leaves a lot to be desired in that area. And both projects are written in languages/frameworks that I am absolutely not comfortable with. Like, it’s really tough to debug something when you don’t even know where the code is or how to modify it!
All in all, I’m happy that this whole adventure has come to an end, and now all that’s left is to maintain it. I hope that the GDB community can make good use of this new service, and I hope that we can see a positive impact in the quality of the whole patch review process.
My final take is that this is all worth as long as the Free Software and the User Freedom are the ones who benefit.
P.S.: Before I forget, our gerrit instance is running at https://gnutoolchain-gerrit.osci.io.