Skip to content

Commit 5f05555

Browse files
authored
feat(obs): implement phase 2 observability stack (#6)
* feat: add actuator support & libraries (not secured) * refactor(security): establish dedicated auth package and decouple contexts * feat(api): implement global exception handler and standardized response DTOs * feat(obs): add custom metrics for login attempts and secure API calls * test: add comprehensive unit tests for security services and filter * refactor(package): rename controller package to api * feat(demo): add chaos controller for latency and error simulation * refactor(security): externalize JWT secret to an environment variable * feat(ops): create multi-stage Dockerfile for the application * feat(ops): add initial docker-compose with app, prometheus, and grafana * feat(ops): add and configure docker-compose with prometheus * test(integration): centralize config with a base class and initializer * feat(obs): provision prometheus datasource in grafana * feat(obs): provision grafana dashboard for service metrics * docs(readme): update for Phase 2 completion * chore(ci): add docker image build validation step
1 parent fa01f8f commit 5f05555

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2558
-496
lines changed

.env.example

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# ===================================================================
2+
# LOCAL DEVELOPMENT ENVIRONMENT VARIABLES
3+
# ===================================================================
4+
# Copy this file to .env and replace the placeholder values.
5+
# The .env file is ignored by Git and should NEVER be committed.
6+
#
7+
# These variables will be used by docker-compose.yml to configure the services.
8+
# ===================================================================
9+
10+
# A secure, 256-bit (32-byte) or longer secret key for signing JWTs.
11+
# You can generate a new one using a command like: openssl rand -hex 32
12+
JWT_SECRET_KEY=replace-with-your-super-secret-and-long-key-for-hs256
13+
14+
# Actuator basic auth configuration
15+
ACTUATOR_USERNAME=actuator
16+
ACTUATOR_PASSWORD=actuator-password
17+
ACTUATOR_ROLES=ACTUATOR_ADMIN

.github/workflows/ci.yml

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Java CI with Maven
1+
name: Java CI & Docker Build
22

33
# This workflow will run on pushes to the 'main' branch and on pull requests targeting 'main'
44
on:
@@ -8,8 +8,8 @@ on:
88
branches: [ "main" ]
99

1010
jobs:
11-
build:
12-
# The type of runner that the job will run on
11+
build_and_test:
12+
name: Build & Test Application
1313
runs-on: ubuntu-latest
1414

1515
# Steps represent a sequence of tasks that will be executed as part of the job
@@ -26,4 +26,32 @@ jobs:
2626

2727
# The build will fail if any tests fail, blocking the PR from merging.
2828
- name: Build and test with Maven
29-
run: ./mvnw -B clean verify
29+
run: ./mvnw -B clean verify
30+
31+
build_docker_image:
32+
name: Build Docker Image
33+
# This job will only run if the 'build_and_test' job succeeds.
34+
needs: build_and_test
35+
runs-on: ubuntu-latest
36+
37+
steps:
38+
- name: Checkout repository
39+
uses: actions/checkout@v4
40+
41+
- name: Set up QEMU
42+
# docker/setup-qemu-action@v3.6.0
43+
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
44+
45+
- name: Set up Docker Buildx
46+
# docker/setup-buildx-action@v3.11.1
47+
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
48+
49+
- name: Build the Docker image
50+
# This command proves that our Dockerfile is valid and can be built.
51+
# We don't push the image in this CI workflow, as that is a CD (Continuous Deployment) task.
52+
run: |
53+
docker buildx build \
54+
--platform linux/amd64 \
55+
-t security-lab/resource-server:ci-build \
56+
-f ./resource-server/Dockerfile \
57+
.

README.md

Lines changed: 91 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,108 @@
11
# Spring Boot Security & Observability Lab
22

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.
3+
This repository is a hands-on lab designed to demonstrate 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.
44

55
---
66

7-
## Workshop Guide: The Evolutionary Phases
7+
## Lab Progress: Phase 2 - Observing the Monolith
88

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.
9+
The `main` branch currently represents the completed state of **Phase 2**.
1010

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** | *Upcoming...* | - | - |
15-
| **3. Evolving to Federated Identity** | *Upcoming...* | - | - |
16-
| **4. Tracing a Distributed System** | *Upcoming...* | - | - |
17-
| **5. Correlated Logs & Access Auditing** | *Upcoming...* | - | - |
18-
| **6. Continuous Security Integration** | *Upcoming...* | - | - |
11+
* **Git Tag for this Phase:** `v2.0-observable-monolith`
12+
13+
### Objective
14+
15+
The goal of this phase was to take the secure monolith from Phase 1 and instrument it with a modern observability stack. We have containerized the entire system and can now launch the application, a metrics database (Prometheus), and a visualization platform (Grafana) with a single command. The focus is on gaining deep, real-time insight into the application's performance and behavior.
16+
17+
### Key Concepts Demonstrated
18+
19+
* **Application Instrumentation:** Using Spring Boot Actuator and Micrometer to expose detailed application metrics.
20+
* **Custom Metrics:** Creating custom `Counter` beans to track specific, high-value business events (e.g., login success vs. failure).
21+
* **Containerization:** Building a minimal, secure, and efficient multi-stage `Dockerfile` for the Spring Boot application.
22+
* **Infrastructure as Code (IaC):** Defining and orchestrating a multi-service environment using a single `docker-compose.yml` file.
23+
* **Metrics Pipeline:** Configuring Prometheus to automatically discover, authenticate with, and scrape the metrics from our application's secured management endpoint.
24+
* **Automated Provisioning:** Using Grafana's provisioning feature to automatically configure its data source and load a pre-built dashboard from version-controlled files.
25+
* **Profile-Specific Code:** Isolating non-production, demonstration code (`ChaosController`) using Spring Profiles.
26+
27+
### Architecture Overview
28+
29+
The architecture for Phase 2 is a containerized, multi-service stack. The `docker-compose.yml` file is the blueprint for this environment.
30+
31+
```mermaid
32+
graph TD
33+
subgraph "Local Development Environment"
34+
subgraph "Docker Compose Network"
35+
A[Resource Server Container] -->|Exposes /actuator/prometheus on :9092| B(Prometheus Container);
36+
B -->|Provides data to| C(Grafana Container);
37+
end
38+
U(Developer/User) -->|API Calls on :8081| A;
39+
U -->|Views Dashboards on :3000| C;
40+
end
41+
```
42+
43+
1. **[Resource Server](resource-server):** Our Spring Boot application, now running inside a Docker container. It exposes its business API on port `8081` and its secured management/metrics API on a separate port, `9092`.
44+
2. **[Prometheus](config/prometheus/prometheus.yml):** The time-series database. It is configured to periodically scrape the `/actuator/prometheus` endpoint on our application container, authenticating with Basic Auth.
45+
3. **[Grafana](config/grafana):** The visualization platform. On startup, it is automatically provisioned with a connection to the Prometheus service and a pre-built "Resource Server Overview" dashboard.
1946

2047
---
2148

22-
## How to Follow This Lab
49+
## Local Development & Quick Start
2350

24-
1. **Start with the `main` branch** to see the latest state of the project.
25-
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.
26-
3. To understand the *"why"* behind the changes, review the **Key Pull Requests** for each phase.
51+
**Prerequisites:** Docker and Docker Compose (or a compatible tool like Colima) must be installed.
52+
53+
1. **Create your local environment file:**
54+
Copy the provided template to create your local `.env` file.
55+
```bash
56+
cp .env.example .env
57+
```
58+
*(Review the `.env` file and ensure the pre-filled secrets are suitable for your local development.)*
59+
60+
2. **Build and run the entire stack:**
61+
From the project root, run the Docker Compose `up` command.
62+
```bash
63+
docker-compose up --build
64+
```
65+
This will build the application's Docker image and start all three services (`resource-server`, `prometheus`, `grafana`).
66+
67+
3. **Access the Services:**
68+
* **Application API:** `http://localhost:8081`
69+
* **Prometheus UI:** `http://localhost:9090`
70+
* **Grafana UI:** `http://localhost:3000` (Login with `admin`/`admin`)
2771
2872
---
2973
30-
## Running the Project
74+
## API & Observability Usage Examples
75+
76+
#### 1. Generate Metrics
77+
78+
To see interesting data on your Grafana dashboard, you need to generate some traffic.
79+
80+
* **Authenticate and get a token** (same as Phase 1):
81+
```bash
82+
TOKEN=$(curl -s -X POST http://localhost:8081/auth/login \
83+
-H "Content-Type: application/json" \
84+
-d '{"username":"user", "password":"password"}' | jq -r .jwtToken)
85+
```
86+
* **Call the secure endpoint:**
87+
```bash
88+
curl http://localhost:8081/api/secure/data -H "Authorization: Bearer $TOKEN"
89+
```
90+
* **Call the Chaos Demo endpoint** (multiple times to see variable results):
91+
```bash
92+
curl http://localhost:8081/demo/flaky-request -H "Authorization: Bearer $TOKEN"
93+
```
94+
95+
#### 2. View the Dashboard
3196
32-
To run the application and see usage examples for the **current phase**, please refer to the detailed instructions in its tagged `README.md` file.
97+
1. Navigate to Grafana at `http://localhost:3000`.
98+
2. Log in (`admin`/`admin`).
99+
3. Go to the "Dashboards" section.
100+
4. Open the pre-provisioned **"Resource Server Overview"** dashboard.
101+
5. Observe the panels update in real-time as you generate more API traffic.
33102
34-
**[>> Go to instructions for the current phase: `v1.0-secure-monolith` <<](https://github.com/apenlor/spring-boot-security-observability-lab/blob/v1.0-secure-monolith/README.md#local-development--quick-start)**
103+
#### 3. Stop the Environment
35104
36-
As the lab progresses, this link will always be updated to point to the latest completed phase.
105+
When you are finished, stop all services and remove the containers.
106+
```bash
107+
docker-compose down
108+
```

0 commit comments

Comments
 (0)