Skip to content

Commit a46c031

Browse files
authored
docs(readme): update master index for phase 3 completion (#9)
1 parent 47afc45 commit a46c031

File tree

1 file changed

+21
-196
lines changed

1 file changed

+21
-196
lines changed

README.md

Lines changed: 21 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -1,213 +1,38 @@
11
# Spring Boot Security & Observability Lab
22

3-
This repository is a hands-on lab designed to demonstrate the architectural evolution of a modern Java application. We
4-
will build a system from the ground up, starting with a secure monolith and progressively refactoring it into a fully
5-
observable, distributed system using cloud-native best practices.
3+
This repository is an advanced, hands-on lab demonstrating the architectural evolution of a modern Java application. We will build a system from the ground up, starting with a secure monolith and progressively refactoring it into a fully observable, distributed system using cloud-native best practices.
64

75
---
86

9-
## Lab Progress: Phase 3 - Federated Identity & Multi-Service Architecture
7+
## Workshop Guide: The Evolutionary Phases
108

11-
The `main` branch currently represents the completed state of **Phase 3**.
9+
This lab is structured in distinct, self-contained phases. The `main` branch always represents the latest completed phase. To explore a previous phase's code and detailed documentation, use the links below.
1210

13-
* **Git Tag for this Phase:** `v3.0-federated-identity`
14-
15-
### Objective
16-
17-
The goal of this phase was to perform a major architectural evolution: moving from a self-contained security model to a
18-
modern, **federated identity** pattern. We have introduced an external Identity Provider (Keycloak) and refactored our
19-
system into two distinct services: a pure backend **Resource Server** and a new **Web Client** that handles user-facing
20-
login flows. This is the standard architecture for secure, distributed systems.
21-
22-
### Key Concepts Demonstrated
23-
24-
* **Federated Identity (OAuth2/OIDC):** Delegating user authentication to a dedicated, centralized Identity Provider (
25-
Keycloak).
26-
* **OAuth2 Resource Server:** Refactoring the backend API to a pure resource server whose only job is to validate JWTs
27-
issued by an external authority.
28-
* **OAuth2 Client:** Building a new web application that implements the OIDC **Authorization Code Grant Flow** for
29-
secure, user-facing login.
30-
* **Service-to-Service Security:** Implementing the **Client Credentials Grant** flow for secure, authenticated
31-
communication between the `web-client` and the `resource-server`.
32-
* **Role-Based Access Control (RBAC):** Using Keycloak to manage user and service account roles, and enforcing them in
33-
the `resource-server` with Spring Security's `@PreAuthorize`.
34-
* **Reverse Proxy Gateway:** Introducing a Traefik reverse proxy to provide a single, clean entry point for our identity
35-
provider, solving complex container networking issues for browser-based flows.
36-
* **Infrastructure as Code (IaC):** All services, including Keycloak, PostgreSQL, and Traefik, are defined in
37-
`docker-compose.yml`. Keycloak's entire realm configuration is captured in a version-controlled JSON file for 100%
38-
automated, reproducible setup.
39-
* **Robust Startup Orchestration:** Using Docker health checks to guarantee a stable startup order, eliminating race
40-
conditions between dependent services.
41-
42-
### Architecture Overview
43-
44-
Phase 3 introduces a distributed, multi-service architecture orchestrated by Docker Compose and fronted by a reverse
45-
proxy.
46-
47-
```mermaid
48-
graph TD
49-
subgraph "User's Machine"
50-
B[Browser]
51-
end
52-
53-
subgraph "Docker Compose Network (lab-net)"
54-
P[Traefik Proxy]
55-
56-
subgraph "Services"
57-
WC[Web Client]
58-
RS[Resource Server]
59-
KC[Keycloak]
60-
DB[(PostgreSQL)]
61-
Prom[Prometheus]
62-
Graf[Grafana]
63-
end
64-
end
65-
66-
B -- "1. GET /dashboard (app.local)" --> P;
67-
P -- "2. Forwards to" --> WC;
68-
WC -- "3. Redirects to login" --> B;
69-
B -- "4. GET /auth (keycloak.local)" --> P;
70-
P -- "5. Forwards to" --> KC;
71-
KC -- "6. User authenticates" --> B;
72-
B -- "7. GET /dashboard (app.local) with session" --> P;
73-
P -- "8. Forwards to" --> WC;
74-
75-
subgraph "Service-to-Service Call"
76-
WC -- "9. GET /api/secure/admin (via resource-server:8081)" --> RS;
77-
end
78-
79-
RS -- "10. Validates token with Keycloak" --> KC;
80-
KC -- "11. Uses" --> DB;
81-
RS -- "12. Exposes metrics" --> Prom;
82-
Prom -- "13. Provides data" --> Graf;
83-
84-
```
85-
86-
1. **[Traefik](docker-compose.yml):** Our reverse proxy. It listens on port 80 and routes traffic based on hostname. It
87-
directs `keycloak.local` traffic to Keycloak.
88-
2. **[Keycloak](docker-compose.yml):** Our external Identity Provider, backed by a PostgreSQL database. It is **fully
89-
pre-configured on startup** using a realm export file. See the "Keycloak Configuration" section below for details.
90-
3. **[Web Client](web-client):** The new user-facing application. It handles the OIDC login flow and makes secure,
91-
backend API calls.
92-
4. **[Resource Server](resource-server):** The original application, now refactored to only protect API endpoints by
93-
validating JWTs issued by Keycloak.
94-
95-
---
96-
97-
### Keycloak Configuration Details
98-
99-
A core principle of this lab is Infrastructure as Code. The entire Keycloak environment is configured automatically on
100-
startup, requiring zero manual setup. This is achieved through three key mechanisms in our `docker-compose.yml`:
101-
102-
1. **Reverse Proxy with Traefik:** A Traefik container acts as a reverse proxy. This is the cornerstone of our
103-
networking solution, designed to solve the "split-horizon" problem where our browser (on the host) and our backend
104-
services (in containers) have different views of the network.
105-
* **The Problem:** When the `web-client` needs to log a user in, it must redirect the user's browser to Keycloak. If
106-
it redirects to the internal Docker address (`http://keycloak:8080`), the browser will fail as it cannot resolve
107-
that hostname. If Keycloak is configured to use `localhost`, then the inter-service JWT validation fails.
108-
* **The Solution:** We use a custom hostname, `keycloak.local`. Traefik is configured via Docker labels to listen
109-
for traffic directed to `keycloak.local` and route it to the `keycloak` container. This provides a single,
110-
consistent address. To make this hostname reachable from our host machine, a one-time update to the `/etc/hosts`
111-
file is required, as detailed in the "Local Development" section.
112-
2. **Network Alias:** We use Docker's `networks.aliases` feature to make the Traefik proxy reachable at the
113-
`keycloak.local` hostname from any other container on our shared `lab-net` network. This provides a single,
114-
consistent URL for all services.
115-
3. **Realm Export File:** We provide a complete realm definition in
116-
the [observability-lab-realm.json](config/keycloak/observability-lab-realm.json) file. When the Keycloak container
117-
starts, its `--import-realm` command automatically creates and configures our entire environment based on this file.
118-
119-
The realm export file defines:
120-
121-
* The **`observability-lab` Realm**.
122-
* Two **Clients**:
123-
* `resource-server-api`: A "bearer-only" client representing our backend API.
124-
* `web-app-client`: A "confidential" client representing our user-facing web application, with the correct redirect
125-
URIs configured.
126-
* Two **Users**:
127-
* `lab-admin` (password: `lab-admin`)
128-
* `lab-user` (password: `lab-user`)
129-
* One **Realm Role**: `ADMIN`, which is assigned to the `lab-admin` user.
130-
* **Service-to-Service Authorization**: A set of mappers on the `web-app-client` that ensure its service account token
131-
is correctly configured to be accepted by the `resource-server` and to contain the `ADMIN` role.
132-
133-
This automated setup ensures a perfectly consistent and reproducible environment for every developer, every time.
11+
| Phase | Description & Key Concepts | Code & Docs (at tag) | Key Pull Requests |
12+
|:-----------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
13+
| **1. The Secure Monolith** | A standalone service that issues and validates its own JWTs. Concepts: `AuthenticationManager`, custom `JwtAuthenticationFilter`, `jjwt` library, and a foundational CI pipeline. | [`v1.0-secure-monolith`](https://github.com/apenlor/spring-boot-security-observability-lab/blob/v1.0-secure-monolith/README.md) | [#2](https://github.com/apenlor/spring-boot-security-observability-lab/pull/2), [#3](https://github.com/apenlor/spring-boot-security-observability-lab/pull/3), [#4](https://github.com/apenlor/spring-boot-security-observability-lab/pull/4) |
14+
| **2. Observing the Monolith** | The service is containerized and orchestrated via `docker-compose`. Concepts: Micrometer, Prometheus, Grafana, custom metrics, and automated dashboard provisioning. | [`v2.0-observable-monolith`](https://github.com/apenlor/spring-boot-security-observability-lab/blob/v2.0-observable-monolith/README.md) | [#6](https://github.com/apenlor/spring-boot-security-observability-lab/pull/6) |
15+
| **3. Evolving to Federated Identity** | The system is refactored into a multi-service architecture with an external IdP. Concepts: Keycloak, OIDC, OAuth2 Client (`web-client`) vs. Resource Server, Traefik reverse proxy, service-to-service security. | [`v3.0-federated-identity`](https://github.com/apenlor/spring-boot-security-observability-lab/blob/v3.0-federated-identity/README.md) | [#8](https://github.com/apenlor/spring-boot-security-observability-lab/pull/8) |
16+
| **4. Tracing a Distributed System** | _Upcoming..._ | - | - |
17+
| **5. Correlated Logs & Access Auditing** | _Upcoming..._ | - | - |
18+
| **6. Proactive Alerting** | _Upcoming..._ | - | - |
19+
| **7. Continuous Security Integration** | _Upcoming..._ | - | - |
20+
| **8. Advanced Secret Management** | _Upcoming..._ | - | - |
13421

13522
---
13623

137-
## Local Development & Quick Start
138-
139-
**Prerequisites:** Docker and Docker Compose must be installed. A **one-time setup** is required to configure local
140-
domain names.
141-
142-
1. **Configure Local Hostnames (One-Time Setup):**
143-
You must edit your local `hosts` file to map our service domains to your local machine. This is required for your
144-
browser to correctly interact with the containerized services via the reverse proxy.
145-
* **On macOS / Linux:** Edit `/etc/hosts`
146-
* **On Windows:** Edit `C:\Windows\System32\drivers\etc\hosts` (with an administrator editor)
147-
148-
Add the following line to the end of the file:
149-
```
150-
127.0.0.1 keycloak.local
151-
```
152-
153-
2. **Create and Configure Your Environment File:**
154-
Copy the provided template to create your local `.env` file.
155-
```bash
156-
cp .env.example .env
157-
```
158-
This file contains secrets that your Docker Compose stack will use. You must now add the `WEB_CLIENT_SECRET`.
159-
160-
**How to get the `WEB_CLIENT_SECRET`:**
161-
1. After starting the stack for the first time (`docker-compose up -d`), navigate to the **Keycloak Admin Console**
162-
at [http://keycloak.local](http://keycloak.local).
163-
2. Log in with the admin credentials (`admin`/`admin`).
164-
3. Ensure you are in the `observability-lab` realm (use the dropdown in the top-left corner).
165-
4. Navigate to **Clients** in the left-hand menu.
166-
5. Click on the `web-app-client`.
167-
6. Go to the **Credentials** tab.
168-
7. You will see a "Client secret" field. Click the "copy" icon to copy the secret value.
169-
8. Paste this value into your `.env` file:
170-
```dotenv
171-
# .env
172-
# ... other variables
173-
WEB_CLIENT_SECRET=PASTE_YOUR_COPIED_SECRET_HERE
174-
```
175-
9. You may need to restart the `web-client` for it to pick up the new secret: `docker-compose restart web-client`.
176-
177-
3. **Build and run the entire stack:**
178-
```bash
179-
docker-compose up --build -d
180-
```
181-
This will build all application images and start all services. The `--build` flag ensures your latest code changes
182-
are included. The `-d` flag runs them in the background.
24+
## How to Follow This Lab
18325

184-
4. **Access the Services:**
185-
* **Web Client Application:** [http://localhost:8082](http://localhost:8082) (Login with `lab-user`/`lab-user` or
186-
`lab-admin`/`lab-admin`)
187-
* **Keycloak Admin Console:** [http://keycloak.local](http://keycloak.local) (Login with `admin`/`admin`)
188-
* **Traefik Dashboard:** [http://localhost:8080](http://localhost:8080)
189-
* **Prometheus UI:** [http://localhost:9090](http://localhost:9090)
190-
* **Grafana UI:** [http://localhost:3000](http://localhost:3000) (Login with `admin`/`admin`)
26+
1. **Start with the `main` branch** to see the latest state of the project.
27+
2. To go back in time, use the **"Code & Docs" link** for a specific phase. This will show you the `README.md` for that phase, which contains the specific instructions and examples for that version of the code.
28+
3. To understand the *"why"* behind the changes, review the **Key Pull Requests** for each phase.
19129

19230
---
19331

194-
## Usage Example: The Full OIDC Flow
32+
## Running the Project
19533

196-
1. **Navigate to the Web Client:** Open your browser to `http://localhost:8082`.
197-
2. **Log In:** Click the "Go to Dashboard" button. You will be redirected to the `keycloak.local` login page.
198-
* Log in as the admin user: `lab-admin` / `lab-admin`
199-
* Or log in as the regular user: `lab-user` / `lab-user`
200-
3. **Access the Dashboard and Test Permissions:** You will be redirected back to the `web-client` dashboard. Both
201-
buttons will be visible for both users. This allows you to test the API-level security:
202-
* **As `lab-admin`:** Clicking **both** "Fetch Secure Data" and "Fetch Admin Data" will succeed.
203-
* **As `lab-user`:** Clicking "Fetch Secure Data" will succeed. Clicking "Fetch Admin Data" will correctly fail and
204-
display a **403 FORBIDDEN** error. This proves that our backend `resource-server` is correctly enforcing
205-
role-based security.
206-
4. **Log Out:** Click the "Logout" button. This will perform a full OIDC federated logout, terminating both your
207-
application session and your Keycloak session.
34+
To run the application and see usage examples for the **current phase**, please refer to the detailed instructions in its tagged `README.md` file.
20835

209-
#### Stop the Environment
36+
**[>> Go to instructions for the current phase: `v3.0-federated-identity` <<](https://github.com/apenlor/spring-boot-security-observability-lab/blob/v3.0-federated-identity/README.md#local-development--quick-start)**
21037

211-
```bash
212-
docker-compose down -v
213-
```
38+
As the lab progresses, this link will always be updated to point to the latest completed phase.

0 commit comments

Comments
 (0)