soajs.controller 4.2.42 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +43 -0
- package/.github/workflows/release.yml +94 -0
- package/ARCHITECTURE.md +193 -0
- package/Gruntfile.js +1 -1
- package/docs/configuration-custom-registry.md +421 -0
- package/docs/configuration-services-config.md +275 -0
- package/docs/data-flow.md +138 -0
- package/docs/deployment.md +205 -0
- package/docs/external-integrations.md +159 -0
- package/docs/gateway-routes.md +259 -0
- package/docs/maintenance-routes.md +308 -0
- package/docs/middleware/awareness.md +120 -0
- package/docs/middleware/cors.md +88 -0
- package/docs/middleware/enhancer.md +75 -0
- package/docs/middleware/favicon.md +36 -0
- package/docs/middleware/gotoService.md +146 -0
- package/docs/middleware/ip2ban.md +70 -0
- package/docs/middleware/key.md +196 -0
- package/docs/middleware/keyACL.md +139 -0
- package/docs/middleware/lastSeen.md +111 -0
- package/docs/middleware/maintenanceMode.md +81 -0
- package/docs/middleware/mt.md +568 -0
- package/docs/middleware/oauth.md +173 -0
- package/docs/middleware/response.md +106 -0
- package/docs/middleware/soajs.md +71 -0
- package/docs/middleware/traffic.md +190 -0
- package/docs/middleware/url.md +102 -0
- package/docs/multi-tenant-security.md +183 -0
- package/docs/request-flow.md +230 -0
- package/docs/service-discovery.md +167 -0
- package/mw/key/index.js +16 -1
- package/mw/mt/urac.js +21 -1
- package/mw/mt/utils.js +2 -0
- package/package.json +13 -13
- package/test/unit/mw/key/index.js +150 -0
- package/test/unit/mw/mt/urac.js +157 -4
- package/.travis.yml +0 -72
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Multi-Tenant Security Pipeline
|
|
2
|
+
|
|
3
|
+
The SOAJS Controller Gateway implements a comprehensive security pipeline for multi-tenant environments.
|
|
4
|
+
|
|
5
|
+
## Security Check Flow
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────────────────────────────────────────────────────────────────┐
|
|
9
|
+
│ MULTI-TENANT SECURITY CHECKS │
|
|
10
|
+
└─────────────────────────────────────────────────────────────────────────────────┘
|
|
11
|
+
|
|
12
|
+
Incoming Request with Key
|
|
13
|
+
│
|
|
14
|
+
▼
|
|
15
|
+
┌───────────────────┐
|
|
16
|
+
│ 1. IP Whitelist │ Check application-level IP restrictions
|
|
17
|
+
│ Validation │ FAIL → 403 Forbidden
|
|
18
|
+
└─────────┬─────────┘
|
|
19
|
+
│ PASS
|
|
20
|
+
▼
|
|
21
|
+
┌───────────────────┐
|
|
22
|
+
│ 2. Geo-Location │ Validate request origin geography
|
|
23
|
+
│ Check │ FAIL → 403 Forbidden
|
|
24
|
+
└─────────┬─────────┘
|
|
25
|
+
│ PASS
|
|
26
|
+
▼
|
|
27
|
+
┌───────────────────┐
|
|
28
|
+
│ 3. Device │ Verify device fingerprint
|
|
29
|
+
│ Fingerprint │ FAIL → 403 Forbidden
|
|
30
|
+
└─────────┬─────────┘
|
|
31
|
+
│ PASS
|
|
32
|
+
▼
|
|
33
|
+
┌───────────────────┐
|
|
34
|
+
│ 4. ACL Check │ Validate service/API access permission
|
|
35
|
+
│ │ FAIL → 403 Forbidden
|
|
36
|
+
└─────────┬─────────┘
|
|
37
|
+
│ PASS
|
|
38
|
+
▼
|
|
39
|
+
┌───────────────────┐
|
|
40
|
+
│ 5. OAuth Check │ Validate token (OAuth2 or JWT)
|
|
41
|
+
│ │ FAIL → 401 Unauthorized
|
|
42
|
+
└─────────┬─────────┘
|
|
43
|
+
│ PASS
|
|
44
|
+
▼
|
|
45
|
+
┌───────────────────┐
|
|
46
|
+
│ 6. URAC Profile │ Load user profile and groups
|
|
47
|
+
│ Resolution │ Resolve user-specific ACL
|
|
48
|
+
└─────────┬─────────┘
|
|
49
|
+
│
|
|
50
|
+
▼
|
|
51
|
+
Continue to Service
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Security Checks Detail
|
|
55
|
+
|
|
56
|
+
### 1. IP Whitelist Validation
|
|
57
|
+
|
|
58
|
+
**Middleware:** `mw/mt/utils.js`
|
|
59
|
+
|
|
60
|
+
Validates that the request IP is allowed to access the application.
|
|
61
|
+
|
|
62
|
+
- Configured per external key in the key's `geo` field
|
|
63
|
+
- Supports CIDR notation for IP ranges
|
|
64
|
+
- Also supports gateway-level whitelist via custom registry
|
|
65
|
+
|
|
66
|
+
### 2. Geo-Location Check
|
|
67
|
+
|
|
68
|
+
**Middleware:** `mw/mt/utils.js`
|
|
69
|
+
|
|
70
|
+
Validates request origin based on geographic location.
|
|
71
|
+
|
|
72
|
+
- Configured in external key's `geo` field
|
|
73
|
+
- Supports country-level restrictions
|
|
74
|
+
|
|
75
|
+
### 3. Device Fingerprint
|
|
76
|
+
|
|
77
|
+
**Middleware:** `mw/mt/utils.js`
|
|
78
|
+
|
|
79
|
+
Validates device fingerprint for mobile/app authentication.
|
|
80
|
+
|
|
81
|
+
- Configured in external key's `device` field
|
|
82
|
+
- Useful for mobile app authentication
|
|
83
|
+
|
|
84
|
+
### 4. ACL Check
|
|
85
|
+
|
|
86
|
+
**Middleware:** `mw/mt/utils.js`
|
|
87
|
+
|
|
88
|
+
Validates that the tenant has access to the requested service/API.
|
|
89
|
+
|
|
90
|
+
ACL Resolution Priority:
|
|
91
|
+
1. User-specific ACL (from URAC profile)
|
|
92
|
+
2. Application ACL (from tenant application)
|
|
93
|
+
3. Package ACL (from product package)
|
|
94
|
+
|
|
95
|
+
### 5. OAuth Check
|
|
96
|
+
|
|
97
|
+
**Middleware:** `mw/oauth/index.js`
|
|
98
|
+
|
|
99
|
+
Validates OAuth2 tokens or JWT.
|
|
100
|
+
|
|
101
|
+
- Supports OAuth2 password grant
|
|
102
|
+
- Supports JWT validation
|
|
103
|
+
- Configurable per service
|
|
104
|
+
|
|
105
|
+
### 6. URAC Profile Resolution
|
|
106
|
+
|
|
107
|
+
**Middleware:** `mw/mt/urac.js`
|
|
108
|
+
|
|
109
|
+
Loads user profile from URAC for authenticated requests.
|
|
110
|
+
|
|
111
|
+
- Resolves user groups
|
|
112
|
+
- Applies user-specific ACL overrides
|
|
113
|
+
- Handles network package override for user packages
|
|
114
|
+
|
|
115
|
+
## IP Whitelist Configuration
|
|
116
|
+
|
|
117
|
+
### Gateway-Level Whitelist
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
// In custom registry: gateway.value.mt.whitelist
|
|
121
|
+
{
|
|
122
|
+
"mt": {
|
|
123
|
+
"whitelist": {
|
|
124
|
+
"ips": ["10.0.0.0/8", "192.168.1.0/24"],
|
|
125
|
+
"acl": true, // Skip ACL checks for whitelisted IPs
|
|
126
|
+
"oauth": true // Skip OAuth checks for whitelisted IPs
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Key-Level Restrictions
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
// In external key definition
|
|
136
|
+
{
|
|
137
|
+
"extKey": "...",
|
|
138
|
+
"env": "DEV",
|
|
139
|
+
"geo": {
|
|
140
|
+
"ips": ["192.168.1.0/24"],
|
|
141
|
+
"countries": ["US", "CA"]
|
|
142
|
+
},
|
|
143
|
+
"device": {
|
|
144
|
+
"allow": ["iOS", "Android"]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## ACL Structure
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
{
|
|
153
|
+
"serviceName": {
|
|
154
|
+
"version": {
|
|
155
|
+
"access": true, // or false, or ["group1", "group2"]
|
|
156
|
+
"apisPermission": "restricted", // "restricted" = whitelist mode
|
|
157
|
+
"get": {
|
|
158
|
+
"apis": {
|
|
159
|
+
"/api/path": {
|
|
160
|
+
"access": ["owner", "admin"] // Groups allowed
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"post": { ... },
|
|
165
|
+
"put": { ... },
|
|
166
|
+
"delete": { ... }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Error Codes
|
|
173
|
+
|
|
174
|
+
| Code | Description |
|
|
175
|
+
|------|-------------|
|
|
176
|
+
| 150 | ACL validation failed - no access to service |
|
|
177
|
+
| 151 | ACL validation failed - no access to API |
|
|
178
|
+
| 152 | ACL validation failed - version mismatch |
|
|
179
|
+
| 153 | Geo-location validation failed |
|
|
180
|
+
| 154 | Device validation failed |
|
|
181
|
+
| 155 | IP whitelist validation failed |
|
|
182
|
+
| 401 | OAuth token invalid or expired |
|
|
183
|
+
| 403 | Access forbidden |
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Request Flow
|
|
2
|
+
|
|
3
|
+
The complete request lifecycle through the SOAJS Controller Gateway.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
┌──────────────────────────────────────────────────────────────────────────────────┐
|
|
7
|
+
│ REQUEST LIFECYCLE │
|
|
8
|
+
└──────────────────────────────────────────────────────────────────────────────────┘
|
|
9
|
+
|
|
10
|
+
HTTP Request HTTP Response
|
|
11
|
+
│ ▲
|
|
12
|
+
▼ │
|
|
13
|
+
┌──────────────┐ ┌──────────────┐
|
|
14
|
+
│ 1. SOAJS MW │ Initialize req.soajs context │ Error Handler│
|
|
15
|
+
│ │ Attach registry reference │ │
|
|
16
|
+
└──────┬───────┘ └──────▲───────┘
|
|
17
|
+
│ │
|
|
18
|
+
▼ │
|
|
19
|
+
┌──────────────┐ │
|
|
20
|
+
│ 2. Security │ CORS, IP Ban, Maintenance Mode │
|
|
21
|
+
│ Checks │ │
|
|
22
|
+
└──────┬───────┘ │
|
|
23
|
+
│ │
|
|
24
|
+
▼ │
|
|
25
|
+
┌──────────────┐ │
|
|
26
|
+
│ 3. URL Parse │ Extract: serviceName, version, path │
|
|
27
|
+
│ │ Extract: key/token from header/query │
|
|
28
|
+
└──────┬───────┘ │
|
|
29
|
+
│ │
|
|
30
|
+
▼ │
|
|
31
|
+
┌──────────────┐ │
|
|
32
|
+
│ 4. Service │ Resolve service host via awareness │
|
|
33
|
+
│ Discovery │ Support HA (K8s/Swarm) or custom │
|
|
34
|
+
└──────┬───────┘ │
|
|
35
|
+
│ │
|
|
36
|
+
▼ │
|
|
37
|
+
┌──────────────┐ │
|
|
38
|
+
│ 5. Tenant │ Load key data, validate tenant │
|
|
39
|
+
│ Resolution │ Extract ACL from package │
|
|
40
|
+
└──────┬───────┘ │
|
|
41
|
+
│ │
|
|
42
|
+
▼ │
|
|
43
|
+
┌──────────────┐ │
|
|
44
|
+
│ 6. Security │ IP Whitelist → Geo Check → Device Check │
|
|
45
|
+
│ Pipeline │ → ACL Check → OAuth Check │
|
|
46
|
+
└──────┬───────┘ │
|
|
47
|
+
│ │
|
|
48
|
+
▼ │
|
|
49
|
+
┌──────────────┐ │
|
|
50
|
+
│ 7. Traffic │ Rate limiting with configurable │
|
|
51
|
+
│ Control │ strategies and storage backends │
|
|
52
|
+
└──────┬───────┘ │
|
|
53
|
+
│ │
|
|
54
|
+
▼ │
|
|
55
|
+
┌──────────────────────────────────────────────────────────────────┬──────┘
|
|
56
|
+
│ 8. PROXY TO SERVICE │
|
|
57
|
+
│ │
|
|
58
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ │
|
|
59
|
+
│ │ Resolve Host │───▶│ Build Request │───▶│ HTTP Proxy │ │
|
|
60
|
+
│ │ (awareness) │ │ (headers/body) │ │ (forward) │ │
|
|
61
|
+
│ └─────────────────┘ └─────────────────┘ └──────────────┘ │
|
|
62
|
+
│ │ │
|
|
63
|
+
│ ▼ │
|
|
64
|
+
│ ┌──────────────────┐ │
|
|
65
|
+
│ │ Target Service │ │
|
|
66
|
+
│ │ (Microservice) │ │
|
|
67
|
+
│ └──────────────────┘ │
|
|
68
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Stage Details
|
|
72
|
+
|
|
73
|
+
### 1. SOAJS Initialization
|
|
74
|
+
|
|
75
|
+
**Middleware:** `mw/soajs/index.js`
|
|
76
|
+
|
|
77
|
+
- Creates `req.soajs` object
|
|
78
|
+
- Attaches registry reference
|
|
79
|
+
- Sets up logging context
|
|
80
|
+
- Initializes controller params
|
|
81
|
+
|
|
82
|
+
### 2. Security Checks
|
|
83
|
+
|
|
84
|
+
**Middlewares:** `mw/cors`, `mw/ip2ban`, `mw/maintenanceMode`
|
|
85
|
+
|
|
86
|
+
- CORS preflight handling
|
|
87
|
+
- IP blacklist enforcement
|
|
88
|
+
- Maintenance mode check
|
|
89
|
+
|
|
90
|
+
### 3. URL Parsing
|
|
91
|
+
|
|
92
|
+
**Middleware:** `mw/url/index.js`
|
|
93
|
+
|
|
94
|
+
- Extracts service name from URL path
|
|
95
|
+
- Parses version number (if provided)
|
|
96
|
+
- Extracts API path
|
|
97
|
+
|
|
98
|
+
### 4. Service Discovery
|
|
99
|
+
|
|
100
|
+
**Middleware:** `mw/awareness/index.js`
|
|
101
|
+
|
|
102
|
+
- Attaches `getHost()` and `getLatestVersion()` functions
|
|
103
|
+
- Supports both custom and HA modes
|
|
104
|
+
|
|
105
|
+
### 5. Tenant Resolution
|
|
106
|
+
|
|
107
|
+
**Middlewares:** `mw/key`, `mw/keyACL`
|
|
108
|
+
|
|
109
|
+
- Loads external key data
|
|
110
|
+
- Validates key for environment
|
|
111
|
+
- Extracts ACL from package or application
|
|
112
|
+
|
|
113
|
+
### 6. Security Pipeline
|
|
114
|
+
|
|
115
|
+
**Middleware:** `mw/mt/index.js`
|
|
116
|
+
|
|
117
|
+
- IP whitelist validation
|
|
118
|
+
- Geo-location checks
|
|
119
|
+
- Device fingerprint verification
|
|
120
|
+
- ACL enforcement
|
|
121
|
+
- OAuth token validation
|
|
122
|
+
|
|
123
|
+
### 7. Traffic Control
|
|
124
|
+
|
|
125
|
+
**Middleware:** `mw/traffic/index.js`
|
|
126
|
+
|
|
127
|
+
- Rate limiting per strategy
|
|
128
|
+
- Response headers (X-RateLimit-*)
|
|
129
|
+
|
|
130
|
+
### 8. Proxy to Service
|
|
131
|
+
|
|
132
|
+
**Middleware:** `mw/gotoService/*`
|
|
133
|
+
|
|
134
|
+
- Resolves target host
|
|
135
|
+
- Builds proxy request
|
|
136
|
+
- Forwards to microservice
|
|
137
|
+
- Returns response to client
|
|
138
|
+
|
|
139
|
+
## Configuration Model
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
┌─────────────────────────────────────────────────────────────────────────────────┐
|
|
143
|
+
│ CONFIGURATION HIERARCHY │
|
|
144
|
+
└─────────────────────────────────────────────────────────────────────────────────┘
|
|
145
|
+
|
|
146
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
147
|
+
│ ENVIRONMENT VARIABLES (Highest Priority) │
|
|
148
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
149
|
+
│ SOAJS_ENV │ Environment code (default: "dev") │
|
|
150
|
+
│ SOAJS_SOLO │ Solo mode flag (local registry) │
|
|
151
|
+
│ SOAJS_DEPLOY_HA │ HA mode: "kubernetes" | "swarm" │
|
|
152
|
+
│ SOAJS_MAX_BODY_SIZE │ Max request body (default: 10MB) │
|
|
153
|
+
│ SOAJS_SENSITIVE_ENVS │ Sensitive env codes (default: ["dashboard"]) │
|
|
154
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
155
|
+
│
|
|
156
|
+
▼
|
|
157
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
158
|
+
│ SERVICE CONFIGURATION │
|
|
159
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
160
|
+
│ config.js │ Service metadata (name, version, port) │
|
|
161
|
+
│ profiles/single.js │ MongoDB connection profile │
|
|
162
|
+
│ profiles/solo.js │ Local file-based profile │
|
|
163
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
164
|
+
│
|
|
165
|
+
▼
|
|
166
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
167
|
+
│ REGISTRY (from Core DB) │
|
|
168
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
169
|
+
│ services │ Service definitions (ports, hosts, versions) │
|
|
170
|
+
│ serviceConfig │ Global configs (throttling, CORS, OAuth) │
|
|
171
|
+
│ custom.gateway │ Gateway-specific settings │
|
|
172
|
+
│ dbs │ Database connection configs │
|
|
173
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
174
|
+
│
|
|
175
|
+
▼
|
|
176
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
177
|
+
│ TENANT/APPLICATION (Lowest Priority) │
|
|
178
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
179
|
+
│ Tenant.application │ App-specific OAuth, ACL overrides │
|
|
180
|
+
│ Package.acl │ Package-level access control │
|
|
181
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Rate Limiting Architecture
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
┌─────────────────────────────────────────────────────────────────────────────────┐
|
|
188
|
+
│ RATE LIMITING (THROTTLING) │
|
|
189
|
+
└─────────────────────────────────────────────────────────────────────────────────┘
|
|
190
|
+
|
|
191
|
+
┌────────────────────────────────────────────────────────────────────────────┐
|
|
192
|
+
│ STRATEGY SELECTION │
|
|
193
|
+
│ │
|
|
194
|
+
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
|
|
195
|
+
│ │ publicAPIStrategy │ │ privateAPIStrategy │ │
|
|
196
|
+
│ │ (Unauthenticated) │ │ (Authenticated) │ │
|
|
197
|
+
│ └───────────┬─────────────┘ └───────────┬─────────────┘ │
|
|
198
|
+
│ │ │ │
|
|
199
|
+
│ └──────────────┬───────────────────┘ │
|
|
200
|
+
│ ▼ │
|
|
201
|
+
└──────────────────────────────┬─────────────────────────────────────────────┘
|
|
202
|
+
│
|
|
203
|
+
▼
|
|
204
|
+
┌────────────────────────────────────────────────────────────────────────────┐
|
|
205
|
+
│ CONFIGURATION CASCADE │
|
|
206
|
+
│ │
|
|
207
|
+
│ 1. Service-specific: gateway.throttling │
|
|
208
|
+
│ 2. Custom registry: gateway.value.traffic.throttling │
|
|
209
|
+
│ 3. Global default: serviceConfig.throttling │
|
|
210
|
+
└──────────────────────────────┬─────────────────────────────────────────────┘
|
|
211
|
+
│
|
|
212
|
+
▼
|
|
213
|
+
┌────────────────────────────────────────────────────────────────────────────┐
|
|
214
|
+
│ STORAGE BACKENDS │
|
|
215
|
+
│ │
|
|
216
|
+
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
|
|
217
|
+
│ │ Memory │ │ MongoDB │ │
|
|
218
|
+
│ │ (Fast, volatile) │ │ (Persistent, shared) │ │
|
|
219
|
+
│ └─────────────────────────┘ └─────────────────────────┘ │
|
|
220
|
+
└──────────────────────────────┬─────────────────────────────────────────────┘
|
|
221
|
+
│
|
|
222
|
+
▼
|
|
223
|
+
┌────────────────────────────────────────────────────────────────────────────┐
|
|
224
|
+
│ RESPONSE HEADERS │
|
|
225
|
+
│ │
|
|
226
|
+
│ X-RateLimit-Limit │ Maximum requests allowed │
|
|
227
|
+
│ X-RateLimit-Remaining │ Requests remaining in window │
|
|
228
|
+
│ Retry-After │ Seconds until window resets │
|
|
229
|
+
└────────────────────────────────────────────────────────────────────────────┘
|
|
230
|
+
```
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Service Discovery Modes
|
|
2
|
+
|
|
3
|
+
The SOAJS Controller Gateway supports two service discovery modes: Custom (non-Kubernetes) and HA (Kubernetes/Docker Swarm).
|
|
4
|
+
|
|
5
|
+
## Discovery Modes Overview
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────────────────────────────────────────────────────────────────┐
|
|
9
|
+
│ SERVICE DISCOVERY MODES │
|
|
10
|
+
└─────────────────────────────────────────────────────────────────────────────────┘
|
|
11
|
+
|
|
12
|
+
┌─────────────────────────────────┐ ┌──────────────────────────────────────────┐
|
|
13
|
+
│ CUSTOM MODE │ │ HA MODE │
|
|
14
|
+
│ (Non-Kubernetes) │ │ (Kubernetes / Docker Swarm) │
|
|
15
|
+
├─────────────────────────────────┤ ├──────────────────────────────────────────┤
|
|
16
|
+
│ │ │ │
|
|
17
|
+
│ ┌─────────────────────────┐ │ │ ┌──────────────────────────────────┐ │
|
|
18
|
+
│ │ Registry DB │ │ │ │ Cluster API │ │
|
|
19
|
+
│ │ (MongoDB/Local) │ │ │ │ (K8s API / Docker API) │ │
|
|
20
|
+
│ └───────────┬─────────────┘ │ │ └────────────────┬─────────────────┘ │
|
|
21
|
+
│ │ │ │ │ │
|
|
22
|
+
│ ▼ │ │ ▼ │
|
|
23
|
+
│ ┌─────────────────────────┐ │ │ ┌──────────────────────────────────┐ │
|
|
24
|
+
│ │ Static Host List │ │ │ │ Dynamic Service Discovery │ │
|
|
25
|
+
│ │ per Service/Version │ │ │ │ via Labels/Selectors │ │
|
|
26
|
+
│ └───────────┬─────────────┘ │ │ └────────────────┬─────────────────┘ │
|
|
27
|
+
│ │ │ │ │ │
|
|
28
|
+
│ ▼ │ │ ▼ │
|
|
29
|
+
│ ┌─────────────────────────┐ │ │ ┌──────────────────────────────────┐ │
|
|
30
|
+
│ │ In-Memory Health │ │ │ │ Automatic Health Monitoring │ │
|
|
31
|
+
│ │ State Tracking │ │ │ │ via Pod/Container Status │ │
|
|
32
|
+
│ └───────────┬─────────────┘ │ │ └────────────────┬─────────────────┘ │
|
|
33
|
+
│ │ │ │ │ │
|
|
34
|
+
│ ▼ │ │ ▼ │
|
|
35
|
+
│ ┌─────────────────────────┐ │ │ ┌──────────────────────────────────┐ │
|
|
36
|
+
│ │ Round-Robin │ │ │ │ Cluster Load Balancing │ │
|
|
37
|
+
│ │ Selection │ │ │ │ (via Service/Ingress) │ │
|
|
38
|
+
│ └─────────────────────────┘ │ │ └──────────────────────────────────┘ │
|
|
39
|
+
│ │ │ │
|
|
40
|
+
└─────────────────────────────────┘ └──────────────────────────────────────────┘
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Custom Mode
|
|
44
|
+
|
|
45
|
+
Used when running outside of container orchestration platforms.
|
|
46
|
+
|
|
47
|
+
### Configuration
|
|
48
|
+
|
|
49
|
+
Set via environment variable:
|
|
50
|
+
```bash
|
|
51
|
+
# Do not set SOAJS_DEPLOY_HA, or set it to empty
|
|
52
|
+
unset SOAJS_DEPLOY_HA
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### How it Works
|
|
56
|
+
|
|
57
|
+
1. **Registry Loading**: Service hosts are loaded from MongoDB registry
|
|
58
|
+
2. **Host List**: Static list of hosts per service/version
|
|
59
|
+
3. **Health Tracking**: In-memory state tracking with heartbeat
|
|
60
|
+
4. **Load Balancing**: Round-robin selection among healthy hosts
|
|
61
|
+
|
|
62
|
+
### Registry Structure
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
// In environment registry
|
|
66
|
+
{
|
|
67
|
+
"services": {
|
|
68
|
+
"oauth": {
|
|
69
|
+
"port": 4002,
|
|
70
|
+
"hosts": {
|
|
71
|
+
"1": ["host1.local", "host2.local"],
|
|
72
|
+
"2": ["host3.local"]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## HA Mode (Kubernetes)
|
|
80
|
+
|
|
81
|
+
Used when running in Kubernetes.
|
|
82
|
+
|
|
83
|
+
### Configuration
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
export SOAJS_DEPLOY_HA=kubernetes
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### How it Works
|
|
90
|
+
|
|
91
|
+
1. **API Discovery**: Uses Kubernetes API to discover services
|
|
92
|
+
2. **Label Selectors**: Finds pods via SOAJS labels
|
|
93
|
+
3. **Health Monitoring**: Leverages pod readiness/liveness probes
|
|
94
|
+
4. **Load Balancing**: Can use Kubernetes Service or direct pod access
|
|
95
|
+
|
|
96
|
+
### Kubernetes Labels
|
|
97
|
+
|
|
98
|
+
SOAJS uses these labels to discover services:
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
metadata:
|
|
102
|
+
labels:
|
|
103
|
+
soajs.env.code: dev
|
|
104
|
+
soajs.service.name: oauth
|
|
105
|
+
soajs.service.version: "1"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## HA Mode (Docker Swarm)
|
|
109
|
+
|
|
110
|
+
Used when running in Docker Swarm.
|
|
111
|
+
|
|
112
|
+
### Configuration
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
export SOAJS_DEPLOY_HA=swarm
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### How it Works
|
|
119
|
+
|
|
120
|
+
1. **API Discovery**: Uses Docker Swarm API to discover services
|
|
121
|
+
2. **Label Selectors**: Finds tasks via SOAJS labels
|
|
122
|
+
3. **Health Monitoring**: Leverages task health checks
|
|
123
|
+
4. **Load Balancing**: Can use Swarm service mesh or direct task access
|
|
124
|
+
|
|
125
|
+
## Awareness Middleware
|
|
126
|
+
|
|
127
|
+
**File:** `mw/awareness/index.js`
|
|
128
|
+
|
|
129
|
+
The awareness middleware attaches helper functions to the request:
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
req.soajs.awareness = {
|
|
133
|
+
getHost: function(serviceName, version, callback) {
|
|
134
|
+
// Returns host:port for the service
|
|
135
|
+
},
|
|
136
|
+
getLatestVersion: function(serviceName, callback) {
|
|
137
|
+
// Returns latest available version
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Cross-Environment Awareness
|
|
143
|
+
|
|
144
|
+
**File:** `mw/awarenessEnv/index.js`
|
|
145
|
+
|
|
146
|
+
For roaming requests that need to access services in other environments:
|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
req.soajs.awarenessEnv = {
|
|
150
|
+
getHost: function(envCode, serviceName, version, callback) {
|
|
151
|
+
// Returns host:port for service in specified environment
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Driver Module
|
|
157
|
+
|
|
158
|
+
**File:** `modules/driver/index.js`
|
|
159
|
+
|
|
160
|
+
The driver module abstracts infrastructure-specific operations:
|
|
161
|
+
|
|
162
|
+
| Method | Description |
|
|
163
|
+
|--------|-------------|
|
|
164
|
+
| `getServiceHosts()` | Get all hosts for a service |
|
|
165
|
+
| `getServiceHost()` | Get a single host (load balanced) |
|
|
166
|
+
| `getLatestVersion()` | Get latest version number |
|
|
167
|
+
| `getInfo()` | Get node/container info |
|
package/mw/key/index.js
CHANGED
|
@@ -8,13 +8,15 @@
|
|
|
8
8
|
* found in the LICENSE file at the root of this repository
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
const get = (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o);
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
*
|
|
13
15
|
* @param {object} configuration {provision,regEnvironment}
|
|
14
16
|
* @returns {Function}
|
|
15
17
|
*/
|
|
16
18
|
module.exports = (configuration) => {
|
|
17
|
-
|
|
19
|
+
|
|
18
20
|
return (req, res, next) => {
|
|
19
21
|
let key = req.get("key");
|
|
20
22
|
if (key) {
|
|
@@ -34,6 +36,19 @@ module.exports = (configuration) => {
|
|
|
34
36
|
return next(144);
|
|
35
37
|
}
|
|
36
38
|
}
|
|
39
|
+
|
|
40
|
+
// Check for network-based package override
|
|
41
|
+
let network = get(["soajs", "registry", "custom", "gateway", "value", "lastSeen", "network"], req);
|
|
42
|
+
if (network) {
|
|
43
|
+
let product = keyObj.application.product;
|
|
44
|
+
let networkPackageConfig = get(["config", "gateway", "networkPackages", network, product], keyObj);
|
|
45
|
+
if (networkPackageConfig && networkPackageConfig.default) {
|
|
46
|
+
let originalPackage = keyObj.application.package;
|
|
47
|
+
keyObj.application.package = networkPackageConfig.default;
|
|
48
|
+
req.soajs.log.debug("Network package override: replaced package [" + originalPackage + "] with [" + networkPackageConfig.default + "] for network [" + network + "] and product [" + product + "]");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
37
52
|
configuration.provision.getPackageData(keyObj.application.package, function (err, packObj) {
|
|
38
53
|
if (err) {
|
|
39
54
|
req.soajs.log.error("Unable to fetch data about package [" + keyObj.application.package + "]");
|
package/mw/mt/urac.js
CHANGED
|
@@ -14,6 +14,8 @@ let provision = coreModules.provision;
|
|
|
14
14
|
|
|
15
15
|
const lib = require("./lib.js");
|
|
16
16
|
|
|
17
|
+
const get = (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o);
|
|
18
|
+
|
|
17
19
|
function Urac(param) {
|
|
18
20
|
let _self = this;
|
|
19
21
|
|
|
@@ -101,7 +103,25 @@ Urac.prototype.resolveACL = function (cb) {
|
|
|
101
103
|
let productCode = _self.soajs.tenant.application.product;
|
|
102
104
|
if (_self.userRecord.groupsConfig && _self.userRecord.groupsConfig.allowedPackages) {
|
|
103
105
|
if (_self.userRecord.groupsConfig.allowedPackages[productCode]) {
|
|
104
|
-
|
|
106
|
+
let allowedPackages = _self.userRecord.groupsConfig.allowedPackages[productCode].slice();
|
|
107
|
+
|
|
108
|
+
// Check for user-specific network package override
|
|
109
|
+
let network = get(["registry", "custom", "gateway", "value", "lastSeen", "network"], _self.soajs);
|
|
110
|
+
if (network) {
|
|
111
|
+
let keyObj = get(["controller", "serviceParams", "keyObj"], _self.soajs);
|
|
112
|
+
let networkPackageConfig = get(["config", "gateway", "networkPackages", network, productCode], keyObj);
|
|
113
|
+
if (networkPackageConfig && networkPackageConfig.users) {
|
|
114
|
+
for (let i = 0; i < allowedPackages.length; i++) {
|
|
115
|
+
if (networkPackageConfig.users[allowedPackages[i]]) {
|
|
116
|
+
let originalPackage = allowedPackages[i];
|
|
117
|
+
allowedPackages[i] = networkPackageConfig.users[allowedPackages[i]];
|
|
118
|
+
_self.soajs.log.debug("User network package override: replaced package [" + originalPackage + "] with [" + allowedPackages[i] + "] for network [" + network + "] and product [" + productCode + "]");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
provision.getPackagesData(allowedPackages, (error, arrayACLs) => {
|
|
105
125
|
if (error) {
|
|
106
126
|
return cb();
|
|
107
127
|
} else {
|
package/mw/mt/utils.js
CHANGED
|
@@ -632,6 +632,8 @@ let utils = {
|
|
|
632
632
|
obj.req.soajs.log.error(error.message, error.code);
|
|
633
633
|
return cb(146);
|
|
634
634
|
}
|
|
635
|
+
//NOTE: if the user changes the account's email or phone and validateTokenAccount is set to true,
|
|
636
|
+
// kick the user out to force re login. i.e. the username behaviour is similar by default
|
|
635
637
|
if (obj.keyObj.config && obj.keyObj.config.gateway && obj.keyObj.config.gateway.validateTokenAccount) {
|
|
636
638
|
if (obj.req.soajs.uracDriver.bearerTokenUser && record) {
|
|
637
639
|
if (obj.keyObj.config.gateway.validateTokenAccount.email && record.email) {
|