sentinel-api 1.0.3__tar.gz
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.
- sentinel_api-1.0.3/PKG-INFO +286 -0
- sentinel_api-1.0.3/README.md +252 -0
- sentinel_api-1.0.3/pyproject.toml +66 -0
- sentinel_api-1.0.3/setup.cfg +4 -0
- sentinel_api-1.0.3/src/sentinel_api/__init__.py +17 -0
- sentinel_api-1.0.3/src/sentinel_api/config.py +228 -0
- sentinel_api-1.0.3/src/sentinel_api/main.py +137 -0
- sentinel_api-1.0.3/src/sentinel_api/models/security.py +7 -0
- sentinel_api-1.0.3/src/sentinel_api/sdk_deployer.py +629 -0
- sentinel_api-1.0.3/src/sentinel_api/services/auth.py +127 -0
- sentinel_api-1.0.3/src/sentinel_api/services/dynamodb_rate_limiter.py +98 -0
- sentinel_api-1.0.3/src/sentinel_api/services/memory_rate_limiter.py +57 -0
- sentinel_api-1.0.3/src/sentinel_api/services/proxy.py +51 -0
- sentinel_api-1.0.3/src/sentinel_api/services/rate_limiter.py +86 -0
- sentinel_api-1.0.3/src/sentinel_api/services/rate_limiter_base.py +16 -0
- sentinel_api-1.0.3/src/sentinel_api/services/request_logger.py +166 -0
- sentinel_api-1.0.3/src/sentinel_api.egg-info/PKG-INFO +286 -0
- sentinel_api-1.0.3/src/sentinel_api.egg-info/SOURCES.txt +27 -0
- sentinel_api-1.0.3/src/sentinel_api.egg-info/dependency_links.txt +1 -0
- sentinel_api-1.0.3/src/sentinel_api.egg-info/requires.txt +14 -0
- sentinel_api-1.0.3/src/sentinel_api.egg-info/top_level.txt +1 -0
- sentinel_api-1.0.3/tests/test_anomaly_detector.py +171 -0
- sentinel_api-1.0.3/tests/test_auth.py +75 -0
- sentinel_api-1.0.3/tests/test_auth_routes.py +30 -0
- sentinel_api-1.0.3/tests/test_health.py +14 -0
- sentinel_api-1.0.3/tests/test_proxy_integration.py +142 -0
- sentinel_api-1.0.3/tests/test_rate_limiter_backends.py +221 -0
- sentinel_api-1.0.3/tests/test_request_logger.py +138 -0
- sentinel_api-1.0.3/tests/test_sdk_deployer.py +87 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sentinel-api
|
|
3
|
+
Version: 1.0.3
|
|
4
|
+
Summary: Intelligent API Gateway with rate limiting and anomaly detection
|
|
5
|
+
Project-URL: Homepage, https://github.com/SamioneX/SentinelAPI
|
|
6
|
+
Project-URL: Repository, https://github.com/SamioneX/SentinelAPI
|
|
7
|
+
Project-URL: Issues, https://github.com/SamioneX/SentinelAPI/issues
|
|
8
|
+
Keywords: api-gateway,security,rate-limiting,anomaly-detection,aws
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Internet :: Proxy Servers
|
|
17
|
+
Classifier: Topic :: Security
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: fastapi>=0.115.0
|
|
22
|
+
Requires-Dist: uvicorn[standard]>=0.34.0
|
|
23
|
+
Requires-Dist: httpx>=0.28.0
|
|
24
|
+
Requires-Dist: redis>=5.2.0
|
|
25
|
+
Requires-Dist: boto3>=1.37.0
|
|
26
|
+
Requires-Dist: python-jose[cryptography]>=3.3.0
|
|
27
|
+
Requires-Dist: pydantic-settings>=2.7.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=8.3.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.25.0; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.11.0; extra == "dev"
|
|
32
|
+
Requires-Dist: build>=1.2.2; extra == "dev"
|
|
33
|
+
Requires-Dist: twine>=6.0.1; extra == "dev"
|
|
34
|
+
|
|
35
|
+
# SentinelAPI
|
|
36
|
+
|
|
37
|
+
SentinelAPI is an intelligent API gateway that provides JWT auth, per-user rate limiting, structured request telemetry, and scheduled anomaly detection with auto-blocking.
|
|
38
|
+
|
|
39
|
+
## Why no Amazon Lookout for Metrics?
|
|
40
|
+
|
|
41
|
+
We intentionally do not implement Lookout for Metrics because it is not practical for free-tier testing in this project. Instead, anomaly detection is implemented with a scheduled Lambda on DynamoDB aggregates, with SNS alerting and optional auto-blocking.
|
|
42
|
+
|
|
43
|
+
## Architecture
|
|
44
|
+
|
|
45
|
+
SentinelAPI uses one cloud-native architecture:
|
|
46
|
+
- ECS Fargate service behind an ALB
|
|
47
|
+
- ElastiCache Redis for token-bucket rate limiting
|
|
48
|
+
- DynamoDB for request logs, aggregates, and blocklist state
|
|
49
|
+
- EventBridge schedule -> Lambda anomaly detector -> SNS alerts
|
|
50
|
+
- Fargate tasks in public subnets, no NAT gateway
|
|
51
|
+
|
|
52
|
+
## Optimization Presets
|
|
53
|
+
|
|
54
|
+
SentinelAPI supports optional optimization presets in code:
|
|
55
|
+
- `cost` (default)
|
|
56
|
+
- `performance`
|
|
57
|
+
|
|
58
|
+
Set with:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
SENTINEL_API_OPTIMIZE_FOR=cost
|
|
62
|
+
# or
|
|
63
|
+
SENTINEL_API_OPTIMIZE_FOR=performance
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Preset values are defaults only. Any explicitly provided knob in shell env or `.env` overrides the preset.
|
|
67
|
+
|
|
68
|
+
## Environment File
|
|
69
|
+
|
|
70
|
+
`.env` is optional. SentinelAPI SDK deploy reads:
|
|
71
|
+
1. System environment variables
|
|
72
|
+
2. `.env` in repo root (if present)
|
|
73
|
+
|
|
74
|
+
Required:
|
|
75
|
+
- `SENTINEL_API_UPSTREAM_BASE_URL`
|
|
76
|
+
- at least one auth method:
|
|
77
|
+
- `SENTINEL_API_JWT_SECRET_KEY` (HS*)
|
|
78
|
+
- `SENTINEL_API_JWT_PUBLIC_KEY` (static public key)
|
|
79
|
+
- `SENTINEL_API_JWT_JWKS_URL` (OIDC/JWKS)
|
|
80
|
+
|
|
81
|
+
Optional:
|
|
82
|
+
- `SENTINEL_API_OPTIMIZE_FOR`
|
|
83
|
+
- explicit knob overrides (Fargate sizing, desired count, rate/anomaly knobs, timeouts, JWT algorithm)
|
|
84
|
+
|
|
85
|
+
Precedence:
|
|
86
|
+
1. Explicit shell/CI env vars
|
|
87
|
+
2. `.env` (if present)
|
|
88
|
+
3. Built-in preset defaults (`cost` or `performance`)
|
|
89
|
+
|
|
90
|
+
## One-Command AWS Deploy (SDK Full Stack)
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
./deploy.sh
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## One-Command AWS Teardown
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
./teardown.sh
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Requirements:
|
|
103
|
+
- AWS credentials configured locally
|
|
104
|
+
- Docker installed and running (used to build and push gateway image)
|
|
105
|
+
|
|
106
|
+
Before deploy, set `SENTINEL_API_UPSTREAM_BASE_URL` in `.env` to the backend you want SentinelAPI to protect.
|
|
107
|
+
You can set it either in your shell/CI environment or in `.env`.
|
|
108
|
+
|
|
109
|
+
For the example Lambda backend, use the Function URL printed by:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
./examples/example-api/scripts/deploy.sh
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## JWT Configuration
|
|
116
|
+
|
|
117
|
+
SentinelAPI does not auto-generate JWT verification keys.
|
|
118
|
+
You must provide auth settings via shell env or `.env` before deploy.
|
|
119
|
+
|
|
120
|
+
At least one is required:
|
|
121
|
+
- `SENTINEL_API_JWT_SECRET_KEY` for HS* verification
|
|
122
|
+
- `SENTINEL_API_JWT_PUBLIC_KEY` for static RS*/ES* public-key verification
|
|
123
|
+
- `SENTINEL_API_JWT_JWKS_URL` for JWKS-based verification (recommended)
|
|
124
|
+
|
|
125
|
+
## Local Testing and Linting
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
./scripts/test.sh
|
|
129
|
+
make lint
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Makefile Shortcuts
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
make lint
|
|
136
|
+
make test
|
|
137
|
+
make deploy
|
|
138
|
+
make teardown
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## CI/CD (GitHub Actions + OIDC)
|
|
142
|
+
|
|
143
|
+
Workflow file: `.github/workflows/deploy.yml`
|
|
144
|
+
|
|
145
|
+
On push to `main`:
|
|
146
|
+
1. `lint` job runs `ruff`
|
|
147
|
+
2. `test` job runs `pytest`
|
|
148
|
+
3. `validate_templates` job runs SDK dry-run plan
|
|
149
|
+
4. `deploy` job calls reusable integration workflow (`.github/workflows/integration-tests.yml`), deploys `SentinelSdkFull`, runs smoke checks, then always tears down Sentinel + example-api stacks
|
|
150
|
+
|
|
151
|
+
Required secret:
|
|
152
|
+
- `AWS_DEPLOY_ROLE_ARN`
|
|
153
|
+
- `SENTINEL_API_UPSTREAM_BASE_URL`
|
|
154
|
+
- `SENTINEL_API_JWT_SECRET_KEY`
|
|
155
|
+
|
|
156
|
+
## PyPI Release Pipeline
|
|
157
|
+
|
|
158
|
+
Workflow file: `.github/workflows/release.yml`
|
|
159
|
+
|
|
160
|
+
Trigger:
|
|
161
|
+
- push a tag like `v0.1.1`
|
|
162
|
+
- or run workflow manually from Actions tab
|
|
163
|
+
|
|
164
|
+
Pipeline stages:
|
|
165
|
+
1. lint + tests
|
|
166
|
+
2. build wheel/sdist + `twine check`
|
|
167
|
+
3. reusable integration tests (`.github/workflows/integration-tests.yml`)
|
|
168
|
+
4. publish to PyPI
|
|
169
|
+
|
|
170
|
+
Tag and push release:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
git tag v0.1.1
|
|
174
|
+
git push origin v0.1.1
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Required one-time setup:
|
|
178
|
+
1. Create project on PyPI (name: `sentinel-api`) or reserve the name.
|
|
179
|
+
2. In GitHub repo settings, add environment `pypi`.
|
|
180
|
+
3. In PyPI project settings, add a trusted publisher:
|
|
181
|
+
- Owner: `SamioneX`
|
|
182
|
+
- Repository: `SentinelAPI`
|
|
183
|
+
- Workflow: `release.yml`
|
|
184
|
+
- Environment: `pypi`
|
|
185
|
+
|
|
186
|
+
## Runtime Backends
|
|
187
|
+
|
|
188
|
+
SentinelAPI runtime uses fixed backends:
|
|
189
|
+
- rate limiting: Redis
|
|
190
|
+
- request logging: DynamoDB
|
|
191
|
+
|
|
192
|
+
## JWT Verification Modes
|
|
193
|
+
|
|
194
|
+
- Shared-secret/static-key mode:
|
|
195
|
+
- `SENTINEL_API_JWT_SECRET_KEY` (HS256) or `SENTINEL_API_JWT_PUBLIC_KEY`
|
|
196
|
+
- JWKS discovery mode:
|
|
197
|
+
- `SENTINEL_API_JWT_JWKS_URL`
|
|
198
|
+
- `SENTINEL_API_JWT_JWKS_CACHE_TTL_SECONDS`
|
|
199
|
+
|
|
200
|
+
When `SENTINEL_API_JWT_JWKS_URL` is set, JWKS key selection by token `kid` is used.
|
|
201
|
+
|
|
202
|
+
## JWT Testing Quickstart
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
python3 scripts/generate_jwt.py --env-file .env --user-id demo-user
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
TOKEN="$(python3 scripts/generate_jwt.py --env-file .env --user-id demo-user)"
|
|
210
|
+
curl -X GET "http://localhost:8000/auth/verify" \
|
|
211
|
+
-H "Authorization: Bearer ${TOKEN}"
|
|
212
|
+
|
|
213
|
+
curl -X GET "http://localhost:8000/proxy/v1/orders?limit=5" \
|
|
214
|
+
-H "Authorization: Bearer ${TOKEN}"
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Anomaly Detection Smoke Test
|
|
218
|
+
|
|
219
|
+
You can validate the anomaly pipeline end-to-end without waiting for the 15-minute schedule.
|
|
220
|
+
|
|
221
|
+
Requirements:
|
|
222
|
+
- Sentinel stack deployed
|
|
223
|
+
- example upstream reachable
|
|
224
|
+
- JWT secret available in env:
|
|
225
|
+
- `SMOKE_JWT_SECRET_KEY` (preferred), or
|
|
226
|
+
- `SENTINEL_API_JWT_SECRET_KEY`
|
|
227
|
+
|
|
228
|
+
Run:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
python3 scripts/anomaly_smoke.py --stack-name SentinelSdkFull --region us-east-1
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
What it does:
|
|
235
|
+
- seeds baseline traffic into aggregate buckets
|
|
236
|
+
- sends a burst of authenticated requests through the ALB
|
|
237
|
+
- invokes the anomaly Lambda directly
|
|
238
|
+
- checks that the user appears in the blocklist table
|
|
239
|
+
|
|
240
|
+
If needed, tune sensitivity in the command:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
python3 scripts/anomaly_smoke.py \
|
|
244
|
+
--stack-name SentinelSdkFull \
|
|
245
|
+
--region us-east-1 \
|
|
246
|
+
--baseline-hourly 10 \
|
|
247
|
+
--burst-requests 120
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Core Components
|
|
251
|
+
|
|
252
|
+
- API app: `src/sentinel_api/main.py`
|
|
253
|
+
- Auth: `src/sentinel_api/services/auth.py`
|
|
254
|
+
- Rate limiting: `src/sentinel_api/services/rate_limiter.py`
|
|
255
|
+
- Request logging: `src/sentinel_api/services/request_logger.py`
|
|
256
|
+
- Anomaly Lambda: `lambda/anomaly_detector/handler.py`
|
|
257
|
+
- SDK deploy library: `src/sentinel_api/sdk_deployer.py`
|
|
258
|
+
- SDK templates: `infrastructure/templates/foundation.yaml`, `infrastructure/templates/full.yaml`
|
|
259
|
+
|
|
260
|
+
## Example Backend
|
|
261
|
+
|
|
262
|
+
Use `examples/example-api` as an upstream target:
|
|
263
|
+
- deploy: `./examples/example-api/scripts/deploy.sh`
|
|
264
|
+
- destroy: `./examples/example-api/scripts/destroy.sh`
|
|
265
|
+
|
|
266
|
+
## InfraKit + SDK Strategy
|
|
267
|
+
|
|
268
|
+
SentinelAPI uses an SDK-native deploy model designed to align with InfraKit's lean approach and avoid CDK runtime dependency.
|
|
269
|
+
|
|
270
|
+
- migration docs: `infrastructure/README.md`
|
|
271
|
+
- parity tracker: `infrastructure/PARITY_CHECKLIST.md`
|
|
272
|
+
- full stack deploy: `./deploy.sh`
|
|
273
|
+
- full stack teardown: `./teardown.sh`
|
|
274
|
+
- foundation deploy: `python3 infrastructure/deploy.py --stack-name SentinelSdkFoundation --region us-east-1`
|
|
275
|
+
- foundation teardown: `python3 infrastructure/teardown.py --stack-name SentinelSdkFoundation --region us-east-1`
|
|
276
|
+
|
|
277
|
+
Importable API (for InfraKit/provider integration):
|
|
278
|
+
- `from sentinel_api import deploy_foundation, deploy_full, teardown_foundation`
|
|
279
|
+
|
|
280
|
+
## Adoption Docs and Templates
|
|
281
|
+
|
|
282
|
+
- Product-style onboarding: `USAGE.md`
|
|
283
|
+
- Proposed InfraKit custom resource contract: `infrakit/resource-spec.md`
|
|
284
|
+
- InfraKit templates:
|
|
285
|
+
- `infrakit/templates/sentinelapi-minimal.yaml`
|
|
286
|
+
- `infrakit/templates/sentinelapi-production.yaml`
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# SentinelAPI
|
|
2
|
+
|
|
3
|
+
SentinelAPI is an intelligent API gateway that provides JWT auth, per-user rate limiting, structured request telemetry, and scheduled anomaly detection with auto-blocking.
|
|
4
|
+
|
|
5
|
+
## Why no Amazon Lookout for Metrics?
|
|
6
|
+
|
|
7
|
+
We intentionally do not implement Lookout for Metrics because it is not practical for free-tier testing in this project. Instead, anomaly detection is implemented with a scheduled Lambda on DynamoDB aggregates, with SNS alerting and optional auto-blocking.
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
SentinelAPI uses one cloud-native architecture:
|
|
12
|
+
- ECS Fargate service behind an ALB
|
|
13
|
+
- ElastiCache Redis for token-bucket rate limiting
|
|
14
|
+
- DynamoDB for request logs, aggregates, and blocklist state
|
|
15
|
+
- EventBridge schedule -> Lambda anomaly detector -> SNS alerts
|
|
16
|
+
- Fargate tasks in public subnets, no NAT gateway
|
|
17
|
+
|
|
18
|
+
## Optimization Presets
|
|
19
|
+
|
|
20
|
+
SentinelAPI supports optional optimization presets in code:
|
|
21
|
+
- `cost` (default)
|
|
22
|
+
- `performance`
|
|
23
|
+
|
|
24
|
+
Set with:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
SENTINEL_API_OPTIMIZE_FOR=cost
|
|
28
|
+
# or
|
|
29
|
+
SENTINEL_API_OPTIMIZE_FOR=performance
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Preset values are defaults only. Any explicitly provided knob in shell env or `.env` overrides the preset.
|
|
33
|
+
|
|
34
|
+
## Environment File
|
|
35
|
+
|
|
36
|
+
`.env` is optional. SentinelAPI SDK deploy reads:
|
|
37
|
+
1. System environment variables
|
|
38
|
+
2. `.env` in repo root (if present)
|
|
39
|
+
|
|
40
|
+
Required:
|
|
41
|
+
- `SENTINEL_API_UPSTREAM_BASE_URL`
|
|
42
|
+
- at least one auth method:
|
|
43
|
+
- `SENTINEL_API_JWT_SECRET_KEY` (HS*)
|
|
44
|
+
- `SENTINEL_API_JWT_PUBLIC_KEY` (static public key)
|
|
45
|
+
- `SENTINEL_API_JWT_JWKS_URL` (OIDC/JWKS)
|
|
46
|
+
|
|
47
|
+
Optional:
|
|
48
|
+
- `SENTINEL_API_OPTIMIZE_FOR`
|
|
49
|
+
- explicit knob overrides (Fargate sizing, desired count, rate/anomaly knobs, timeouts, JWT algorithm)
|
|
50
|
+
|
|
51
|
+
Precedence:
|
|
52
|
+
1. Explicit shell/CI env vars
|
|
53
|
+
2. `.env` (if present)
|
|
54
|
+
3. Built-in preset defaults (`cost` or `performance`)
|
|
55
|
+
|
|
56
|
+
## One-Command AWS Deploy (SDK Full Stack)
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
./deploy.sh
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## One-Command AWS Teardown
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
./teardown.sh
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Requirements:
|
|
69
|
+
- AWS credentials configured locally
|
|
70
|
+
- Docker installed and running (used to build and push gateway image)
|
|
71
|
+
|
|
72
|
+
Before deploy, set `SENTINEL_API_UPSTREAM_BASE_URL` in `.env` to the backend you want SentinelAPI to protect.
|
|
73
|
+
You can set it either in your shell/CI environment or in `.env`.
|
|
74
|
+
|
|
75
|
+
For the example Lambda backend, use the Function URL printed by:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
./examples/example-api/scripts/deploy.sh
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## JWT Configuration
|
|
82
|
+
|
|
83
|
+
SentinelAPI does not auto-generate JWT verification keys.
|
|
84
|
+
You must provide auth settings via shell env or `.env` before deploy.
|
|
85
|
+
|
|
86
|
+
At least one is required:
|
|
87
|
+
- `SENTINEL_API_JWT_SECRET_KEY` for HS* verification
|
|
88
|
+
- `SENTINEL_API_JWT_PUBLIC_KEY` for static RS*/ES* public-key verification
|
|
89
|
+
- `SENTINEL_API_JWT_JWKS_URL` for JWKS-based verification (recommended)
|
|
90
|
+
|
|
91
|
+
## Local Testing and Linting
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
./scripts/test.sh
|
|
95
|
+
make lint
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Makefile Shortcuts
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
make lint
|
|
102
|
+
make test
|
|
103
|
+
make deploy
|
|
104
|
+
make teardown
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## CI/CD (GitHub Actions + OIDC)
|
|
108
|
+
|
|
109
|
+
Workflow file: `.github/workflows/deploy.yml`
|
|
110
|
+
|
|
111
|
+
On push to `main`:
|
|
112
|
+
1. `lint` job runs `ruff`
|
|
113
|
+
2. `test` job runs `pytest`
|
|
114
|
+
3. `validate_templates` job runs SDK dry-run plan
|
|
115
|
+
4. `deploy` job calls reusable integration workflow (`.github/workflows/integration-tests.yml`), deploys `SentinelSdkFull`, runs smoke checks, then always tears down Sentinel + example-api stacks
|
|
116
|
+
|
|
117
|
+
Required secret:
|
|
118
|
+
- `AWS_DEPLOY_ROLE_ARN`
|
|
119
|
+
- `SENTINEL_API_UPSTREAM_BASE_URL`
|
|
120
|
+
- `SENTINEL_API_JWT_SECRET_KEY`
|
|
121
|
+
|
|
122
|
+
## PyPI Release Pipeline
|
|
123
|
+
|
|
124
|
+
Workflow file: `.github/workflows/release.yml`
|
|
125
|
+
|
|
126
|
+
Trigger:
|
|
127
|
+
- push a tag like `v0.1.1`
|
|
128
|
+
- or run workflow manually from Actions tab
|
|
129
|
+
|
|
130
|
+
Pipeline stages:
|
|
131
|
+
1. lint + tests
|
|
132
|
+
2. build wheel/sdist + `twine check`
|
|
133
|
+
3. reusable integration tests (`.github/workflows/integration-tests.yml`)
|
|
134
|
+
4. publish to PyPI
|
|
135
|
+
|
|
136
|
+
Tag and push release:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
git tag v0.1.1
|
|
140
|
+
git push origin v0.1.1
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Required one-time setup:
|
|
144
|
+
1. Create project on PyPI (name: `sentinel-api`) or reserve the name.
|
|
145
|
+
2. In GitHub repo settings, add environment `pypi`.
|
|
146
|
+
3. In PyPI project settings, add a trusted publisher:
|
|
147
|
+
- Owner: `SamioneX`
|
|
148
|
+
- Repository: `SentinelAPI`
|
|
149
|
+
- Workflow: `release.yml`
|
|
150
|
+
- Environment: `pypi`
|
|
151
|
+
|
|
152
|
+
## Runtime Backends
|
|
153
|
+
|
|
154
|
+
SentinelAPI runtime uses fixed backends:
|
|
155
|
+
- rate limiting: Redis
|
|
156
|
+
- request logging: DynamoDB
|
|
157
|
+
|
|
158
|
+
## JWT Verification Modes
|
|
159
|
+
|
|
160
|
+
- Shared-secret/static-key mode:
|
|
161
|
+
- `SENTINEL_API_JWT_SECRET_KEY` (HS256) or `SENTINEL_API_JWT_PUBLIC_KEY`
|
|
162
|
+
- JWKS discovery mode:
|
|
163
|
+
- `SENTINEL_API_JWT_JWKS_URL`
|
|
164
|
+
- `SENTINEL_API_JWT_JWKS_CACHE_TTL_SECONDS`
|
|
165
|
+
|
|
166
|
+
When `SENTINEL_API_JWT_JWKS_URL` is set, JWKS key selection by token `kid` is used.
|
|
167
|
+
|
|
168
|
+
## JWT Testing Quickstart
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
python3 scripts/generate_jwt.py --env-file .env --user-id demo-user
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
TOKEN="$(python3 scripts/generate_jwt.py --env-file .env --user-id demo-user)"
|
|
176
|
+
curl -X GET "http://localhost:8000/auth/verify" \
|
|
177
|
+
-H "Authorization: Bearer ${TOKEN}"
|
|
178
|
+
|
|
179
|
+
curl -X GET "http://localhost:8000/proxy/v1/orders?limit=5" \
|
|
180
|
+
-H "Authorization: Bearer ${TOKEN}"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Anomaly Detection Smoke Test
|
|
184
|
+
|
|
185
|
+
You can validate the anomaly pipeline end-to-end without waiting for the 15-minute schedule.
|
|
186
|
+
|
|
187
|
+
Requirements:
|
|
188
|
+
- Sentinel stack deployed
|
|
189
|
+
- example upstream reachable
|
|
190
|
+
- JWT secret available in env:
|
|
191
|
+
- `SMOKE_JWT_SECRET_KEY` (preferred), or
|
|
192
|
+
- `SENTINEL_API_JWT_SECRET_KEY`
|
|
193
|
+
|
|
194
|
+
Run:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
python3 scripts/anomaly_smoke.py --stack-name SentinelSdkFull --region us-east-1
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
What it does:
|
|
201
|
+
- seeds baseline traffic into aggregate buckets
|
|
202
|
+
- sends a burst of authenticated requests through the ALB
|
|
203
|
+
- invokes the anomaly Lambda directly
|
|
204
|
+
- checks that the user appears in the blocklist table
|
|
205
|
+
|
|
206
|
+
If needed, tune sensitivity in the command:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
python3 scripts/anomaly_smoke.py \
|
|
210
|
+
--stack-name SentinelSdkFull \
|
|
211
|
+
--region us-east-1 \
|
|
212
|
+
--baseline-hourly 10 \
|
|
213
|
+
--burst-requests 120
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Core Components
|
|
217
|
+
|
|
218
|
+
- API app: `src/sentinel_api/main.py`
|
|
219
|
+
- Auth: `src/sentinel_api/services/auth.py`
|
|
220
|
+
- Rate limiting: `src/sentinel_api/services/rate_limiter.py`
|
|
221
|
+
- Request logging: `src/sentinel_api/services/request_logger.py`
|
|
222
|
+
- Anomaly Lambda: `lambda/anomaly_detector/handler.py`
|
|
223
|
+
- SDK deploy library: `src/sentinel_api/sdk_deployer.py`
|
|
224
|
+
- SDK templates: `infrastructure/templates/foundation.yaml`, `infrastructure/templates/full.yaml`
|
|
225
|
+
|
|
226
|
+
## Example Backend
|
|
227
|
+
|
|
228
|
+
Use `examples/example-api` as an upstream target:
|
|
229
|
+
- deploy: `./examples/example-api/scripts/deploy.sh`
|
|
230
|
+
- destroy: `./examples/example-api/scripts/destroy.sh`
|
|
231
|
+
|
|
232
|
+
## InfraKit + SDK Strategy
|
|
233
|
+
|
|
234
|
+
SentinelAPI uses an SDK-native deploy model designed to align with InfraKit's lean approach and avoid CDK runtime dependency.
|
|
235
|
+
|
|
236
|
+
- migration docs: `infrastructure/README.md`
|
|
237
|
+
- parity tracker: `infrastructure/PARITY_CHECKLIST.md`
|
|
238
|
+
- full stack deploy: `./deploy.sh`
|
|
239
|
+
- full stack teardown: `./teardown.sh`
|
|
240
|
+
- foundation deploy: `python3 infrastructure/deploy.py --stack-name SentinelSdkFoundation --region us-east-1`
|
|
241
|
+
- foundation teardown: `python3 infrastructure/teardown.py --stack-name SentinelSdkFoundation --region us-east-1`
|
|
242
|
+
|
|
243
|
+
Importable API (for InfraKit/provider integration):
|
|
244
|
+
- `from sentinel_api import deploy_foundation, deploy_full, teardown_foundation`
|
|
245
|
+
|
|
246
|
+
## Adoption Docs and Templates
|
|
247
|
+
|
|
248
|
+
- Product-style onboarding: `USAGE.md`
|
|
249
|
+
- Proposed InfraKit custom resource contract: `infrakit/resource-spec.md`
|
|
250
|
+
- InfraKit templates:
|
|
251
|
+
- `infrakit/templates/sentinelapi-minimal.yaml`
|
|
252
|
+
- `infrakit/templates/sentinelapi-production.yaml`
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "sentinel-api"
|
|
3
|
+
version = "1.0.3"
|
|
4
|
+
description = "Intelligent API Gateway with rate limiting and anomaly detection"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
keywords = ["api-gateway", "security", "rate-limiting", "anomaly-detection", "aws"]
|
|
8
|
+
classifiers = [
|
|
9
|
+
"Development Status :: 3 - Alpha",
|
|
10
|
+
"Intended Audience :: Developers",
|
|
11
|
+
"Operating System :: OS Independent",
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
14
|
+
"Programming Language :: Python :: 3.11",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
"Topic :: Internet :: Proxy Servers",
|
|
17
|
+
"Topic :: Security",
|
|
18
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"fastapi>=0.115.0",
|
|
22
|
+
"uvicorn[standard]>=0.34.0",
|
|
23
|
+
"httpx>=0.28.0",
|
|
24
|
+
"redis>=5.2.0",
|
|
25
|
+
"boto3>=1.37.0",
|
|
26
|
+
"python-jose[cryptography]>=3.3.0",
|
|
27
|
+
"pydantic-settings>=2.7.0"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/SamioneX/SentinelAPI"
|
|
32
|
+
Repository = "https://github.com/SamioneX/SentinelAPI"
|
|
33
|
+
Issues = "https://github.com/SamioneX/SentinelAPI/issues"
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
dev = [
|
|
37
|
+
"pytest>=8.3.0",
|
|
38
|
+
"pytest-asyncio>=0.25.0",
|
|
39
|
+
"ruff>=0.11.0",
|
|
40
|
+
"build>=1.2.2",
|
|
41
|
+
"twine>=6.0.1"
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[build-system]
|
|
45
|
+
requires = ["setuptools>=69", "wheel"]
|
|
46
|
+
build-backend = "setuptools.build_meta"
|
|
47
|
+
|
|
48
|
+
[tool.setuptools]
|
|
49
|
+
package-dir = {"" = "src"}
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.packages.find]
|
|
52
|
+
where = ["src"]
|
|
53
|
+
|
|
54
|
+
[tool.pytest.ini_options]
|
|
55
|
+
pythonpath = ["src"]
|
|
56
|
+
asyncio_mode = "auto"
|
|
57
|
+
testpaths = ["tests"]
|
|
58
|
+
norecursedirs = [".git", ".venv"]
|
|
59
|
+
|
|
60
|
+
[tool.ruff]
|
|
61
|
+
line-length = 100
|
|
62
|
+
target-version = "py311"
|
|
63
|
+
|
|
64
|
+
[tool.ruff.lint]
|
|
65
|
+
select = ["E", "F", "I", "B"]
|
|
66
|
+
ignore = ["B008"]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""SentinelAPI package exports."""
|
|
2
|
+
|
|
3
|
+
from sentinel_api.sdk_deployer import (
|
|
4
|
+
deploy_foundation,
|
|
5
|
+
deploy_full,
|
|
6
|
+
deploy_stack,
|
|
7
|
+
teardown_foundation,
|
|
8
|
+
teardown_stack,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"deploy_foundation",
|
|
13
|
+
"deploy_full",
|
|
14
|
+
"deploy_stack",
|
|
15
|
+
"teardown_foundation",
|
|
16
|
+
"teardown_stack",
|
|
17
|
+
]
|