Skip to content

Commit e5400b4

Browse files
committed
Implement Keycloak integration for authentication and authorization
- Update environment variables for Keycloak configuration in .env.example - Modify Docker Compose files to include Keycloak service and database setup - Add database initialization script for Keycloak and People API - Enhance application security with OAuth2 and JWT support in Spring configuration - Update application.yml for Keycloak OAuth2 client settings - Add example secret files for Keycloak and API database passwords
1 parent 25fc46a commit e5400b4

File tree

12 files changed

+383
-28
lines changed

12 files changed

+383
-28
lines changed

.env.example

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,32 @@
11
# ----------------------------------------------------------------------------
22
# GENERAL
33
# ----------------------------------------------------------------------------
4-
COMPOSE_PROJECT_NAME=people-api
4+
COMPOSE_PROJECT_NAME=people
55
ENVIRONMENT=production
66

77
# ----------------------------------------------------------------------------
8-
# DB
8+
# API DB
99
# ----------------------------------------------------------------------------
1010
POSTGRES_DB=people
11-
POSTGRES_USER_FILE=/run/secrets/db-user
11+
POSTGRES_USER=postgres
1212
POSTGRES_PASSWORD_FILE=/run/secrets/db-password
1313
PGDATA=/var/lib/postgresql/data/pgdata
1414
POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
1515

16+
# ----------------------------------------------------------------------------
17+
# KEYCLOAK ADMIN (Web UI credentials)
18+
# ----------------------------------------------------------------------------
19+
KC_DB=postgres
20+
KC_DB_URL=jdbc:postgresql://db:5432/keycloak
21+
KC_DB_USERNAME=keycloak
22+
KC_DB_PASSWORD=keycloak
23+
KC_HOSTNAME=keycloak.example.com
24+
KC_PROXY_HEADERS=xforwarded
25+
KC_BOOTSTRAP_ADMIN_USERNAME=username
26+
KC_BOOTSTRAP_ADMIN_PASSWORD=password
27+
KC_HEALTH_ENABLED=true
28+
KC_METRICS_ENABLED=true
29+
1630
# ----------------------------------------------------------------------------
1731
# SPRING
1832
# ----------------------------------------------------------------------------
@@ -22,6 +36,8 @@ SPRING_DATASOURCE_USERNAME=username
2236
SPRING_DATASOURCE_PASSWORD=password
2337
#JAVA_OPTS="-XX:+UseG1GC -Xms256m -Xmx512m"
2438
JAVA_OPTS="-XX:+UseG1GC -XX:MaxRAMPercentage=75"
39+
KEYCLOAK_ISSUER_URI=http://keycloak.example.com/realms/people-realm
40+
KEYCLOAK_JWK_SET_URI=http://keycloak.example.com/realms/people-realm/protocol/openid-connect/certs
2541

2642
# ----------------------------------------------------------------------------
2743
# NGINX

compose-dev.yaml

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,83 @@
1+
name: people-dev
2+
3+
networks:
4+
backend:
5+
driver: bridge
6+
17
services:
28
db:
39
image: postgres:18-alpine3.22
4-
container_name: db
510
restart: always
611
user: postgres
712
secrets:
8-
- db-user
913
- db-password
14+
- keycloak-db-password
15+
- api-db-password
1016
volumes:
1117
- db-data:/var/lib/postgresql/data
12-
env_file:
13-
- .env
18+
- ./postgres/init:/docker-entrypoint-initdb.d:ro # Initialization scripts
19+
environment:
20+
POSTGRES_DB: postgres
21+
POSTGRES_USER: postgres
22+
POSTGRES_PASSWORD: postgres
1423
ports:
1524
- "5432:5432"
1625
healthcheck:
17-
test: [ "CMD", "pg_isready" ]
26+
test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ]
1827
interval: 10s
1928
timeout: 5s
29+
retries: 3
30+
networks:
31+
- backend
32+
33+
keycloak:
34+
image: quay.io/keycloak/keycloak:26.4
35+
command: start-dev
36+
depends_on:
37+
db:
38+
condition: service_healthy
39+
ports:
40+
- "8080:8080"
41+
- "9000:9000" # Admin health endpoint
42+
environment:
43+
KC_DB: postgres
44+
KC_DB_URL: jdbc:postgresql://db:5432/keycloak
45+
KC_DB_USERNAME: keycloak
46+
KC_DB_PASSWORD: keycloak
47+
KEYCLOAK_ADMIN: admin
48+
KEYCLOAK_ADMIN_PASSWORD: admin
49+
KC_HOSTNAME: localhost
50+
KC_PROXY_HEADERS: xforwarded
51+
KC_HEALTH_ENABLED: true
52+
KC_METRICS_ENABLED: true
53+
healthcheck:
54+
test: ["CMD-SHELL", "exec 3<>/dev/tcp/keycloak/9000 && echo -e 'GET /health/ready HTTP/1.1\r\nHost: keycloak\r\nConnection: close\r\n\r\n' >&3 && cat <&3 | grep -q '200 OK'"]
55+
interval: 30s
56+
timeout: 10s
2057
retries: 5
58+
start_period: 90s # Keycloak takes time to initialize
59+
networks:
60+
- backend
2161

