Skip to content

Commit f6bc33f

Browse files
committed
Add a sample docker-compose configuration
This is just a simple setup that users can try out without setting up anything manually, if they have docker installed.
1 parent 0431974 commit f6bc33f

File tree

6 files changed

+272
-0
lines changed

6 files changed

+272
-0
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,8 @@ Hopefully the information above will give you everything you need to configure _
8888
## Testing
8989

9090
The validator has a basic test suite, documented under [test/README.md](test/README.md).
91+
92+
## Examples
93+
94+
Examples can be found in the `examples` folder.
95+
Currently there's only a single [keycloak](examples/keycloak/README.md) example.

examples/keycloak/README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Keycloak Example for pg_oidc_validator
2+
3+
This example provides a demo environment with Keycloak and PostgreSQL configured for OAuth authentication using Docker Compose.
4+
5+
**Notes:**
6+
* This is only a demo environment, with self-signed certificates.
7+
Do not use for production.
8+
* This example doesn't use persistent volumes. When you stop the containers, all data is lost.
9+
10+
## Prerequisites
11+
12+
### Required software
13+
14+
Docker with Compose V2 installed (`docker compose` command)
15+
16+
### Add keycloak to hosts file
17+
18+
For the OAuth device flow to work in your browser, add `keycloak` to your hosts file:
19+
20+
**On Linux/Mac:**
21+
```bash
22+
echo "127.0.0.1 keycloak" | sudo tee -a /etc/hosts
23+
```
24+
25+
**On Windows:** Edit `C:\Windows\System32\drivers\etc\hosts` as Administrator and add:
26+
```
27+
127.0.0.1 keycloak
28+
```
29+
30+
This allows your browser to resolve the `https://keycloak:8443` URLs used in the OAuth device flow.
31+
32+
## Quick Start
33+
34+
```bash
35+
# Start Keycloak and PostgreSQL
36+
docker compose up -d
37+
38+
# Wait for services to be ready
39+
# Optional: watch the logs while waiting
40+
docker compose logs -f
41+
42+
# Once ready, run the interactive psql client
43+
# Follow the OAuth device flow, login with `testuser` / `asdfasdf`
44+
docker compose run --rm psql-client
45+
46+
# When done, stop the services
47+
docker compose down
48+
```
49+
50+
## Keycloak admin interface access
51+
52+
Open https://keycloak:8443 in your browser:
53+
- Username: `admin`
54+
- Password: `admin`

examples/keycloak/certs/crt.pem

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
-----BEGIN CERTIFICATE-----
2+
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
34+
-----END CERTIFICATE-----

examples/keycloak/certs/gencert.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
# Command to generate the files in the certs folder.
3+
# Since they have a 10 year lifetime, running this isn't necessary for a long time.
4+
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out crt.pem -sha256 -days 3650 -nodes \
5+
-subj "/C=XX/ST=StateName/L=CityName/O=CompanyName/OU=CompanySectionName/CN=keycloak" \
6+
-addext "subjectAltName=DNS:keycloak,DNS:localhost,IP:127.0.0.1"

