Sổ tay vận hành — GIW POC Identity Platform
Trạng thái: POC · Ngày: 21/09/2026
1. Khởi động, dừng, làm lại từ đầu
cd poc/identity
docker compose up -d --build # khởi động (build lần đầu ~3-5 phút)
docker compose ps # tình trạng sức khoẻ mọi service
docker compose logs -f keycloak # theo dõi một service
docker compose down # dừng, giữ lại cơ sở dữ liệu
docker compose down -v # dừng và xoá sạch — lần sau realm import lại
Build lại một service sau khi đổi code:
docker compose up -d --build entitlement-service
Đổi authenticator Java hoặc theme login thì phải build lại Keycloak:
docker compose build keycloak && docker compose up -d keycloak
2. Kiểm chứng
node tests/e2e.mjs # 39 test
cd api && npx @redocly/cli lint giw-poc # OpenAPI
cd api/collection && npx @usebruno/cli run "01 HR Verification" --env local \
--env-var hrApiKey=giw-poc-hr-key-change-me
3. Truy vết một hành trình
Mọi request đều mang X-Correlation-ID. Để đi theo nó từ đầu tới cuối:
CORR=corr-<uuid>
for c in giw-wifi-portal giw-keycloak giw-mock-hr-api giw-entitlement giw-session; do
echo "── $c"; docker logs $c 2>&1 | grep "$CORR"
done
Portal in correlation id lên màn hình Access Granted, nên hành khách có thể đọc nó cho nhân viên hỗ trợ.
4. Tiêm lỗi
# HR hết giờ
curl -X POST localhost:3001/admin/fault -H 'Content-Type: application/json' \
-d '{"mode":"timeout","delayMs":4000}'
# HR trả 503
curl -X POST localhost:3001/admin/fault -H 'Content-Type: application/json' \
-d '{"mode":"unavailable"}'
# về bình thường
curl -X POST localhost:3001/admin/fault -H 'Content-Type: application/json' \
-d '{"mode":"none"}'
curl -s localhost:3001/health # cho biết chế độ lỗi đang bật
Dừng hẳn một service để thử sự cố thật:
docker compose stop mock-hr-api # luồng nhân viên phải fail closed
docker compose stop entitlement-service # cả hai luồng phải fail closed
docker compose start mock-hr-api entitlement-service
5. Admin của Keycloak
http://localhost:8080 — admin / admin (lấy từ .env).
| Việc cần làm | Ở đâu |
|---|---|
| Xem luồng nhân viên | Authentication → Flows → employee-browser |
| Đổi endpoint HR hoặc timeout | Authentication → Flows → employee-browser → execution giw-employee-verify → biểu tượng bánh răng |
| Xác nhận flow binding | Clients → wifi-portal-employee → Advanced → Authentication flow overrides → Browser Flow |
| Xem một nhân viên đã được tạo | Users → tìm emp- → Attributes |
| Theo dõi event trực tiếp | Realm settings → Sessions, và Events → User events |
| Kiểm tra các claim mapper | Client scopes → giw-identity → Mappers |
6. Xử lý sự cố
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
dependency failed to start: container giw-keycloak is unhealthy |
Keycloak còn đang khởi động, hoặc health probe sai | docker logs giw-keycloak. Health nằm ở cổng 9000, không phải 8080. |
Token không có claim profile/email |
Một mảng clientScopes trong bản import realm đầy đủ thay thế các scope dựng sẵn của Keycloak |
Đừng đặt clientScopes vào realm-export.json. bootstrap tạo giw-identity qua Admin API chính vì lý do này. |
| Luồng nhân viên hiện form mật khẩu thông thường | Ghi đè flow binding không có hiệu lực | docker logs giw-bootstrap — tìm dòng flow.binding.set. Chạy lại bằng docker compose up -d --force-recreate bootstrap. |
500 ở trang nhân viên |
Lỗi FreeMarker trong employee-verify.ftl |
`docker logs giw-keycloak |
Entitlement trả UNAUTHORIZED dù token còn mới |
Lệch iss |
iss trong token là hostname hướng trình duyệt (KC_HOSTNAME), trong khi JWKS được lấy qua mạng container. OIDC_ISSUER và OIDC_JWKS_URI là hai biến riêng, có chủ đích. |
ENTITLEMENT_DENIED · COMPANY_NOT_ELIGIBLE |
Đúng như thiết kế | Công ty không nằm trong EMPLOYEE_COMPANIES. |
| Nhân viên xác thực được nhưng chỉ nhận BASIC | Scope giw-identity chưa gắn vào client |
Client scopes → wifi-portal-employee → tab Client scopes. |
RATE_LIMITED dù đăng nhập đúng |
5 lần đoán sai trên hồ sơ nhân viên đó trong vòng 60 s | Chờ, hoặc curl -X POST localhost:3001/admin/reset-limits (chỉ dành cho bộ test). Lần đăng nhập thành công không bao giờ bị tính. |
DMN_UNAVAILABLE |
Bộ máy quyết định đang sập — fail closed theo thiết kế | docker compose ps dmn-service, docker logs giw-dmn. POLICY_FALLBACK=local bật bảng dự phòng dựng sẵn. |
| Sửa luật không có tác dụng | Bộ máy vẫn giữ model cũ | curl -X POST localhost:3005/api/v1/decisions/reload, rồi GET /api/v1/decisions để xác nhận nó nạp file nào. |
DMN_EVALUATION_ERROR |
File .dmn nạp được nhưng không đánh giá được |
Lỗi mô hình hoá, không phải một lần từ chối. docker logs giw-dmn cho thấy thông báo của engine. |
IDENTITY_LINK_CONFLICT |
Hai user cùng một employee_ref |
Phải sửa dữ liệu thủ công. Luồng từ chối đoán. |
| Mất phiên portal sau khi restart | Kho trong bộ nhớ | Đúng như dự kiến. Đăng nhập lại. |
| Cổng đã bị chiếm | 3000-3003, 5432, 8080, 9000 | lsof -ti tcp:8080 |
| Build Maven chậm hoặc lỗi | Lần build đầu phải giải cây phụ thuộc SPI của Keycloak | Cần truy cập mạng tới repo1.maven.org. Sau đó layer được cache. |
7. Cái gì hỏng khi cái gì sập
| Service sập | Luồng khách hàng | Luồng nhân viên |
|---|---|---|
dmn-service |
fail closed — không có luật thì không có truy cập | fail closed |
mock-hr-api |
không ảnh hưởng | fail closed ở bước xác minh |
keycloak |
hỏng | hỏng |
entitlement-service |
xác thực xong rồi 502 — không có truy cập |
như trên |
session-service |
cấp entitlement xong rồi 502 — không có truy cập |
như trên |
postgres |
Keycloak hỏng | Keycloak hỏng |
Không đường nào cấp quyền truy cập khi một phụ thuộc đang sập. Đó là tính chất đáng kiểm lại sau mọi thay đổi.
8. Sức khoẻ hệ thống
for p in 3000 3001 3002 3003; do echo -n "$p: "; curl -s localhost:$p/health; echo; done
curl -s localhost:9000/health/ready # Keycloak
9. Trước khi thứ này rời khỏi máy tính cá nhân
Chỉ thị đang có hiệu lực: nó không rời khỏi máy tính cá nhân. Không cloud, không môi trường test, không server dùng chung, không production, không hosting bên ngoài. Danh sách dưới đây là những gì một lần triển khai trong tương lai sẽ phải đáp ứng — không phải danh sách việc phải làm ngay bây giờ. Xem ENVIRONMENTS.md §3.
- Thay toàn bộ secret trong
.env -
DEBUG_EXPOSE_TOKEN=0 - Gỡ
POST /admin/faultvàPOST /admin/reset-limitskhỏimock-hr-apivàmock-loyalty-api - Gỡ các trang giới thiệu service (
GET /trên cổng 3001–3003, 3005–3006) — chúng liệt kê toàn bộ bề mặt endpoint - Xác thực cho
POST /api/v1/decisions/reload, và đặt việc sửa luật sau một quy trình duyệt - TLS:
sslRequired: external,KC_HOSTNAMEdạng https, cookiesidcóSecure - Thay cả hai chặng
X-API-Keybằng mTLS hoặc service token - Thay kho entitlement và session đang nằm trong bộ nhớ
- Thêm giới hạn tần suất cho Entitlement và Session
- Thu hẹp audience được chấp nhận — ngừng chấp nhận
account - Thay Direct Grant bằng browser OIDC / federation — Mode B trong
AUTH-STRATEGY.md. Direct Grant chỉ dành cho POC. - Chốt quyết định D7 (Bên kiểm soát / Bên xử lý) trước khi trỏ vào dữ liệu HR thật
- Thu thập bằng chứng đồng ý cho đường CCCD, hoặc bỏ CCCD theo ADR-003