22-
app:
62+
api:
2363
build:
2464
context: .
2565
dockerfile: Dockerfile-dev
2666
working_dir: /app
2767
#command: .mvnw -q spring-boot:run
28-
container_name: people-api-dev
2968
depends_on:
3069
db:
3170
condition: service_healthy
71+
keycloak:
72+
condition: service_healthy
3273
environment:
33-
SPRING_PROFILES_ACTIVE: docker
3474
MAVEN_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
35-
env_file:
36-
- .env
75+
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/people
76+
SPRING_DATASOURCE_USERNAME: people
77+
SPRING_DATASOURCE_PASSWORD: people
78+
KEYCLOAK_ISSUER_URI: http://keycloak:8080/realms/people-realm
3779
ports:
38-
- "8080:8080"
80+
- "8081:8080"
3981
- "5005:5005"
4082
volumes:
4183
# - ./:/app
@@ -46,11 +88,15 @@ services:
4688
path: .
4789
target: /app
4890
tty: true
91+
networks:
92+
- backend
4993

5094
volumes:
5195
db-data:
5296
secrets:
5397
db-password:
54-
file: secrets/db-password.txt
55-
db-user:
56-
file: ./secrets/db-user.txt
98+
file: ./secrets/db-password.txt
99+
api-db-password:
100+
file: ./secrets/api-db-password.txt
101+
keycloak-db-password:
102+
file: ./secrets/keycloak-db-password.txt

compose.yaml

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,12 @@ volumes:
146146
secrets:
147147
db-password:
148148
file: ./secrets/db-password.txt
149-
db-user:
150-
file: ./secrets/db-user.txt
149+
api-db-password:
150+
file: ./secrets/api-db-password.txt
151+
keycloak-db-password:
152+
file: ./secrets/keycloak-db-password.txt
153+
keycloak-admin-password:
154+
file: ./secrets/keycloak-admin-password.txt
151155

152156
# ============================================================================
153157
# CONFIGURATION
@@ -266,7 +270,7 @@ services:
266270

267271
# Ports: DO NOT expose externally in production
268272
# ports:
269-
# - "8080:8080" # ❌ For debug only, remove in production
273+
# - "8081:8080" # ❌ For debug only, remove in production
270274

271275
# Ports (not externally exposed, only through nginx)
272276
expose:
@@ -277,8 +281,7 @@ services:
277281
- .env
278282

279283
secrets:
280-
- db-password
281-
- db-user
284+
- api-db-password
282285

283286
# Volumes
284287
volumes:
@@ -288,6 +291,8 @@ services:
288291
depends_on:
289292
db:
290293
condition: service_healthy
294+
keycloak:
295+
condition: service_healthy
291296

292297
# Resource limits
293298
deploy:
@@ -368,11 +373,13 @@ services:
368373
# Secrets
369374
secrets:
370375
- db-password
371-
- db-user
376+
- keycloak-db-password
377+
- api-db-password
372378

373379
# Persistent volumes
374380
volumes:
375381
- db-data:/var/lib/postgresql/data
382+
- ./postgres/init:/docker-entrypoint-initdb.d:ro # Initialization scripts
376383

377384
# Not required, docker uses .env by default
378385
env_file:
@@ -386,7 +393,7 @@ services:
386393

387394
# Healthcheck
388395
healthcheck:
389-
test: [ "CMD-SHELL", "pg_isready -U $$(cat /run/secrets/db-user) -d ${POSTGRES_DB:-people}" ]
396+
test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ]
390397
interval: 10s
391398
timeout: 5s
392399
retries: 5
@@ -418,6 +425,71 @@ services:
418425
# Shared memory size (important for PostgreSQL)
419426
shm_size: 256mb
420427

