Slack authentication middleware for Slim Framework

At $work we use Slim for powering our slack / command bot. It's a really nice minimalist framework in PHP which has a nice set of helpers and features whilst still being very lightweight.

Since we're using it for responding to slack requests, we need to validate whether the headers that slack commands send for auth are all correct (the basic idea is that you generate a HMAC hash using your secret key and the details in the header and see if it matches the hash slack sent). Thankfully, Slim has a pretty lean middleware system, which made the code pretty easy to implement.

I've put the code for it on gist for anyone to use under the Mozilla Public License 2.0:

It assumes you are using phpdotenv to store your shared secret as SLACK_SECRET, but if not you can change this on line 43.

There is also, on lines 20-24 the option to have an AUTH_BYPASS env var set to skip checking for the header, but if you don't need this it can safely be removed.

Deploying an image via the digest in Kubernetes

It's possible in kubernetes to specify an image digest when putting together the spec for a pod or deployment, but this doesn't seem to be documented in the documentation itself.

Fortunately, it's really easy to do, and just involves you using an @ instead of a : between the image name and the digest, being sure to include the leading sha256: so if your image definition looks like this with a tag:

image: foo/bar:latest

Change it to:

image: foo/[email protected]:8dc07735a8ffe78835c91e1e278b8cd75ce7ca6e08ed3d36d4b46e9297434157

to deploy the image by its digest.

Add a valid SSL to r1soft server web interface

When you setup r1soft for backups, it will generate its own self-signed SSL for the browser UI. Although it worked fine, the SSL warnings annoyed me and at $work we have a multi-year wildcard for the domain the backup servers sit on, so I decided to sort out a valid SSL for the service.

Unfortunately the r1soft wiki is not great for this as it can be a bit unclear, with the link to key tool they tell you you need being dead, and it took a little bit of fiddling and wrangling with java (one of my favourite things). And why not do their wiki maintainer's job for them?

Requirements

First you'll need the ImportKey tool to generate the keystore file. The link on the r1soft wiki is dead, but you can get the java file from this git repository. Put the ImportKey.java file in /usr/sbin/r1soft/jre/bin

Although r1soft bundles its own version of java, it doesn't include javac which is required to build the ImportKey tool. You should be able to get this from your repos by installing openjdk. The java bundled with r1soft is openjdk 1.7.0, so I downloaded the matching version (package name java-1.7.0-openjdk-devel in centos 7), but in theory openjdk 1.8.0 should also be fine if you don't have repos for 1.7.0, but I haven't tested with this.

Process

First things first, you'll want to ensure you have your SSL certificate in DER format with the cabundle added to the certificate. If you want/need to generate your own from PEM, you should create two files: example.crt and example.key where the example.crt contains your Certificate followed by your CABundle one after the other, and the example.key should contain your Private Key.

Once you have these files, you can run the following openssl commands to convert them to DER files (I do this in /root, but it's up to you where, you'll just need to adjust the upcoming ImportKey commands accordingly):

openssl pkcs8 -topk8 -nocrypt -in example.crt -inform PEM -out examplecert.der -outform DER

openssl x509 -in example.key -inform PEM -out examplekey.der -outform DER

Now you have the necessary certificates, cd to /usr/sbin/r1soft/jre/bin and chmod the file java and keystore to 755 to make them executable. But before we can use the ImportKey file, we need to build it, which you can do by running:

javac ImportKey.java

With that done, we can use the included java with r1soft to generate the keystore file, as follows:

./java ImportKey /root/examplekey.der /root/examplecert.der cdp

n.b. Despite the file being ImportKey.java, you need to run the command on just ImportKey, otherwise java will complain about not being able to load the class

This will have created a file in /root called keystore.ImportKey and we now need to change the passwords on the keystore since this is hardcoded to just password in r1soft (Yay, security!).

First run:

./keytool -storepasswd -keystore /root/keystore.ImportKey

When prompted for the keystore password, just put in importkey and when prompted for the new keystore password, set it to password. Then we need to change the key password to, which we do with:

./keytool -keypasswd -alias cdp -keystore /root/keystore.ImportKey 

