Caddy with Google OAuth2
Caddy is a reverse proxy, used to serve content to the internet from within multiple VMs and containers in my lab. But what if the webpage is not secure? Enter caddy-security.
Caddy is a reverse proxy, used to serve content to the internet from within multiple VMs and containers in my lab. This website is being hosted through Caddy.
But what if the webpage is not secure? Is there a way to provide SSO across all sites? Enter caddy-security - a plugin for Caddy that allows integration with a variety of OAuth2 providers. For our example we'll be concentrating on Google's authentication provider.
Installing xcaddy
Caddy does not come prebuilt with caddy-security by default. I opted to build Caddy from source and to include caddy-security at build time. Other options are available - Docker images and downloading prebuilt binaries. The latter of which did not work for me.
First of all, download and install Go. I installed version 1.18.1 - some of the dependencies of the caddy-security build require later versions of Go. The latest available from apt preceded this requirement, so I downloaded the binary manually.
Once installed, run the following:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-xcaddy-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-xcaddy.list
sudo apt update
sudo apt install xcaddy
Building Caddy
Simply run the following to build the Caddy binary with caddy-security support
xcaddy build --with github.com/greenpau/caddy-security
Setting up Google Client ID & Secret
Some set up is required on the Google side in order for the authentication handshake to actually work.
You will first need to set up an OAuth consent screen in Google Cloud: https://console.cloud.google.com/apis/credentials/consent
Followed by a credentials entry:
This will produce a client ID and client secret required to configure caddy-security.
Updates to the Caddyfile
The following is an cut down version of my Caddyfile which provides OAuth2 security to this website
{
order authenticate before respond
order authorize before basicauth
security {
oauth identity provider google {
realm google
driver google
client_id {env.GOOGLE_CLIENT_ID}.apps.googleusercontent.com
client_secret {env.GOOGLE_CLIENT_SECRET}
scopes openid email profile
}
authentication portal mfportal {
crypto default token lifetime 3600
crypto key sign-verify {env.JWT_SHARED_KEY}
enable identity provider google
cookie domain mayfield.site
transform user {
match realm google
match email [email protected]
action add role authp/user
}
transform user {
match realm google
match email [email protected]
action add role authp/admin
}
}
authorization policy mfpolicy {
set auth url https://auth.mayfield.site/oauth2/google/authorization-code-callback
crypto key verify {env.JWT_SHARED_KEY}
allow roles authp/admin authp/user
validate bearer header
inject headers with claims
}
}
}
auth.mayfield.site {
authenticate with mfportal
}
blog.mayfield.site {
authorize with mfpolicy
header x-forwarded-proto https
reverse_proxy 192.168.1.142:2368
}
Note the different roles that can be added to the user, depending on the email address configured. I'm an admin and Shreena is a user.
Requests hit Caddy, which informs the need to authorize using mfpolicy. This authorization policy depends on an authentication hop via mfportal, which in turn uses the Google identity provider. Once Caddy is happy we have successfully authenticated and have been authorized, it will forward the request on to the server listed on 192.168.1.142.
Caddy Environment
In the Caddyfile you will notice a few values injected via environment variables. As I'm running the service at startup with systemctl on Ubuntu, I ran the following command to edit the environment variables.
systemctl edit caddy
### Editing /etc/systemd/system/caddy.service.d/override.conf
### Anything between here and the comment below will become the new contents of the file
[Service]
Environment="JWT_SHARED_KEY=mf"
Environment="GOOGLE_CLIENT_ID=blahblahblah"
Environment="GOOGLE_CLIENT_SECRET=shhshhshh"
Restarting Caddy via systemctl will pick up these changes and your site should now pass through an authn/z phase.
Comments ()