428+
# ==========================================================================
429+
# KEYCLOAK - Identity and Access Management
430+
# ==========================================================================
431+
keycloak:
432+
image: quay.io/keycloak/keycloak:26.4
433+
container_name: keycloak
434+
435+
cap_drop:
436+
- ALL
437+
438+
security_opt:
439+
- no-new-privileges:true
440+
441+
restart: unless-stopped
442+
443+
networks:
444+
- backend
445+
446+
expose:
447+
- "8080"
448+
449+
# Ports: DO NOT expose externally in production
450+
# ports:
451+
# - "8080:8080" # ❌ For debug only, remove in production
452+
453+
secrets:
454+
- keycloak-db-password
455+
- keycloak-admin-password
456+
457+
env_file:
458+
- .env
459+
460+
command: start-dev
461+
462+
depends_on:
463+
db:
464+
condition: service_healthy
465+
466+
healthcheck:
467+
test: ["CMD-SHELL", "exec 3<>/dev/tcp/keycloak/9000 && echo -e 'GET /health/ready HTTP/1.1\r\nHost: keycloak\r\nConnection: close\r\n\r\n' >&3 && cat <&3 | grep -q '200 OK'"]
468+
interval: 30s
469+
timeout: 10s
470+
retries: 5
471+
start_period: 90s # Keycloak takes time to initialize
472+
473+
deploy:
474+
resources:
475+
limits:
476+
cpus: '0.5'
477+
memory: 512M
478+
reservations:
479+
cpus: '0.25'
480+
memory: 256M
481+
482+
logging:
483+
driver: "json-file"
484+
options:
485+
max-size: "50m"
486+
max-file: "3"
487+
488+
labels:
489+
service: "keycloak"
490+
tier: "backend"
491+
environment: "${ENVIRONMENT:-production}"
492+
421493
# ============================================================================
422494
# INITIALIZATION
423495
# ============================================================================

pom.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,24 @@
119119
<artifactId>commons-lang3</artifactId>
120120
<version>3.20.0</version>
121121
</dependency>
122+
123+
<!-- Spring Security OAuth2 Resource Server - validates tokens -->
124+
<dependency>
125+
<groupId>org.springframework.boot</groupId>
126+
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
127+
</dependency>
128+
129+
<!-- OAuth2 Client - for Swagger and login flows -->
130+
<dependency>
131+
<groupId>org.springframework.boot</groupId>
132+
<artifactId>spring-boot-starter-oauth2-client</artifactId>
133+
</dependency>
134+
135+
<!-- JWT Support -->
136+
<dependency>
137+
<groupId>org.springframework.boot</groupId>
138+
<artifactId>spring-boot-starter-security</artifactId>
139+
</dependency>
122140
</dependencies>
123141

124142
<build>

postgres/init/00-init-databases.sh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Read passwords from Docker secrets
5+
KEYCLOAK_DB_PASSWORD=$(cat /run/secrets/keycloak-db-password)
6+
API_DB_PASSWORD=$(cat /run/secrets/api-db-password)
7+
8+
# Execute SQL with environment variables
9+
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
10+
-- ============================================================================
11+
-- PostgreSQL Initialization Script
12+
-- Creates separate databases and users for each application
13+
-- ============================================================================
14+
15+
-- Create database and user for Keycloak
16+
CREATE DATABASE keycloak;
17+
CREATE USER keycloak WITH PASSWORD '$KEYCLOAK_DB_PASSWORD';
18+
ALTER DATABASE keycloak OWNER TO keycloak;
19+
20+
-- Connect to keycloak database
21+
\c keycloak
22+
23+
-- Grant usage and create privileges on public schema
24+
GRANT ALL PRIVILEGES ON SCHEMA public TO keycloak;
25+
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO keycloak;
26+
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO keycloak;
27+
28+
-- Grant default privileges for future objects
29+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO keycloak;
30+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO keycloak;
31+
32+
----------------------------------------------------------------------------
33+
34+
-- Create database and user for People API
35+
\c postgres
36+
CREATE DATABASE people;
37+
CREATE USER people WITH PASSWORD '$API_DB_PASSWORD';
38+
ALTER DATABASE people OWNER TO people;
39+
40+
-- Connect to keycloak database
41+
\c people
42+
43+
-- Grant usage and create privileges on public schema
44+
GRANT ALL PRIVILEGES ON SCHEMA public TO people;
45+
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO people;
46+
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO people;
47+
48+
-- Grant default privileges for future objects
49+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO people;
50+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO people;
51+
52+
-- Return to postgres database
53+
\c postgres
54+
EOSQL
55+
56+
echo "Database initialization completed successfully!"

secrets/db-password.txt.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
people
1+
postgres
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
admin
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
keycloak

0 commit comments

Comments
 (0)