On the first password prompt ('Enter keystore password:') enter the new keystore password, which should be password and on the second prompt ('Enter key password for <cdp>:') put in importkey and then on the final prompt ('New key password for <cdp>:') enter password.

And with that you're basically done, you just need to replace the existing keystore with

cp /root/keystore.ImportKey /usr/sbin/r1soft/conf/keystore

Then just restart the r1soft service (called cdp-server) and you'll be done.

PHP Manager for IIS Fatal Error during installation

Adding new programming language functionality to IIS is pretty streamlined these days via the use of Microsoft's Web Platform Installer which bundles together installers and modules for various languages and handles all the setup for you with a couple of clicks.

However, there is a slight stumbling block when trying to add PHP support to IIS in Windows Server 2016. Specifically, when you go to use Web Platform Installer to install a PHP version, the PHP binaries and modules will install fine, but you'll encounter the following fatal error when the automatically included PHP Manager for IIS tries to install:
error_phpman.png

Now, strictly speaking you don't need this, it just provides a UI for managing loaded extensions in the php.ini, etc., but it's definitely a nicety to have for managing the config directly within the IIS. Fortunately the fix is easy, albeit involving a bit of registry hacking (Or as my coworker would prefer to call it 'Configuration Changing').

First things first, hit start and in the start menu, type in regedit and open it. In here, via the left, browse through the folder structures to the following location:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC\Parameters

Your regedit window should look as follows:
regedit_iis.png

Double click on the MajorVersion value, and in the window that pops up, set the Base to Decimal and the Value Data to 8, so the resulting window should look like:
edit_registry.png

Save, and then without closing regedit, go to Web Platform Installer and you should be able to install PHP Manager without any issues. Once installed, go back to the regedit window and edit the same MajorVersion Value in the same way, but set the Value back to 10.

Essentially we're spoofing our windows version to the installer as the error occurs due to it checking which windows you're running and failing due to it not matching what it thinks it can support. This is exactly why I'd consider it Registry Hacking rather than simple configuration changes, and also why you should put the value back as there's probably a number of fun ways having software thinking you're running a different version of windows than you are can cause you issues.

Redirecting EU visitors in Apache

At $work a client requested the ability to easily detect visitors to their site coming from within the EU so that they could redirect them accordingly.

Fortunately, this was pretty simple to do via use of mod_maxminddb which parses maxmind databases to provide a rather large amount of possible information.

You should follow the guide within their git to get it installed and acquire a maxmind database, of which both free and commerical copies exist, linked to on the module's git page.

Once installed and correctly using your maxmind DB within the apache config, we want to set it to both detect your visitor's country ISO code and from there check if they're within the EU. To grab their ISO code you would specify the following in your apache config:

MaxMindDBEnv MM_COUNTRY_CODE COUNTRY_DB/country/iso_code

This will create an apache variable called MM_COUNTRY_CODE which contains the 2 letter ISO code of your visitor. From this we can set another variable if this is code matches a defined EU state, like so:

SetEnvIf MM_COUNTRY_CODE ^(AT|BE|BG|CZ|DE|DK|EE|ES|FI|FR|HR|GB|GR|IE|IT|CY|LV|LT|LU|HU|MT|NL|PL|PT|RO|SI|SK|SE) EUROPEANUNION

So when you're done, your httpd.conf should contain lines that look like this:

MaxMindDBEnable On
MaxMindDBFile COUNTRY_DB /usr/local/share/GeoIP/GeoLite2-Country.mmdb
MaxMindDBFile CITY_DB    /usr/local/share/GeoIP/GeoLite2-City.mmdb
MaxMindDBEnv MM_COUNTRY_CODE COUNTRY_DB/country/iso_code
SetEnvIf MM_COUNTRY_CODE ^(AT|BE|BG|CZ|DK|EE|ES|HR|GR|IE|IT|CY|LV|LT|LU|HU|MT|NL|AT|PL|PT|RO|SI|SK|FI|SE) EUROPEANUNION

This can now be used within your .htaccess file to redirect customers who are in the EU as follows:

RewriteEngine On
RewriteCond %{ENV:EUROPEANUNION} ^1$
RewriteRule ^(.*)$ http://www.yourawesomesite.com/eu/ [R=301,L]