examples/keycloak/certs/key.pem

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
-----BEGIN PRIVATE KEY-----
2+
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
51+
Z0chEXWiWdvIrJ0PVV304gW1cdzvQQ==
52+
-----END PRIVATE KEY-----
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
services:
2+
keycloak:
3+
image: quay.io/keycloak/keycloak:latest
4+
hostname: keycloak
5+
environment:
6+
KC_BOOTSTRAP_ADMIN_USERNAME: admin
7+
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
8+
KC_HTTPS_CERTIFICATE_FILE: /keys/crt.pem
9+
KC_HTTPS_CERTIFICATE_KEY_FILE: /keys/key.pem
10+
KC_HEALTH_ENABLED: "true"
11+
KC_HOSTNAME: keycloak
12+
KC_HOSTNAME_PORT: 8443
13+
KC_HOSTNAME_STRICT: "false"
14+
KC_HOSTNAME_STRICT_BACKCHANNEL: "true"
15+
volumes:
16+
- ../../test/import:/opt/keycloak/data/import
17+
- ./certs:/keys
18+
ports:
19+
- "8443:8443"
20+
command: start-dev --import-realm
21+
healthcheck:
22+
test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/8443 || exit 1"]
23+
interval: 5s
24+
timeout: 3s
25+
retries: 60
26+
start_period: 30s
27+
28+
postgres:
29+
image: postgres:18
30+
environment:
31+
POSTGRES_HOST_AUTH_METHOD: trust
32+
volumes:
33+
- ./certs/crt.pem:/usr/local/share/ca-certificates/keycloak-test.crt:ro
34+
ports:
35+
- "5432:5432"
36+
depends_on:
37+
keycloak:
38+
condition: service_healthy
39+
entrypoint:
40+
- bash
41+
- -c
42+
- |
43+
apt-get update -qq
44+
apt-get install -y -qq ca-certificates curl libcurl4 wget
45+
update-ca-certificates
46+
47+
wget -q https://github.com/Percona-Lab/pg_oidc_validator/releases/download/latest/pg-oidc-validator-pgdg18.deb
48+
dpkg -i pg-oidc-validator-pgdg18.deb
49+
rm pg-oidc-validator-pgdg18.deb
50+
51+
mkdir -p /etc/postgresql/conf.d /docker-entrypoint-initdb.d
52+
53+
cat > /etc/postgresql/conf.d/oauth.conf <<'EOF'
54+
listen_addresses = '*'
55+
oauth_validator_libraries = 'pg_oidc_validator'
56+
pg_oidc_validator.authn_field = 'email'
57+
EOF
58+
59+
cat > /tmp/pg_hba.conf <<'EOF'
60+
host all all 0.0.0.0/0 oauth scope="email pgscope",issuer=https://keycloak:8443/realms/pgrealm,map=emap
61+
local all all trust
62+
host all all 127.0.0.1/32 trust
63+
host all all ::1/128 trust
64+
EOF
65+
66+
cat > /tmp/pg_ident.conf <<'EOF'
67+
emap testuser@example.com testuser
68+
EOF
69+
70+
cat > /docker-entrypoint-initdb.d/create-testuser.sh <<'EOF'
71+
#!/bin/bash
72+
set -e
73+
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
74+
CREATE ROLE testuser LOGIN SUPERUSER;
75+
EOSQL
76+
EOF
77+
78+
chmod +x /docker-entrypoint-initdb.d/create-testuser.sh
79+
80+
exec docker-entrypoint.sh postgres -c hba_file=/tmp/pg_hba.conf -c ident_file=/tmp/pg_ident.conf -c config_file=/etc/postgresql/conf.d/oauth.conf
81+
healthcheck:
82+
test: ["CMD-SHELL", "pg_isready -U postgres"]
83+
interval: 5s
84+
timeout: 5s
85+
retries: 10
86+
87+
psql-client:
88+
image: postgres:18
89+
profiles:
90+
- client
91+
volumes:
92+
- ./certs/crt.pem:/usr/local/share/ca-certificates/keycloak-test.crt:ro
93+
depends_on:
94+
postgres:
95+
condition: service_healthy
96+
entrypoint:
97+
- bash
98+
- -c
99+
- |
100+
apt-get update -qq
101+
apt-get install -y -qq ca-certificates libpq-oauth
102+
update-ca-certificates
103+
104+
echo ''
105+
echo '========================================'
106+
echo 'PostgreSQL OAuth Client'
107+
echo '========================================'
108+
echo ''
109+
echo 'Connecting to PostgreSQL with OAuth...'
110+
echo ''
111+
echo 'When prompted, follow the device flow:'
112+
echo ' 1. Visit the URL shown in your browser'
113+
echo ' 2. Enter the device code'
114+
echo ' 3. Login with: testuser / asdfasdf'
115+
echo ''
116+
echo '========================================'
117+
echo ''
118+
119+
exec psql 'host=postgres dbname=postgres user=testuser oauth_issuer=https://keycloak:8443/realms/pgrealm oauth_client_id=pgtest'
120+
stdin_open: true
121+
tty: true

0 commit comments

Comments
 (0)