Jenkins is a platform for build automation, and as such allows you to store the results of the build (the binaries, commonly known as “artifacts”) for later.
I saw other people on the internet manually downloading their results via the web UI:
However, I wanted to pull the artifacts from my automation platform (currently Chef), and ran into an authentication predicament.
Normally, when using HTTP basic authentication, there’s a “challenge-response” mechanism, looking something like this:
However, Jenkins doesn’t challenge clients for credentials (response 401), and instead fails immediatly (response 403).
This is called “Preemptive authentication”, and is considered a bad habit because the client hands out credentials when it’s not definitely required. Therefore, most clients require special configuration to handle this.
For instance, when using
wget, one can use:
wget --auth-no-challenge --http-user=USER --http-password=BESTPASS http://server/jenkins
However, when using any tool where the URL is implicit, such as PIP or Chef’s remote_file, I can only provide credentials by specifying them in the URL (e.g.
http://back:firstname.lastname@example.org/repo), so I don’t have any way of modifying the authentication method.
The result - I can’t download artifacts directly from Jenkins, messing up my deployment cookbooks.
I thought about storing the results in a secondary server to act as a repo, but I really liked having Jenkins automatic maintenance (only keeping the last successful build’s artifact) and the simplicity of downloading from Jenkins directly, because less steps in building-downloading-installing means less places to fail.
I ended up using Apache on the Jenkins server as a credentials-requiring-proxy, meaning that:
- Apache will require credentials using the good-old “challenge-response” method
- Apache will forward the request, including the now-provided crednetials, to Jenkins
- Jenkins will do it’s thing, providing the latest build’s artifacts
The setup was as pretty standard reverse proxy, except for the authentication part - I needed Apache to require credetials, but accept any non-empty set.
I used mod_authn_anon to require authentication with
* as the value, causing it to accept any user/password provided.
The result looks like this:
<VirtualHost *:1234> <Location /> # Allow any user, but require one Anonymous * AuthType basic AuthName 'Jenkins Proxy' AuthBasicProvider anon Require valid-user </Location> ProxyPass / http://localhost:1111/ </VirtualHost>
http://localhost:1111/ is Jenkins’ normal web UI.
Since I only use “end” URLs (as in not following redirections from the server), I didn’t need to add a ProxyPassReverse directive like
ProxyPassReverse / http://localhost:1111/, which causes Apache to rewrite HTTP headers to match the proxy rather than the original server.
I won’t post the entire apache configuration, because it’s pretty trivial. However, the modules I needed are:
Now everything works and I’m happy.