Dex is the solution used for handling OpenID connect sessions.
A user first connects to a dex instance where an OpenID session is invoked.
The user then authorises Fulcio to request the users email address as part of an OpenID scope. This email address is then recored into the x509 signing certificates
Connect to the compute instance
$ gcloud compute ssh sigstore-oauth2
$ sudo apt-get update -y
If you want to save up some time, remove man-db first
$ sudo apt-get remove -y --purge man-db
$ sudo apt-get install haproxy make git gcc certbot -y
Download and run the golang installer (system package is not yet 1.16)
$ curl -O https://storage.googleapis.com/golang/getgo/installer_linux
$ chmod +x installer_linux
$ ./installer_linux
e.g.
Welcome to the Go installer!
Downloading Go version go1.17.1 to /home/luke/.go
This may take a bit of time...
Downloaded!
Setting up GOPATH
GOPATH has been set up!
One more thing! Run `source /home/$USER/.bash_profile` to persist the
new environment variables to your current session, or open a
new shell prompt.
As suggested run
$ source /home/$USER/.bash_profile
$ go version
go version go1.17.1 linux/amd64
Let's create a HAProxy config, set DOMAIN
to your registered domain and your
private IP
address
DOMAIN="oauth2.yourdomain.com"
IP="10.240.0.12"
Let's now run certbot to obtain our TLS certs.
$ sudo certbot certonly --standalone --preferred-challenges http \
--http-01-address ${IP} --http-01-port 80 -d ${DOMAIN} \
--non-interactive --agree-tos --email youremail@domain.com
Move the PEM chain into place
$ sudo cat "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" \
"/etc/letsencrypt/live/${DOMAIN}/privkey.pem" \
| sudo tee "/etc/ssl/private/${DOMAIN}.pem" > /dev/null
Now we need to change certbot configuration for automatic renewal
Prepare post renewal script
$ cat /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh
#!/bin/bash
DOMAIN="oauth2.example.com"
cat "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" \
"/etc/letsencrypt/live/${DOMAIN}/privkey.pem" \
> "/etc/ssl/private/${DOMAIN}.pem"
systemctl reload haproxy.service
Make sure the script has executable flag set
$ sudo chmod +x /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh
Replace port and address in the certbot's renewal configuration file for the domain (pass ACME request through the haproxy to certbot)
$ ls -l /etc/letsencrypt/renewal/oauth2.example.com.conf
http01_port = 9080
http01_address = 127.0.0.1
Append new line
post_hook = /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh
Prepare haproxy configuration
$ cat > haproxy.cfg <<EOF
defaults
timeout connect 10s
timeout client 30s
timeout server 30s
log global
mode http
option httplog
maxconn 3000
log 127.0.0.1 local0
frontend haproxy
#public IP address
bind ${IP}:80
bind ${IP}:443 ssl crt /etc/ssl/private/${DOMAIN}.pem
# HTTPS redirect
redirect scheme https code 301 if !{ ssl_fc }
acl letsencrypt-acl path_beg /.well-known/acme-challenge/
use_backend letsencrypt-backend if letsencrypt-acl
default_backend sigstore_dex
backend sigstore_dex
server sigstore_oauth2_internal ${IP}:6000
backend letsencrypt-backend
server certbot_internal 127.0.0.1:9080
EOF
Inspect the resulting haproxy.cfg
and make sure everything looks correct.
If so, move it into place
$ sudo mv haproxy.cfg /etc/haproxy/
Check syntax
$ sudo /usr/sbin/haproxy -c -V -f /etc/haproxy/haproxy.cfg
Let's now start HAProxy
$ sudo systemctl enable haproxy.service
Synchronizing state of haproxy.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable haproxy
$ sudo systemctl restart haproxy.service
$ sudo systemctl status haproxy.service
● haproxy.service - HAProxy Load Balancer
Loaded: loaded (/lib/systemd/system/haproxy.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2021-07-18 10:12:28 UTC; 58min ago
Docs: man:haproxy(1)
file:/usr/share/doc/haproxy/configuration.txt.gz
Main PID: 439 (haproxy)
Tasks: 2 (limit: 2322)
Memory: 4.1M
CGroup: /system.slice/haproxy.service
├─439 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid
└─444 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid
Jul 18 10:12:27 sigstore-fulcio systemd[1]: Starting HAProxy Load Balancer...
Jul 18 10:12:28 sigstore-fulcio systemd[1]: Started HAProxy Load Balancer.
Test automatic renewal
$ sudo certbot renew --dry-run
$ mkdir -p ~/go/src/github.com/dexidp/ && cd "$_"
$ git clone https://github.com/dexidp/dex.git
$ cd dex
$ make build
$ sudo mv bin/dex /usr/local/bin/
📝 We re using Google here, you can do the same for github and microsoft too. The placeholders are already within
config.yaml
-
Head to the credentials page
-
Select 'CONFIGURE CONSENT SCREEN'
Select 'Internal'
NOTE: If you're not a Google Workspace user, the 'Internal' option will not be available. You can only make your app available to external (general audience) users only. In such a case, the 'External' User Type works fine as well.
Fill out the app registration details
-
Set scopes
Select 'ADD OR REMOVE SCOPES' and set the
userinfo.email
scopeSelect "SAVE AND CONTINUE"
Select "BACK TO DASHBOARD" and select 'Credentials'
-
Create OAuth Client ID
Select "Web Application" and fill out the "Authorized Redirect URIs"
Select "CREATE"
-
Note down tour Client ID and Secret and keep them safe (we will need them for dex)
Set up the configuration file for dex.
Provide saved OIDC details as variables
GOOGLE_CLIENT_ID="..."
GOOGLE_CLIENT_SECRET="..."
$ cat > dex-config.yaml <<EOF
issuer: https://${DOMAIN}/auth
storage:
type: sqlite3
config:
file: /var/dex/dex.db
web:
http: 0.0.0.0:5556
frontend:
issuer: sigstore
theme: light
# Configuration for telemetry
telemetry:
http: 0.0.0.0:5558
# Options for controlling the logger.
logger:
level: "debug"
format: "json"
# Default values shown below
oauth2:
responseTypes: [ "code" ]
skipApprovalScreen: false
alwaysShowLoginScreen: true
staticClients:
- id: sigstore
public: true
name: 'sigstore'
redirectURIs:
- 'https://${DOMAIN}/auth/callback'
- 'http://localhost:5556/auth/callback'
connectors:
- type: google
id: google-sigstore-test
name: Google
config:
clientID: $GOOGLE_CLIENT_ID
clientSecret: $GOOGLE_CLIENT_SECRET
redirectURI: https://${DOMAIN}/auth/callback
#- type: microsoft
# id: microsoft-sigstore-test
# name: Microsoft
# config:
# clientID: $MSFT_CLIENT_ID
# clientSecret: $MSFT_CLIENT_SECRET
# redirectURI: https://${DOMAIN}/auth/callback
#- type: github
# id: github-sigstore-test
# name: GitHub
# config:
# clientID: $GITHUB_CLIENT_ID
# clientSecret: $GITHUB_CLIENT_SECRET
# redirectURI: https://${DOMAIN}/auth/callback
EOF
Move configuration file
$ sudo mkdir -p /var/dex/
$ sudo mkdir -p /etc/dex/
$ sudo mv dex-config.yaml /etc/dex/
$ dex serve --web-http-addr=0.0.0.0:6000 dex-config.yaml
You may create a bare minimal systemd service for dex
$ cat /etc/systemd/system/dex.service
[Unit]
Description=dex
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
ExecStart=/usr/local/bin/dex serve --web-http-addr=0.0.0.0:6000 /etc/dex/dex-config.yaml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
$ sudo systemctl daemon-reload
$ sudo systemctl enable dex.service
$ sudo systemctl start dex.service
$ sudo systemctl status dex.service
Next: Fulcio