Browse Source

two articles on oidc

itix-theme
Nicolas Massé 6 years ago
parent
commit
31a0a52b8e
  1. 294
      content/blog/secure-raspberry-pi-keycloak-gatekeeper.md
  2. 162
      content/blog/use-google-account-openid-connect-provider.md
  3. BIN
      static/blog/use-google-account-openid-connect-provider/auth-ok.png
  4. BIN
      static/blog/use-google-account-openid-connect-provider/auth.png
  5. BIN
      static/blog/use-google-account-openid-connect-provider/authorized-domains.png
  6. BIN
      static/blog/use-google-account-openid-connect-provider/create-credentials.png
  7. BIN
      static/blog/use-google-account-openid-connect-provider/create-project.png
  8. BIN
      static/blog/use-google-account-openid-connect-provider/links.png
  9. BIN
      static/blog/use-google-account-openid-connect-provider/oauth-consent.png
  10. BIN
      static/blog/use-google-account-openid-connect-provider/project-name.png
  11. BIN
      static/blog/use-google-account-openid-connect-provider/redirect-uri.png
  12. BIN
      static/blog/use-google-account-openid-connect-provider/script-start.png
  13. BIN
      static/blog/use-google-account-openid-connect-provider/script-url.png
  14. 59
      static/blog/use-google-account-openid-connect-provider/test-auth.sh

294
content/blog/secure-raspberry-pi-keycloak-gatekeeper.md

