tiny-ca-gateway 0.1.0__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.
- tiny_ca_gateway-0.1.0/LICENSE +54 -0
- tiny_ca_gateway-0.1.0/PKG-INFO +233 -0
- tiny_ca_gateway-0.1.0/README.md +181 -0
- tiny_ca_gateway-0.1.0/pyproject.toml +288 -0
- tiny_ca_gateway-0.1.0/setup.cfg +4 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/aiohttp/api/v1/ca_routes.py +546 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/aiohttp/lifespan/manager.py +11 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/core/__init__.py +71 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/core/auth.py +26 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/core/base_manager.py +162 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/core/helpers.py +110 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/core/routes.py +41 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/core/schemas.py +179 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/core/summary.py +26 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/db.py +63 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/django/api/v1/ca_router.py +594 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/django/lifespan/manager.py +5 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/fastapi/api/v1/__init__.py +1 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/fastapi/api/v1/ca_routes.py +580 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/fastapi/api/v1/utils.py +87 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/fastapi/auth/__init__.py +0 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/fastapi/auth/verify.py +61 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/fastapi/lifespan/__init__.py +3 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/fastapi/lifespan/manager.py +7 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/flask/api/v1/ca_blueprint.py +629 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/flask/lifespan/manager.py +5 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/models.py +79 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/openapi.py +536 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway/utils/singleton.py +27 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway.egg-info/PKG-INFO +233 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway.egg-info/SOURCES.txt +32 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway.egg-info/dependency_links.txt +1 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway.egg-info/requires.txt +28 -0
- tiny_ca_gateway-0.1.0/tiny_ca_gateway.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Denis Shchutskyi (Shchusia)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Dependency Notice
|
|
26
|
+
|
|
27
|
+
This package is built on top of **tiny-ca** by Denis Shchutskyi (Shchusia),
|
|
28
|
+
also distributed under the MIT License.
|
|
29
|
+
See: https://github.com/Shchusia/tiny_ca
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Third-Party Licenses
|
|
34
|
+
|
|
35
|
+
This software uses the following open source dependencies:
|
|
36
|
+
|
|
37
|
+
### Core
|
|
38
|
+
- **tiny-ca** (MIT) - https://github.com/Shchusia/tiny_ca
|
|
39
|
+
- **cryptography** (BSD 3-Clause) - https://github.com/pyca/cryptography
|
|
40
|
+
- **SQLAlchemy** (MIT) - https://github.com/sqlalchemy/sqlalchemy
|
|
41
|
+
- **Pydantic** (MIT) - https://github.com/pydantic/pydantic
|
|
42
|
+
- **aiosqlite** (MIT) - https://github.com/omnilib/aiosqlite
|
|
43
|
+
- **aiofiles** (Apache 2.0) - https://github.com/Tinche/aiofiles
|
|
44
|
+
|
|
45
|
+
### Optional framework dependencies
|
|
46
|
+
- **FastAPI** (MIT) - https://github.com/tiangolo/fastapi
|
|
47
|
+
- **Starlette** (BSD 3-Clause) - https://github.com/encode/starlette
|
|
48
|
+
- **Uvicorn** (BSD 3-Clause) - https://github.com/encode/uvicorn
|
|
49
|
+
- **Flask** (BSD 3-Clause) - https://github.com/pallets/flask
|
|
50
|
+
- **Werkzeug** (BSD 3-Clause) - https://github.com/pallets/werkzeug
|
|
51
|
+
- **aiohttp** (Apache 2.0) - https://github.com/aio-libs/aiohttp
|
|
52
|
+
- **Django** (BSD 3-Clause) - https://github.com/django/django
|
|
53
|
+
- **django-ninja** (MIT) - https://github.com/vitalik/django-ninja
|
|
54
|
+
- **Gunicorn** (MIT) - https://github.com/benoitc/gunicorn
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tiny-ca-gateway
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Framework-agnostic REST API routes for tiny-ca — supports FastAPI, Flask, aiohttp and Django Ninja
|
|
5
|
+
Author-email: Denis Shchutskyi <denisshchutskyi@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Shchusia/tiny-ca-gateway
|
|
8
|
+
Project-URL: Documentation, https://github.com/Shchusia/tiny-ca-gateway/blob/master/README.md
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/Shchusia/tiny-ca-gateway/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/Shchusia/tiny-ca-gateway/blob/master/CHANGELOG.md
|
|
11
|
+
Keywords: certificate-authority,pki,ca,tls,ssl,fastapi,flask,aiohttp,django,rest,api
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
19
|
+
Classifier: Topic :: Security :: Cryptography
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Framework :: FastAPI
|
|
22
|
+
Classifier: Framework :: Flask
|
|
23
|
+
Classifier: Framework :: Django
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.12
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: gunicorn>=26.0.0
|
|
29
|
+
Requires-Dist: pydantic>=2.13.3
|
|
30
|
+
Requires-Dist: pydantic-settings>=2.14.0
|
|
31
|
+
Requires-Dist: tiny-ca[async]>=0.2.0
|
|
32
|
+
Requires-Dist: aiofiles>=23.0.0
|
|
33
|
+
Requires-Dist: cryptography>=42.0.0
|
|
34
|
+
Provides-Extra: fastapi
|
|
35
|
+
Requires-Dist: fastapi>=0.136.1; extra == "fastapi"
|
|
36
|
+
Requires-Dist: uvicorn[standard]>=0.29.0; extra == "fastapi"
|
|
37
|
+
Provides-Extra: django
|
|
38
|
+
Requires-Dist: django>=6.0.5; extra == "django"
|
|
39
|
+
Requires-Dist: django-ninja>=1.6.2; extra == "django"
|
|
40
|
+
Provides-Extra: flask
|
|
41
|
+
Requires-Dist: flask>=3.1.3; extra == "flask"
|
|
42
|
+
Provides-Extra: aiohttp
|
|
43
|
+
Requires-Dist: aiohttp>=3.13.5; extra == "aiohttp"
|
|
44
|
+
Provides-Extra: all
|
|
45
|
+
Requires-Dist: fastapi>=0.136.1; extra == "all"
|
|
46
|
+
Requires-Dist: uvicorn[standard]>=0.29.0; extra == "all"
|
|
47
|
+
Requires-Dist: django>=6.0.5; extra == "all"
|
|
48
|
+
Requires-Dist: django-ninja>=1.6.2; extra == "all"
|
|
49
|
+
Requires-Dist: flask>=3.1.3; extra == "all"
|
|
50
|
+
Requires-Dist: aiohttp>=3.13.5; extra == "all"
|
|
51
|
+
Dynamic: license-file
|
|
52
|
+
|
|
53
|
+
# tiny-ca-gateway
|
|
54
|
+
|
|
55
|
+
[](https://pypi.org/project/tiny-ca-gateway/)
|
|
56
|
+
[](https://pypi.org/project/tiny-ca-gateway/)
|
|
57
|
+
[](LICENSE)
|
|
58
|
+
|
|
59
|
+
**tiny-ca-gateway** provides ready-to-use REST API routes for [tiny-ca](https://github.com/Shchusia/tiny_ca) — a lightweight Python Certificate Authority library. Mount a full-featured CA HTTP API into any of your existing applications in minutes.
|
|
60
|
+
|
|
61
|
+
> **Built on top of [tiny-ca](https://github.com/Shchusia/tiny_ca).** This package only provides the HTTP layer. For CA internals, certificate issuance logic, and database models, see the [tiny-ca documentation](https://github.com/Shchusia/tiny_ca).
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Features
|
|
66
|
+
|
|
67
|
+
- **22 REST endpoints** — issue, revoke, renew, rotate, verify, download certificates and more
|
|
68
|
+
- **4 framework adapters** — drop into an existing app without rewriting anything
|
|
69
|
+
- **Shared core** — identical behaviour across all frameworks; integration tests run against all of them
|
|
70
|
+
- **Bearer token auth** — optional, zero-config when `CA_API_TOKEN` is empty
|
|
71
|
+
- **OpenAPI / Swagger UI** — built-in for FastAPI & Django Ninja; CDN-based for Flask & aiohttp
|
|
72
|
+
- **Async-native** — FastAPI, aiohttp and Django (ASGI) run fully async; Flask uses an asyncio bridge
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Supported frameworks
|
|
77
|
+
|
|
78
|
+
| Framework | Adapter | Integration guide |
|
|
79
|
+
|-----------|---------|------------------|
|
|
80
|
+
| **FastAPI** | `tiny_ca_gateway.fastapi` | [docs/fastapi.md](docs/fastapi.md) |
|
|
81
|
+
| **Flask** | `tiny_ca_gateway.flask` | [docs/flask.md](docs/flask.md) |
|
|
82
|
+
| **aiohttp** | `tiny_ca_gateway.aiohttp` | [docs/aiohttp.md](docs/aiohttp.md) |
|
|
83
|
+
| **Django Ninja** | `tiny_ca_gateway.django` | [docs/django.md](docs/django.md) |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Quick install
|
|
88
|
+
|
|
89
|
+
Install only what you need:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# FastAPI
|
|
93
|
+
pip install "tiny-ca-gateway[fastapi]"
|
|
94
|
+
|
|
95
|
+
# Flask
|
|
96
|
+
pip install "tiny-ca-gateway[flask]"
|
|
97
|
+
|
|
98
|
+
# aiohttp
|
|
99
|
+
pip install "tiny-ca-gateway[aiohttp]"
|
|
100
|
+
|
|
101
|
+
# Django + Django Ninja
|
|
102
|
+
pip install "tiny-ca-gateway[django]"
|
|
103
|
+
|
|
104
|
+
# Everything
|
|
105
|
+
pip install "tiny-ca-gateway[all]"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 60-second example
|
|
111
|
+
|
|
112
|
+
### FastAPI
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from fastapi import FastAPI
|
|
116
|
+
from contextlib import asynccontextmanager
|
|
117
|
+
from tiny_ca_gateway.fastapi.lifespan.manager import FastAPILifespanManager
|
|
118
|
+
from tiny_ca_gateway.fastapi.api.v1.ca_routes import router
|
|
119
|
+
|
|
120
|
+
@asynccontextmanager
|
|
121
|
+
async def lifespan(app: FastAPI):
|
|
122
|
+
await FastAPILifespanManager(common_name="My CA").on_startup()
|
|
123
|
+
yield
|
|
124
|
+
|
|
125
|
+
app = FastAPI(lifespan=lifespan)
|
|
126
|
+
app.include_router(router, prefix="/api/v1")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Flask
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from flask import Flask
|
|
133
|
+
from tiny_ca_gateway.flask.lifespan.manager import FlaskCAManager
|
|
134
|
+
from tiny_ca_gateway.flask.api.v1.ca_blueprint import ca_bp
|
|
135
|
+
|
|
136
|
+
def create_app():
|
|
137
|
+
app = Flask(__name__)
|
|
138
|
+
FlaskCAManager(common_name="My CA").init_sync()
|
|
139
|
+
app.register_blueprint(ca_bp, url_prefix="/api/v1/ca")
|
|
140
|
+
return app
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### aiohttp
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from aiohttp import web
|
|
147
|
+
from tiny_ca_gateway.aiohttp.lifespan.manager import AiohttpCAManager
|
|
148
|
+
from tiny_ca_gateway.aiohttp.api.v1.ca_routes import routes
|
|
149
|
+
|
|
150
|
+
async def lifespan(app):
|
|
151
|
+
await AiohttpCAManager(common_name="My CA").on_startup()
|
|
152
|
+
yield
|
|
153
|
+
|
|
154
|
+
app = web.Application()
|
|
155
|
+
app.cleanup_ctx.append(lifespan)
|
|
156
|
+
app.add_subapp("/api/v1/ca", web.Application())
|
|
157
|
+
app.router.add_routes(routes)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Django Ninja
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# urls.py
|
|
164
|
+
from ninja import NinjaAPI
|
|
165
|
+
from tiny_ca_gateway.django.api.v1.ca_router import ca_router
|
|
166
|
+
|
|
167
|
+
api = NinjaAPI()
|
|
168
|
+
api.add_router("/ca", ca_router)
|
|
169
|
+
|
|
170
|
+
urlpatterns = [path("api/v1/", api.urls)]
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Environment variables
|
|
176
|
+
|
|
177
|
+
| Variable | Default | Description |
|
|
178
|
+
|----------|---------|-------------|
|
|
179
|
+
| `CA_CERT_PATH` | `certs/ca.pem` | Path to the CA certificate |
|
|
180
|
+
| `CA_KEY_PATH` | `certs/ca.key` | Path to the CA private key |
|
|
181
|
+
| `CA_CRL_PATH` | `certs/crl.pem` | Path to the CRL file |
|
|
182
|
+
| `CA_CERTS_DIR` | `certs/` | Directory for issued certificates |
|
|
183
|
+
| `CA_DB_URL` | `sqlite+aiosqlite:///ca.db` | SQLAlchemy async database URL |
|
|
184
|
+
| `CA_API_TOKEN` | `""` | Bearer token — empty = open access |
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## API reference
|
|
189
|
+
|
|
190
|
+
All adapters expose the same 22 endpoints under the configured prefix:
|
|
191
|
+
|
|
192
|
+
| Method | Path | Auth | Description |
|
|
193
|
+
|--------|------|------|-------------|
|
|
194
|
+
| `GET` | `/cert` | ✗ | Download CA public certificate |
|
|
195
|
+
| `GET` | `/crl` | ✗ | Download CRL (DER or `?pem=true`) |
|
|
196
|
+
| `GET` | `/` | ✓ | List certificates |
|
|
197
|
+
| `GET` | `/expiring` | ✓ | Certificates expiring soon |
|
|
198
|
+
| `POST` | `/root` | ✓ | Bootstrap / replace root CA |
|
|
199
|
+
| `POST` | `/intermediate` | ✓ | Issue intermediate CA |
|
|
200
|
+
| `POST` | `/issue` | ✓ | Issue leaf certificate |
|
|
201
|
+
| `POST` | `/maintenance/expire` | ✓ | Mark expired certificates |
|
|
202
|
+
| `POST` | `/crl/refresh` | ✓ | Regenerate CRL |
|
|
203
|
+
| `POST` | `/crl/verify` | ✓ | Verify a CRL |
|
|
204
|
+
| `POST` | `/verify` | ✓ | Verify a certificate |
|
|
205
|
+
| `POST` | `/cosign` | ✓ | Co-sign an external certificate |
|
|
206
|
+
| `POST` | `/export-p12/{serial}` | ✓ | Export PKCS#12 bundle |
|
|
207
|
+
| `PATCH` | `/revoke` | ✓ | Revoke a certificate |
|
|
208
|
+
| `POST` | `/rotate/{serial}` | ✓ | Rotate (new key) |
|
|
209
|
+
| `POST` | `/renew/{serial}` | ✓ | Renew (same key, new validity) |
|
|
210
|
+
| `DELETE` | `/{serial}` | ✓ | Hard-delete certificate |
|
|
211
|
+
| `GET` | `/status/{serial}` | ✓ | Lifecycle status |
|
|
212
|
+
| `GET` | `/inspect/{serial}` | ✓ | Structured details |
|
|
213
|
+
| `GET` | `/chain/{serial}` | ✓ | Full PEM chain |
|
|
214
|
+
| `GET` | `/stream/{uuid}` | ✓ | Stream artefact (pem / key / csr) |
|
|
215
|
+
| `GET` | `/{uuid}` | ✓ | Download artefact |
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Running the integration tests
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# Start any backend first, then:
|
|
223
|
+
python tests/ca_integration_test.py --base-url http://localhost:8000
|
|
224
|
+
|
|
225
|
+
# Run against all frameworks automatically:
|
|
226
|
+
task run-all-tests TOKEN=mysecret
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# tiny-ca-gateway
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/tiny-ca-gateway/)
|
|
4
|
+
[](https://pypi.org/project/tiny-ca-gateway/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
**tiny-ca-gateway** provides ready-to-use REST API routes for [tiny-ca](https://github.com/Shchusia/tiny_ca) — a lightweight Python Certificate Authority library. Mount a full-featured CA HTTP API into any of your existing applications in minutes.
|
|
8
|
+
|
|
9
|
+
> **Built on top of [tiny-ca](https://github.com/Shchusia/tiny_ca).** This package only provides the HTTP layer. For CA internals, certificate issuance logic, and database models, see the [tiny-ca documentation](https://github.com/Shchusia/tiny_ca).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- **22 REST endpoints** — issue, revoke, renew, rotate, verify, download certificates and more
|
|
16
|
+
- **4 framework adapters** — drop into an existing app without rewriting anything
|
|
17
|
+
- **Shared core** — identical behaviour across all frameworks; integration tests run against all of them
|
|
18
|
+
- **Bearer token auth** — optional, zero-config when `CA_API_TOKEN` is empty
|
|
19
|
+
- **OpenAPI / Swagger UI** — built-in for FastAPI & Django Ninja; CDN-based for Flask & aiohttp
|
|
20
|
+
- **Async-native** — FastAPI, aiohttp and Django (ASGI) run fully async; Flask uses an asyncio bridge
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Supported frameworks
|
|
25
|
+
|
|
26
|
+
| Framework | Adapter | Integration guide |
|
|
27
|
+
|-----------|---------|------------------|
|
|
28
|
+
| **FastAPI** | `tiny_ca_gateway.fastapi` | [docs/fastapi.md](docs/fastapi.md) |
|
|
29
|
+
| **Flask** | `tiny_ca_gateway.flask` | [docs/flask.md](docs/flask.md) |
|
|
30
|
+
| **aiohttp** | `tiny_ca_gateway.aiohttp` | [docs/aiohttp.md](docs/aiohttp.md) |
|
|
31
|
+
| **Django Ninja** | `tiny_ca_gateway.django` | [docs/django.md](docs/django.md) |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Quick install
|
|
36
|
+
|
|
37
|
+
Install only what you need:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# FastAPI
|
|
41
|
+
pip install "tiny-ca-gateway[fastapi]"
|
|
42
|
+
|
|
43
|
+
# Flask
|
|
44
|
+
pip install "tiny-ca-gateway[flask]"
|
|
45
|
+
|
|
46
|
+
# aiohttp
|
|
47
|
+
pip install "tiny-ca-gateway[aiohttp]"
|
|
48
|
+
|
|
49
|
+
# Django + Django Ninja
|
|
50
|
+
pip install "tiny-ca-gateway[django]"
|
|
51
|
+
|
|
52
|
+
# Everything
|
|
53
|
+
pip install "tiny-ca-gateway[all]"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 60-second example
|
|
59
|
+
|
|
60
|
+
### FastAPI
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from fastapi import FastAPI
|
|
64
|
+
from contextlib import asynccontextmanager
|
|
65
|
+
from tiny_ca_gateway.fastapi.lifespan.manager import FastAPILifespanManager
|
|
66
|
+
from tiny_ca_gateway.fastapi.api.v1.ca_routes import router
|
|
67
|
+
|
|
68
|
+
@asynccontextmanager
|
|
69
|
+
async def lifespan(app: FastAPI):
|
|
70
|
+
await FastAPILifespanManager(common_name="My CA").on_startup()
|
|
71
|
+
yield
|
|
72
|
+
|
|
73
|
+
app = FastAPI(lifespan=lifespan)
|
|
74
|
+
app.include_router(router, prefix="/api/v1")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Flask
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from flask import Flask
|
|
81
|
+
from tiny_ca_gateway.flask.lifespan.manager import FlaskCAManager
|
|
82
|
+
from tiny_ca_gateway.flask.api.v1.ca_blueprint import ca_bp
|
|
83
|
+
|
|
84
|
+
def create_app():
|
|
85
|
+
app = Flask(__name__)
|
|
86
|
+
FlaskCAManager(common_name="My CA").init_sync()
|
|
87
|
+
app.register_blueprint(ca_bp, url_prefix="/api/v1/ca")
|
|
88
|
+
return app
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### aiohttp
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from aiohttp import web
|
|
95
|
+
from tiny_ca_gateway.aiohttp.lifespan.manager import AiohttpCAManager
|
|
96
|
+
from tiny_ca_gateway.aiohttp.api.v1.ca_routes import routes
|
|
97
|
+
|
|
98
|
+
async def lifespan(app):
|
|
99
|
+
await AiohttpCAManager(common_name="My CA").on_startup()
|
|
100
|
+
yield
|
|
101
|
+
|
|
102
|
+
app = web.Application()
|
|
103
|
+
app.cleanup_ctx.append(lifespan)
|
|
104
|
+
app.add_subapp("/api/v1/ca", web.Application())
|
|
105
|
+
app.router.add_routes(routes)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Django Ninja
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
# urls.py
|
|
112
|
+
from ninja import NinjaAPI
|
|
113
|
+
from tiny_ca_gateway.django.api.v1.ca_router import ca_router
|
|
114
|
+
|
|
115
|
+
api = NinjaAPI()
|
|
116
|
+
api.add_router("/ca", ca_router)
|
|
117
|
+
|
|
118
|
+
urlpatterns = [path("api/v1/", api.urls)]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Environment variables
|
|
124
|
+
|
|
125
|
+
| Variable | Default | Description |
|
|
126
|
+
|----------|---------|-------------|
|
|
127
|
+
| `CA_CERT_PATH` | `certs/ca.pem` | Path to the CA certificate |
|
|
128
|
+
| `CA_KEY_PATH` | `certs/ca.key` | Path to the CA private key |
|
|
129
|
+
| `CA_CRL_PATH` | `certs/crl.pem` | Path to the CRL file |
|
|
130
|
+
| `CA_CERTS_DIR` | `certs/` | Directory for issued certificates |
|
|
131
|
+
| `CA_DB_URL` | `sqlite+aiosqlite:///ca.db` | SQLAlchemy async database URL |
|
|
132
|
+
| `CA_API_TOKEN` | `""` | Bearer token — empty = open access |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## API reference
|
|
137
|
+
|
|
138
|
+
All adapters expose the same 22 endpoints under the configured prefix:
|
|
139
|
+
|
|
140
|
+
| Method | Path | Auth | Description |
|
|
141
|
+
|--------|------|------|-------------|
|
|
142
|
+
| `GET` | `/cert` | ✗ | Download CA public certificate |
|
|
143
|
+
| `GET` | `/crl` | ✗ | Download CRL (DER or `?pem=true`) |
|
|
144
|
+
| `GET` | `/` | ✓ | List certificates |
|
|
145
|
+
| `GET` | `/expiring` | ✓ | Certificates expiring soon |
|
|
146
|
+
| `POST` | `/root` | ✓ | Bootstrap / replace root CA |
|
|
147
|
+
| `POST` | `/intermediate` | ✓ | Issue intermediate CA |
|
|
148
|
+
| `POST` | `/issue` | ✓ | Issue leaf certificate |
|
|
149
|
+
| `POST` | `/maintenance/expire` | ✓ | Mark expired certificates |
|
|
150
|
+
| `POST` | `/crl/refresh` | ✓ | Regenerate CRL |
|
|
151
|
+
| `POST` | `/crl/verify` | ✓ | Verify a CRL |
|
|
152
|
+
| `POST` | `/verify` | ✓ | Verify a certificate |
|
|
153
|
+
| `POST` | `/cosign` | ✓ | Co-sign an external certificate |
|
|
154
|
+
| `POST` | `/export-p12/{serial}` | ✓ | Export PKCS#12 bundle |
|
|
155
|
+
| `PATCH` | `/revoke` | ✓ | Revoke a certificate |
|
|
156
|
+
| `POST` | `/rotate/{serial}` | ✓ | Rotate (new key) |
|
|
157
|
+
| `POST` | `/renew/{serial}` | ✓ | Renew (same key, new validity) |
|
|
158
|
+
| `DELETE` | `/{serial}` | ✓ | Hard-delete certificate |
|
|
159
|
+
| `GET` | `/status/{serial}` | ✓ | Lifecycle status |
|
|
160
|
+
| `GET` | `/inspect/{serial}` | ✓ | Structured details |
|
|
161
|
+
| `GET` | `/chain/{serial}` | ✓ | Full PEM chain |
|
|
162
|
+
| `GET` | `/stream/{uuid}` | ✓ | Stream artefact (pem / key / csr) |
|
|
163
|
+
| `GET` | `/{uuid}` | ✓ | Download artefact |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Running the integration tests
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Start any backend first, then:
|
|
171
|
+
python tests/ca_integration_test.py --base-url http://localhost:8000
|
|
172
|
+
|
|
173
|
+
# Run against all frameworks automatically:
|
|
174
|
+
task run-all-tests TOKEN=mysecret
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT — see [LICENSE](LICENSE).
|