@ -0,0 +1,294 @@
---
title: "Secure your Raspberry PI with Keycloak Gatekeeper on OpenWRT"
date: 2020-03-28T00:00:00+02:00
opensource:
- OpenWRT
- Keycloak
---
In the article "[Nginx with TLS on OpenWRT](../nginx-with-tls-on-openwrt/)", I explained how to install nginx on a Raspberry PI running OpenWRT for hosting web applications.
Some of the web applications that I installed on my Raspberry PI do not feature any authentication mechanism at all.
No authentication means that anybody on the internet could reach those applications and play with them.
This article explains how to secure applications running on a Raspberry PI with [Keycloak Gatekeeper](https://github.com/keycloak/keycloak-gatekeeper).
[Keycloak Gatekeeper](https://github.com/keycloak/keycloak-gatekeeper) is a reverse proxy whose sole purpose is to authenticate the end-users using the [OpenID Connect](https://openid.net/connect/) protocol.
If Keycloak Gatekeeper is best used in conjunction with the [Keycloak Identity Provider](https://www.keycloak.org/), it can also be used with any Identity Provider that conforms to the OpenID Connect specifications.
The rest of this article assumes you have already setup your OpenID Connect client in the Google Developer Console as explained in this article: [Use your Google Account as an OpenID Connect provider](../use-google-account-openid-connect-provider).
## Compile Keycloak Gatekeeper
Since the Keycloak community provides no ARM binaries, we need to compile Keycloak Gatekeeper by ourselves.
First, make sure you have Go installed on your workstation, **at least version 1.11**.
```sh
$ go version
go version go1.14.1 darwin/amd64
```
Clone the Keycloak Gatekeeper repository.
```sh
git clone https://github.com/keycloak/keycloak-gatekeeper.git -b 9.0.2
cd keycloak-gatekeeper
```
Compile it for the ARM architecture.
```sh
GIT_SHA=$(git --no-pager describe --always --dirty)
BUILD_TIME=$(date '+%s')
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -a -tags netgo -ldflags " -w -X main.gitsha=$GIT_SHA -X main.compiled=$BUILD_TIME" -o bin/keycloak-gatekeeper
```
## Install Keycloak Gatekeeper
On your Raspberry PI, create a directory hierarchy for Keycloak Gatekeeper.
```sh
mkdir -p /opt/keycloak-gatekeeper/bin /opt/keycloak-gatekeeper/etc
```
Copy Keycloak Gatekeeper on your Raspberry PI.
```sh
scp bin/keycloak-gatekeeper root@raspberry-pi.example.test:/opt/keycloak-gatekeeper/bin/
```
Create a dedicated user for Keycloak Gatekeeper.
```sh
opkg update
opkg install shadow-useradd
useradd -d /opt/keycloak-gatekeeper -s /bin/false -m -r gatekeeper
```
Adjust the directory permissions on **/opt/keycloak-gatekeeper/etc/**.
```sh
chown gatekeeper:root /opt/keycloak-gatekeeper/etc/
chmod 700 /opt/keycloak-gatekeeper/etc/
```
## Configure Keycloak Gatekeeper
In this article, we will secure an "Echo Service" (it echoes back the received request).
This service is named **echo-api.3scale.net**.
```
$ curl http://echo-api.3scale.net/
{
"method": "GET",
"path": "/",
"args": "",
"body": "",
"headers": {
"HTTP_VERSION": "HTTP/1.1",
"HTTP_HOST": "echo-api.3scale.net",
"HTTP_ACCEPT": "*/*",
"HTTP_USER_AGENT": "curl/7.64.1",
"HTTP_X_FORWARDED_FOR": "90.79.1.247, 10.0.103.119",
"HTTP_X_FORWARDED_HOST": "echo-api.3scale.net",
"HTTP_X_FORWARDED_PORT": "80",
"HTTP_X_FORWARDED_PROTO": "http",
"HTTP_FORWARDED": "for=10.0.103.119;host=echo-api.3scale.net;proto=http"
},
"uuid": "3ac98e47-8895-4b36-9f27-c4cf5d40d5e9"
}
```
Start by creating a file named **echo.yaml** under **/opt/keycloak-gatekeeper/etc/**.
```yaml
client-id: <YOUR CLIENT_ID>.apps.googleusercontent.com
client-secret: <YOUR CLIENT_SECRET>
discovery-url: https://accounts.google.com/.well-known/openid-configuration
listen: 0.0.0.0:3000
redirection-url: http://raspberry-pi.example.test:3000
encryption-key: <CHANGE ME>
secure-cookie: false
upstream-url: http://echo-api.3scale.net
resources:
- uri: /
enable-refresh-tokens: true
```
Of course, you will have to put your Client ID and Client Secret in the **client-id** and **client-secret** fields.
You will also need to edit the **redirection-url** so that it matches your Raspberry PI hostname (do not forget the port!).
You can generate an encryption key using the following command. Copy the output of this command and paste it in the **encryption-key** field.
```sh
openssl rand -base64 24
```
## Test your configuration
Connect to the [Google Developer Console](https://console.developers.google.com/projectselector2/apis/dashboard?organizationId=0) and add a Redirect URI to your existing OpenID Connect client (pick your project > **Credentials** > click your **OAuth 2.0 client**).
If the **redirection-url** field in the Keycloak Gatekeeper configuration is:
```
http://raspberry-pi.example.test:3000
```
Then, you need to add the following **Authorized redirect URI** in the Google Developer Console:
```
http://raspberry-pi.example.test:3000/oauth/callback
```
Start Keycloak Gatekeeper manually.
```sh
/opt/keycloak-gatekeeper/bin/keycloak-gatekeeper --config /opt/keycloak-gatekeeper/etc/echo.yaml
```
From your web browser, connect to the port 3000 of your Raspberry PI using the **http** protocol.
You should be redirected to the Google Login page and once logged in or if already logged in, you should see the Echo API (output edited for brevity).
```json
{
"method": "GET",
"path": "/",
"args": "",
"body": "",
"headers": {
"HTTP_VERSION": "HTTP/1.1",
"HTTP_HOST": "echo-api.3scale.net",
"HTTP_AUTHORIZATION": "Bearer eyJ...",
"HTTP_COOKIE": "request_uri=Lw==; OAuth_Token_Request_State=dbb1cafa-3cca-4ffc-ac2d-ff6b14593e34; kc-access=eyJ...",
"HTTP_X_AUTH_AUDIENCE": "942727606324-fvavcr2fld4t5o0f84s76vrodgcp9vmq.apps.googleusercontent.com",
"HTTP_X_AUTH_EMAIL": "nicolas DOT masse AT itix.fr",
"HTTP_X_AUTH_EXPIRESIN": "2020-03-28 19:21:37 +0000 UTC",
"HTTP_X_AUTH_GROUPS": "",
"HTTP_X_AUTH_ROLES": "",
"HTTP_X_AUTH_SUBJECT": "114331641802984310666",
"HTTP_X_AUTH_TOKEN": "eyJ...",
"HTTP_X_AUTH_USERID": "nicolas DOT masse AT itix.fr",
"HTTP_X_AUTH_USERNAME": "nicolas DOT masse AT itix.fr",
},
"uuid": "e5dcf957-60d3-41a8-a888-2752c62b08a2"
}
```
If your web browser displays a JSON document containing some **HTTP_X\_AUTH\_\*** headers, your setup is working! Those headers are added by Keycloak Gatekeeper once the user is authenticated.
## Add restrictions on who can access the target service
So far, we configured Keycloak Gatekeeper to enforce authentication of the end-user.
But we have not yet configured any check regarding the identity of the end-user.
So, any user having a GMail account can access the target service.
Let's fix this.
If you have a Google Suite with a custom domain, you can add to the Keycloak Gatekeeper configuration file (**itix.fr** being the Google Suite domain):
```yaml
match-claims:
hd: ^itix.fr$
```
With this additional configuration, only users of your Google Suite will be able to connect.
If you are a regular GMail user, you can enforce a check on your exact email address by adding to the Keycloak Gatekeeper configuration file:
```yaml
match-claims:
email: ^john\.doe@gmail\.com$
```
**Note:** the matches are [regular expressions](https://en.wikipedia.org/wiki/Regular_expression).
Restart Keycloak Gatekeeper and verify that the restrictions you put on the end-user identity is actually enforced.
## Put Keycloak Gatekeeper behind nginx
As explained in the article "[Nginx with TLS on OpenWRT](../nginx-with-tls-on-openwrt/)", I am using nginx to host several web applications on my Raspberry PI.
Since nginx is the entrypoint to access any web application on my Raspberry PI, I need to put Keycloak Gatekeeper behind nginx.
In the nginx configuration file, add a virtual host.
```
server {
listen 443 ssl;
server_name echo.pi.example.test;
ssl_certificate /path/to/crt;
ssl_certificate_key /path/to/key;
// add the usual ssl_* directives here...
location / {
proxy_pass http://127.0.0.1:3000;
}
}
```
The important parts of this configuration are:
* the virtual host listens on port 443 and handles TLS
* it forwards the requests to the Keycloak Gatekeeper on port 3000
* the hostname of this virtual host is **echo.pi.example.test**
Then, we need to modify the Keycloak Gatekeeper configuration accordingly. Only altered fields are listed below.
```yaml
listen: 127.0.0.1:3000
secure-cookie: true
redirection-url: https://echo.pi.example.test
```
The important parts of this configuration are:
* Cookies now have the secure flag (since nginx will serves requests over HTTPS).
* The listen address is now 127.0.0.1 to enforce nginx as the main entry point.
* The Redirect URI has been updated to reflect the virtual host hostname and port.
And finally, we need to update the **Authorized redirect URIs** in the Google Developer Console.
```
https://echo.pi.example.test/oauth/callback
```
Restart nginx.
```sh
service nginx restart
```
## Finish the configuration
Create an init script named **gatekeeper-echo** under **/etc/init.d**
```sh
#!/bin/sh /etc/rc.common
START=80
USE_PROCD=1
start_service() {
procd_open_instance
procd_set_param command /opt/keycloak-gatekeeper/bin/keycloak-gatekeeper --config /opt/keycloak-gatekeeper/etc/echo.yaml
procd_set_param file /opt/keycloak-gatekeeper/etc/echo.yaml
procd_set_param respawn
procd_close_instance
}
```
Make it executable.
```sh
chmod 755 /etc/init.d/gatekeeper-echo
```
Enable and start the service.
```sh
service gatekeeper-echo enable
service gatekeeper-echo start
```
## Conclusion
This article explained how to compile, install and configure Keycloak Gatekeeper to secure applications running on a Raspberry PI. The application we secured was an "Echo Service" to keep things simple, but any application can be secured that way.

162
content/blog/use-google-account-openid-connect-provider.md

@ -0,0 +1,162 @@
---
title: "Use your Google Account as an OpenID Connect provider"
date: 2020-03-27T00:00:00+02:00
---
We have passwords everywhere: to unlock our computer, to reach our inbox, to login as root on our Raspberry PI, etc.
Unless you have a password vault to store your credentials securely, it is very difficult to keep all your credentials safe. With the OpenID Connect protocol, you can replace the individual passwords of every web application by a Google Login.
This article goes through all the steps to use your Google Account as an [OpenID Connect](https://openid.net/connect/) provider and subsequent articles (check links at the bottom of this article) explain how to configure the different services and software to use your Google Account as an OpenID Connect provider.
The article is divided in three parts.
* a general overview of OpenID Connect protocol
* how to configure an OpenID Connect client in the Google Developer Console
* how to test your setup
## Overview of OpenID Connect protocol
Better than a very technical explanation about the protocol: when you are using Facebook Connect, Google Login, GitHub Login etc. on a third party site (your bank, a retail shop, etc.) you are actually using OpenID Connect.
In our use case, the third party site is your service that need to authenticate the end-user and Google is the Authorization Server.
A successful authentication sequence goes through those steps:
* The end-user connects to the target service using its web browser
* The target service has no existing session for the end-user. So, it redirects the end-user to the Authorization Server (Google in our setup).
* The Authorization Server (AS) authenticates the end-user and redirects the end-user back to the target service. When doing so, the AS adds a short lived random code in the URL, called the authorization code.
* The target service capture this authorization code and contact the Authorization Server to exchange this code against a long lived "Access Token" and even longer lived "Refresh Token".
* On a regular basis, the target service contacts the Authorization Server to get a new Access Token by providing the Refresh Token.
* When the Refresh Token expires, the user needs to re-authenticate.
To be sure the target service is not a rogue application, the target service has to provide a "Client ID" and "Client Secret" when contacting the Authorization Server. The Client Secret is... secret! Make sure to keep it safe!
For the Authorization Server to redirect the end-user back to the target service, it has to know the URL of the target service. This is called the "Redirect URI".
## How to configure an OpenID Connect client in the Google Developer Console
The first step in order to use your Google Account as an OpenID Connect provider is to create an OpenID Connect client in the Google Developer Console.
It works for regular GMail users as well as for professional Google Suite users. Just like the regular GMail user, Google Suite users do not need any admin privileges to create an OpenID Connect client.
First, connect to the [Google Developer Console](https://console.developers.google.com/projectselector2/apis/dashboard?organizationId=0).
Click **Create Project**.
![create project](create-project.png)
Fill-in the **Project name** (free choice). The location does not matter. Click **Create**.
![project name](project-name.png)
Click **OAuth Consent screen**. If you are a Google Suite user, select **Internal**. If you are a regular GMail user, select **External**. Click **Create**.
![oauth-consent](oauth-consent.png)
Choose an application name (free choice).
Leave the default scopes.
Add your personal domain to the list of **Authorized Domains**.
For instance, if your target service is at *raspberry-pi.example.test*, add **example.test**.
**DO NOT FORGET to press Enter!**
![authorized-domains](authorized-domains.png)
Fill-in the **Application Homepage Link** and **Application Privacy Policy Link** (free choices). Click **Save**.
![links](links.png)
Click **Credentials**. Select **+ Create Credentials**, then **OAuth Client ID**.
![create-credentials](create-credentials.png)
Under **Application type**, select **Web Application**.
Choose a name for your application (free choice).
Add the redirect URI of your target service if you know it already.
Otherwise you can complete it later.
In the last part of this article, we will test our setup.
To be able to do so, we need to add a special Redirect URI: **http://localhost:666/stop-here** (more on this later).
Click **Create**.
![redirect-uri](redirect-uri.png)
Google generated a **Client ID** and **Client Secret** for you. Keep them somewhere safe!
## Test your setup
There are several open source tools to test your OpenID Connect setup but a very simple shell script is sufficient.
Download the following script and make it executable.
```sh
curl -o test-auth.sh https://www.itix.fr/blog/use-google-account-openid-connect-provider/test-auth.sh
chmod 755 test-auth.sh
```
Open **test-auth.sh** in your favorite editor and add your Client ID and Client Secret.
```sh
CLIENT_ID="<YOUR CLIENT_ID>.apps.googleusercontent.com"
CLIENT_SECRET="<YOUR CLIENT_SECRET>"
```
Now, run this script!
```sh
./test-auth.sh
```
The script generates a URL that you need to copy and paste in your web browser.
![script-start](script-start.png)
If you are not yet logged in, Google asks you to authenticate.
![auth](auth.png)
Once logged in or if you are already logged in, you are redirected to the fake Redirect URI we registered earlier.
![auth-ok](auth-ok.png)
We registered a fake Redirect URI so that we could play each part of the OpenID Connect exchange manually.
**So, if you see an error message from your web browser saying that it cannot connect to the target service: THIS IS EXPECTED FOR OUR TEST.**
Once the browser is redirected at `http://localhost:666/stop-here`, copy the redirect URI from the address bar of your web browser and paste it in the script. Press **Enter**.
Remember that the Authorization Code is very short lived.
So, be quick!
![script-url](script-url.png)
The script contacts the Authorization Server to get an Access Token from the Authorization Code captured in the Redirect URI.
The retrieved Access Token and Refresh Token are printed. The response from the **User Info** endpoint is also printed.
```
Checking the access_token
{
"sub": "114331641802984310666",
"name": "Nicolas Massé",
"given_name": "Nicolas",
"family_name": "Massé",
"profile": "https://plus.google.com/114331641802984310666",
"picture": "https://lh3.googleusercontent.com/a-/AOh14Gg6bHAeILvBuKXJxfbBAScPB_z6QBCh9i4ga_wL_w",
"email": "nicolas DOT masse AT itix.fr",
"email_verified": true,
"gender": "male",
"locale": "en",
"hd": "itix.fr"
}
```
Congratulation! You just completed your first OpenID Connect exchange manually!
## Conclusion
This article gave a general overview of OpenID Connect protocol, explained how to configure an OpenID Connect client in the Google Developer Console and how to test your setup.
Now, you are all set to use your Google Account as an OpenID Connect provider. Continue with one of the following articles:
* [Secure your Raspberry PI with Keycloak Gatekeeper on OpenWRT](../secure-raspberry-pi-keycloak-gatekeeper/)

BIN
static/blog/use-google-account-openid-connect-provider/auth-ok.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 KiB

BIN
static/blog/use-google-account-openid-connect-provider/auth.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 KiB

BIN
static/blog/use-google-account-openid-connect-provider/authorized-domains.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
static/blog/use-google-account-openid-connect-provider/create-credentials.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

BIN
static/blog/use-google-account-openid-connect-provider/create-project.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

BIN
static/blog/use-google-account-openid-connect-provider/links.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

BIN
static/blog/use-google-account-openid-connect-provider/oauth-consent.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

BIN
static/blog/use-google-account-openid-connect-provider/project-name.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

BIN
static/blog/use-google-account-openid-connect-provider/redirect-uri.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

BIN
static/blog/use-google-account-openid-connect-provider/script-start.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

BIN
static/blog/use-google-account-openid-connect-provider/script-url.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

59
static/blog/use-google-account-openid-connect-provider/test-auth.sh

@ -0,0 +1,59 @@
#!/bin/bash
if [ -z "$(which jq)" ]; then
echo "JQ not found. Please install JQ (https://stedolan.github.io/jq/)"
echo
echo "On Mac, you can run 'brew install jq'"
exit 1
fi
AUTHORIZE_ENDPOINT="https://accounts.google.com/o/oauth2/v2/auth"
TOKEN_ENDPOINT="https://oauth2.googleapis.com/token"
TOKENINFO_ENDPOINT="https://openidconnect.googleapis.com/v1/userinfo"
CLIENT_ID="<YOUR CLIENT_ID>.apps.googleusercontent.com"
CLIENT_SECRET="<YOUR CLIENT_SECRET>"
SCOPE="openid%20profile%20email"
REDIRECT_URI="http://localhost:666/stop-here"
echo
echo "Copy/Paste the following URL in your web browser :"
echo "$AUTHORIZE_ENDPOINT?client_id=$CLIENT_ID&scope=$SCOPE&response_type=code&redirect_uri=$REDIRECT_URI&nonce=test&state=test"
echo
echo "You will have to provide the login and password of your test user"
echo
echo "Once you ends up on a blank page (hint: url starts with $REDIRECT_URI), copy/paste this URL below :"
echo
URL=""
while [ -z "$URL" ]; do
read -p "URL: " URL
done
regex='^.*[?&]code=([^&]+)(&|$)'
if [[ "$URL" =~ $regex ]]; then
code="${BASH_REMATCH[1]}"
else
echo "OOPS, could not extract authorization code from the given URL. Sorry."
exit 1
fi
echo
echo "Exchanging our auth code with an access token..."
echo
curl -sS -X POST -d "client_id=$CLIENT_ID" -d "client_secret=$CLIENT_SECRET" -d "grant_type=authorization_code" -d "redirect_uri=$REDIRECT_URI" -d "code=$code" "$TOKEN_ENDPOINT" |tee auth.json
echo
access_token="$(jq -r .access_token auth.json)"
id_token="$(jq -r .id_token auth.json)"
echo
echo "Access Token = $access_token"
echo
echo "JWT (ID Token) = $id_token"
echo
echo "Checking the access_token"
echo
curl -sS "$TOKENINFO_ENDPOINT" -H "Authorization: Bearer $access_token"
echo
Loading…
Cancel
Save