certmesh 3.0.2__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.
- certmesh-3.0.2/.gitignore +207 -0
- certmesh-3.0.2/LICENSE +21 -0
- certmesh-3.0.2/PKG-INFO +403 -0
- certmesh-3.0.2/README.md +340 -0
- certmesh-3.0.2/helm/certmesh/templates/tests/test-connection.yaml +15 -0
- certmesh-3.0.2/pyproject.toml +165 -0
- certmesh-3.0.2/src/certmesh/__init__.py +32 -0
- certmesh-3.0.2/src/certmesh/acm_client.py +3 -0
- certmesh-3.0.2/src/certmesh/api/__init__.py +1 -0
- certmesh-3.0.2/src/certmesh/api/app.py +137 -0
- certmesh-3.0.2/src/certmesh/api/auth.py +193 -0
- certmesh-3.0.2/src/certmesh/api/metrics.py +45 -0
- certmesh-3.0.2/src/certmesh/api/middleware.py +131 -0
- certmesh-3.0.2/src/certmesh/api/routes/__init__.py +1 -0
- certmesh-3.0.2/src/certmesh/api/routes/acm.py +131 -0
- certmesh-3.0.2/src/certmesh/api/routes/digicert.py +155 -0
- certmesh-3.0.2/src/certmesh/api/routes/health.py +63 -0
- certmesh-3.0.2/src/certmesh/api/routes/vault_pki.py +117 -0
- certmesh-3.0.2/src/certmesh/api/routes/venafi.py +55 -0
- certmesh-3.0.2/src/certmesh/api/schemas.py +198 -0
- certmesh-3.0.2/src/certmesh/backends/__init__.py +1 -0
- certmesh-3.0.2/src/certmesh/backends/route53_client.py +128 -0
- certmesh-3.0.2/src/certmesh/backends/secrets_manager_client.py +174 -0
- certmesh-3.0.2/src/certmesh/backends/vault_client.py +732 -0
- certmesh-3.0.2/src/certmesh/certificate_utils.py +436 -0
- certmesh-3.0.2/src/certmesh/circuit_breaker.py +141 -0
- certmesh-3.0.2/src/certmesh/cli.py +1204 -0
- certmesh-3.0.2/src/certmesh/config_loader.py +24 -0
- certmesh-3.0.2/src/certmesh/credentials.py +132 -0
- certmesh-3.0.2/src/certmesh/digicert_client.py +3 -0
- certmesh-3.0.2/src/certmesh/exceptions.py +281 -0
- certmesh-3.0.2/src/certmesh/letsencrypt_client.py +3 -0
- certmesh-3.0.2/src/certmesh/logging_config.py +83 -0
- certmesh-3.0.2/src/certmesh/providers/__init__.py +1 -0
- certmesh-3.0.2/src/certmesh/providers/acm_client.py +1034 -0
- certmesh-3.0.2/src/certmesh/providers/digicert_client.py +1291 -0
- certmesh-3.0.2/src/certmesh/providers/letsencrypt_client.py +329 -0
- certmesh-3.0.2/src/certmesh/providers/venafi_client.py +1301 -0
- certmesh-3.0.2/src/certmesh/py.typed +0 -0
- certmesh-3.0.2/src/certmesh/route53_client.py +3 -0
- certmesh-3.0.2/src/certmesh/secrets_manager_client.py +3 -0
- certmesh-3.0.2/src/certmesh/settings.py +571 -0
- certmesh-3.0.2/src/certmesh/vault_client.py +3 -0
- certmesh-3.0.2/src/certmesh/venafi_client.py +3 -0
- certmesh-3.0.2/tests/__init__.py +0 -0
- certmesh-3.0.2/tests/conftest.py +216 -0
- certmesh-3.0.2/tests/test_acm_client.py +1899 -0
- certmesh-3.0.2/tests/test_api/__init__.py +0 -0
- certmesh-3.0.2/tests/test_api/test_app.py +298 -0
- certmesh-3.0.2/tests/test_certificate_utils.py +175 -0
- certmesh-3.0.2/tests/test_circuit_breaker.py +150 -0
- certmesh-3.0.2/tests/test_cli.py +1106 -0
- certmesh-3.0.2/tests/test_credentials.py +100 -0
- certmesh-3.0.2/tests/test_digicert_client.py +1429 -0
- certmesh-3.0.2/tests/test_digicert_resilience.py +611 -0
- certmesh-3.0.2/tests/test_exceptions.py +71 -0
- certmesh-3.0.2/tests/test_letsencrypt_client.py +335 -0
- certmesh-3.0.2/tests/test_secrets_manager.py +411 -0
- certmesh-3.0.2/tests/test_settings.py +205 -0
- certmesh-3.0.2/tests/test_vault_client.py +284 -0
- certmesh-3.0.2/tests/test_vault_kv_v1.py +187 -0
- certmesh-3.0.2/tests/test_venafi_client.py +2468 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
#uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
#poetry.lock
|
|
109
|
+
#poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
#pdm.lock
|
|
116
|
+
#pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
#pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# SageMath parsed files
|
|
135
|
+
*.sage.py
|
|
136
|
+
|
|
137
|
+
# Environments
|
|
138
|
+
.env
|
|
139
|
+
.envrc
|
|
140
|
+
.venv
|
|
141
|
+
env/
|
|
142
|
+
venv/
|
|
143
|
+
ENV/
|
|
144
|
+
env.bak/
|
|
145
|
+
venv.bak/
|
|
146
|
+
|
|
147
|
+
# Spyder project settings
|
|
148
|
+
.spyderproject
|
|
149
|
+
.spyproject
|
|
150
|
+
|
|
151
|
+
# Rope project settings
|
|
152
|
+
.ropeproject
|
|
153
|
+
|
|
154
|
+
# mkdocs documentation
|
|
155
|
+
/site
|
|
156
|
+
|
|
157
|
+
# mypy
|
|
158
|
+
.mypy_cache/
|
|
159
|
+
.dmypy.json
|
|
160
|
+
dmypy.json
|
|
161
|
+
|
|
162
|
+
# Pyre type checker
|
|
163
|
+
.pyre/
|
|
164
|
+
|
|
165
|
+
# pytype static type analyzer
|
|
166
|
+
.pytype/
|
|
167
|
+
|
|
168
|
+
# Cython debug symbols
|
|
169
|
+
cython_debug/
|
|
170
|
+
|
|
171
|
+
# PyCharm
|
|
172
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
173
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
174
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
175
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
176
|
+
#.idea/
|
|
177
|
+
|
|
178
|
+
# Abstra
|
|
179
|
+
# Abstra is an AI-powered process automation framework.
|
|
180
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
181
|
+
# Learn more at https://abstra.io/docs
|
|
182
|
+
.abstra/
|
|
183
|
+
|
|
184
|
+
# Visual Studio Code
|
|
185
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
186
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
188
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
189
|
+
# .vscode/
|
|
190
|
+
|
|
191
|
+
# Ruff stuff:
|
|
192
|
+
.ruff_cache/
|
|
193
|
+
|
|
194
|
+
# PyPI configuration file
|
|
195
|
+
.pypirc
|
|
196
|
+
|
|
197
|
+
# Cursor
|
|
198
|
+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
|
199
|
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
|
200
|
+
# refer to https://docs.cursor.com/context/ignore-files
|
|
201
|
+
.cursorignore
|
|
202
|
+
.cursorindexingignore
|
|
203
|
+
|
|
204
|
+
# Marimo
|
|
205
|
+
marimo/_static/
|
|
206
|
+
marimo/_lsp/
|
|
207
|
+
__marimo__/
|
certmesh-3.0.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dejan Gregor
|
|
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.
|
certmesh-3.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: certmesh
|
|
3
|
+
Version: 3.0.2
|
|
4
|
+
Summary: Multi-provider TLS certificate lifecycle management — DigiCert, Venafi TPP, Vault PKI, ACM, Let's Encrypt
|
|
5
|
+
Project-URL: Homepage, https://github.com/SCGIS-Wales/certmesh
|
|
6
|
+
Project-URL: Repository, https://github.com/SCGIS-Wales/certmesh
|
|
7
|
+
Project-URL: Issues, https://github.com/SCGIS-Wales/certmesh/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/SCGIS-Wales/certmesh#readme
|
|
9
|
+
Project-URL: Changelog, https://github.com/SCGIS-Wales/certmesh/releases
|
|
10
|
+
Author-email: Dejan Gregor <sreengineer@users.noreply.github.com>
|
|
11
|
+
Maintainer-email: Dejan Gregor <sreengineer@users.noreply.github.com>
|
|
12
|
+
License-Expression: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: acm,acme,automation,certificate,certificate-management,cloud-native,devops,digicert,helm,infrastructure,kubernetes,letsencrypt,pki,security,ssl,tls,vault,venafi,x509
|
|
15
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
16
|
+
Classifier: Environment :: Console
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Intended Audience :: System Administrators
|
|
19
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
20
|
+
Classifier: Operating System :: MacOS
|
|
21
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
22
|
+
Classifier: Programming Language :: Python :: 3
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
28
|
+
Classifier: Topic :: Internet
|
|
29
|
+
Classifier: Topic :: Security :: Cryptography
|
|
30
|
+
Classifier: Topic :: System :: Systems Administration
|
|
31
|
+
Classifier: Topic :: Utilities
|
|
32
|
+
Classifier: Typing :: Typed
|
|
33
|
+
Requires-Python: >=3.10
|
|
34
|
+
Requires-Dist: acme>=2.0.0
|
|
35
|
+
Requires-Dist: boto3>=1.28.0
|
|
36
|
+
Requires-Dist: click>=8.1.0
|
|
37
|
+
Requires-Dist: cryptography>=41.0.0
|
|
38
|
+
Requires-Dist: fastapi>=0.115.0
|
|
39
|
+
Requires-Dist: gunicorn>=22.0.0
|
|
40
|
+
Requires-Dist: httpx>=0.27.0
|
|
41
|
+
Requires-Dist: hvac>=2.1.0
|
|
42
|
+
Requires-Dist: josepy>=1.13.0
|
|
43
|
+
Requires-Dist: prometheus-client>=0.20.0
|
|
44
|
+
Requires-Dist: pydantic>=2.0
|
|
45
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
46
|
+
Requires-Dist: python-jose[cryptography]>=3.3.0
|
|
47
|
+
Requires-Dist: python-json-logger>=2.0.0
|
|
48
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
49
|
+
Requires-Dist: requests>=2.31.0
|
|
50
|
+
Requires-Dist: slowapi>=0.1.9
|
|
51
|
+
Requires-Dist: tenacity>=8.2.0
|
|
52
|
+
Requires-Dist: uvicorn[standard]>=0.30.0
|
|
53
|
+
Provides-Extra: dev
|
|
54
|
+
Requires-Dist: freezegun>=1.3.0; extra == 'dev'
|
|
55
|
+
Requires-Dist: moto[acm,acm-pca,iam,secretsmanager,sts]>=4.2.0; extra == 'dev'
|
|
56
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
57
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
|
|
58
|
+
Requires-Dist: pytest-mock>=3.12.0; extra == 'dev'
|
|
59
|
+
Requires-Dist: pytest>=7.4.0; extra == 'dev'
|
|
60
|
+
Requires-Dist: responses>=0.24.0; extra == 'dev'
|
|
61
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
62
|
+
Description-Content-Type: text/markdown
|
|
63
|
+
|
|
64
|
+
[](https://pypi.org/project/certmesh/)
|
|
65
|
+
[](https://pypi.org/project/certmesh/)
|
|
66
|
+
[](https://github.com/SCGIS-Wales/certmesh/actions/workflows/ci.yml)
|
|
67
|
+
[](LICENSE)
|
|
68
|
+
|
|
69
|
+
# certmesh
|
|
70
|
+
|
|
71
|
+
Automated TLS certificate lifecycle management for Python 3.10+.
|
|
72
|
+
|
|
73
|
+
A unified CLI and Python API for managing certificates across **DigiCert CertCentral**, **Venafi Trust Protection Platform**, **HashiCorp Vault PKI**, and **AWS Certificate Manager** (public + private CA).
|
|
74
|
+
|
|
75
|
+
## Features
|
|
76
|
+
|
|
77
|
+
- **Multi-provider** -- single tool for DigiCert, Venafi TPP, Vault PKI, AWS ACM/ACM-PCA, and Let's Encrypt
|
|
78
|
+
- **Full lifecycle** -- request, list, search, describe, download, renew, revoke, and export certificates
|
|
79
|
+
- **REST API** -- production-grade FastAPI service with OAuth2 (ADFS / Azure Entra ID), Prometheus metrics
|
|
80
|
+
- **Credential security** -- secrets come from Vault (KV v1/v2) or environment variables, never from config files
|
|
81
|
+
- **Resilient** -- circuit breakers, exponential-backoff retry, and configurable timeouts on all HTTP calls
|
|
82
|
+
- **Configurable** -- layered config: built-in defaults < YAML file < `CM_*` environment variables
|
|
83
|
+
- **Cloud-native** -- Docker image, Helm chart for EKS with IRSA, NLB, HPA, and Vault PKI TLS
|
|
84
|
+
- **Typed** -- fully typed with `py.typed` marker; dataclass models for all API responses
|
|
85
|
+
|
|
86
|
+
## Installation
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pip install certmesh
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
From source:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git clone https://github.com/SCGIS-Wales/certmesh.git
|
|
96
|
+
cd certmesh
|
|
97
|
+
pip install -e ".[dev]"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Requires Python 3.10, 3.11, 3.12, 3.13, or 3.14.**
|
|
101
|
+
|
|
102
|
+
## Quick Start
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Show effective config
|
|
106
|
+
certmesh config show
|
|
107
|
+
|
|
108
|
+
# Issue a certificate from Vault PKI
|
|
109
|
+
certmesh vault-pki issue --cn myservice.example.com --ttl 720h
|
|
110
|
+
|
|
111
|
+
# Request a public ACM certificate
|
|
112
|
+
certmesh acm request --cn myapp.example.com --validation DNS
|
|
113
|
+
|
|
114
|
+
# List DigiCert certificates
|
|
115
|
+
certmesh digicert list --status issued
|
|
116
|
+
|
|
117
|
+
# Renew a Venafi TPP certificate
|
|
118
|
+
certmesh venafi renew --guid "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Configuration
|
|
122
|
+
|
|
123
|
+
Configuration is layered (lowest to highest precedence):
|
|
124
|
+
|
|
125
|
+
1. **Built-in defaults** -- sensible defaults for all settings
|
|
126
|
+
2. **YAML config file** -- `config/config.yaml` or `--config PATH`
|
|
127
|
+
3. **`CM_*` environment variables** -- override any setting
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Use a .env file
|
|
131
|
+
certmesh --env-file .env digicert list
|
|
132
|
+
|
|
133
|
+
# Override log level
|
|
134
|
+
certmesh --log-level DEBUG acm list
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
See [`config/config.yaml`](config/config.yaml) for the full annotated reference and [`.env.example`](.env.example) for all environment variables.
|
|
138
|
+
|
|
139
|
+
### Authentication
|
|
140
|
+
|
|
141
|
+
| Provider | Method |
|
|
142
|
+
|----------|--------|
|
|
143
|
+
| **Vault** | AppRole (default), LDAP, or AWS IAM |
|
|
144
|
+
| **DigiCert** | API key from `CM_DIGICERT_API_KEY` or Vault KV |
|
|
145
|
+
| **Venafi** | OAuth2 or LDAP; credentials from `CM_VENAFI_USERNAME`/`CM_VENAFI_PASSWORD` or Vault KV |
|
|
146
|
+
| **AWS ACM** | Standard boto3 credential chain (IAM role, env vars, `~/.aws/credentials`) |
|
|
147
|
+
| **Let's Encrypt** | ACME account key (auto-generated or provided) |
|
|
148
|
+
|
|
149
|
+
Credentials are resolved env-first, Vault-fallback. Vault is only contacted when needed.
|
|
150
|
+
|
|
151
|
+
## CLI Reference
|
|
152
|
+
|
|
153
|
+
Exit codes: `0` = success, `1` = config/auth error, `2` = cert operation error, `3` = unexpected error.
|
|
154
|
+
|
|
155
|
+
### DigiCert CertCentral
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
certmesh digicert list [--status TEXT] [--limit INT]
|
|
159
|
+
certmesh digicert search [--cn TEXT] [--serial TEXT] [--status TEXT] [--product TEXT]
|
|
160
|
+
certmesh digicert describe --cert-id INT
|
|
161
|
+
certmesh digicert order --cn TEXT [--san TEXT ...]
|
|
162
|
+
certmesh digicert download --cert-id INT --key-file PATH
|
|
163
|
+
certmesh digicert revoke --cert-id INT|--order-id INT [--reason CHOICE] [--comments TEXT]
|
|
164
|
+
certmesh digicert duplicate --order-id INT --csr-file PATH [--cn TEXT] [--san TEXT ...]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Venafi TPP
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
certmesh venafi list [--limit INT] [--offset INT]
|
|
171
|
+
certmesh venafi search [--cn TEXT] [--san TEXT]
|
|
172
|
+
certmesh venafi describe --guid TEXT
|
|
173
|
+
certmesh venafi request --policy-dn TEXT --cn TEXT [--san TEXT ...] [--client-csr]
|
|
174
|
+
certmesh venafi renew --guid TEXT
|
|
175
|
+
certmesh venafi renew-bulk --guid-file PATH
|
|
176
|
+
certmesh venafi revoke --dn TEXT|--thumbprint TEXT [--reason INT] [--disable]
|
|
177
|
+
certmesh venafi download --guid TEXT
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### HashiCorp Vault PKI
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
certmesh vault-pki issue --cn TEXT [--san TEXT ...] [--ip-san TEXT ...] [--ttl TEXT] [--output-dir PATH]
|
|
184
|
+
certmesh vault-pki sign --cn TEXT --csr-file PATH [--san TEXT ...] [--ttl TEXT] [--output-dir PATH]
|
|
185
|
+
certmesh vault-pki list
|
|
186
|
+
certmesh vault-pki read --serial TEXT
|
|
187
|
+
certmesh vault-pki revoke --serial TEXT
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### AWS ACM (Public Certificates)
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
certmesh acm request --cn TEXT [--san TEXT ...] [--validation DNS|EMAIL] [--key-algorithm TEXT] [--region TEXT]
|
|
194
|
+
certmesh acm list [--status TEXT ...] [--region TEXT]
|
|
195
|
+
certmesh acm describe --arn TEXT [--region TEXT]
|
|
196
|
+
certmesh acm export --arn TEXT --passphrase [--output-dir PATH] [--region TEXT]
|
|
197
|
+
certmesh acm renew --arn TEXT [--region TEXT]
|
|
198
|
+
certmesh acm delete --arn TEXT [--region TEXT]
|
|
199
|
+
certmesh acm validation-records --arn TEXT [--region TEXT]
|
|
200
|
+
certmesh acm wait --arn TEXT [--region TEXT]
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### AWS ACM Private CA
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
certmesh acm-pca issue --ca-arn TEXT --csr-file PATH [--validity-days INT] [--signing-algorithm TEXT] [--region TEXT]
|
|
207
|
+
certmesh acm-pca get --ca-arn TEXT --cert-arn TEXT [--region TEXT]
|
|
208
|
+
certmesh acm-pca revoke --ca-arn TEXT --cert-arn TEXT --cert-serial TEXT [--reason CHOICE] [--region TEXT]
|
|
209
|
+
certmesh acm-pca list --ca-arn TEXT [--region TEXT]
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Config Management
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
certmesh config show # Display effective merged config (secrets redacted)
|
|
216
|
+
certmesh config validate # Validate config; exits 0 on success, 1 on failure
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Architecture
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
certmesh/
|
|
223
|
+
cli.py -- Click CLI (entry point: certmesh.cli:cli)
|
|
224
|
+
settings.py -- Layered config: defaults -> YAML -> env vars
|
|
225
|
+
credentials.py -- Env-first, Vault-fallback secret resolution
|
|
226
|
+
certificate_utils.py -- Key gen, CSR, PKCS#12, bundle assembly, persistence
|
|
227
|
+
circuit_breaker.py -- Thread-safe CLOSED/OPEN/HALF_OPEN state machine
|
|
228
|
+
exceptions.py -- Full exception hierarchy
|
|
229
|
+
providers/
|
|
230
|
+
digicert_client.py -- DigiCert CertCentral API v2
|
|
231
|
+
venafi_client.py -- Venafi TPP API (OAuth2 + LDAP)
|
|
232
|
+
acm_client.py -- AWS ACM + ACM-PCA (boto3)
|
|
233
|
+
letsencrypt_client.py -- Let's Encrypt / ACME (RFC 8555)
|
|
234
|
+
backends/
|
|
235
|
+
vault_client.py -- Vault auth + KV v1/v2 + PKI engine
|
|
236
|
+
secrets_manager_client.py -- AWS Secrets Manager
|
|
237
|
+
route53_client.py -- Route53 DNS record management
|
|
238
|
+
api/
|
|
239
|
+
app.py -- FastAPI application factory
|
|
240
|
+
auth.py -- OAuth2 JWT Bearer validation
|
|
241
|
+
routes/ -- REST API endpoints
|
|
242
|
+
metrics.py -- Prometheus metrics
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Certificate Output
|
|
246
|
+
|
|
247
|
+
Issued certificates can be persisted to:
|
|
248
|
+
|
|
249
|
+
- **Filesystem** -- PEM files with private keys written mode `0600`
|
|
250
|
+
- **Vault KV v1/v2** -- certificate material stored as a KV secret (versioned or unversioned)
|
|
251
|
+
- **AWS Secrets Manager** -- certificate bundle stored as a JSON secret
|
|
252
|
+
- **Multiple destinations** -- any combination of the above
|
|
253
|
+
|
|
254
|
+
Configured per-provider via `output.destination` (list or legacy string: `filesystem`, `vault`, `secrets_manager`, or `both`).
|
|
255
|
+
|
|
256
|
+
## Development
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# Clone and install
|
|
260
|
+
git clone https://github.com/SCGIS-Wales/certmesh.git
|
|
261
|
+
cd certmesh
|
|
262
|
+
python -m venv .venv && source .venv/bin/activate
|
|
263
|
+
pip install -e ".[dev]"
|
|
264
|
+
|
|
265
|
+
# Run tests
|
|
266
|
+
pytest -v --cov=certmesh
|
|
267
|
+
|
|
268
|
+
# Lint and format
|
|
269
|
+
ruff check src/ tests/
|
|
270
|
+
ruff format src/ tests/
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Docker
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
docker build -t certmesh .
|
|
277
|
+
docker run --rm certmesh --help
|
|
278
|
+
|
|
279
|
+
# Run the REST API
|
|
280
|
+
docker run -p 8000:8000 -e CM_CONFIG_FILE=/app/config.yaml certmesh
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Helm Chart
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
helm install certmesh helm/certmesh \
|
|
287
|
+
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::123456789012:role/certmesh
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
See [`helm/certmesh/values.yaml`](helm/certmesh/values.yaml) for all configuration options.
|
|
291
|
+
|
|
292
|
+
### AWS IAM Permissions
|
|
293
|
+
|
|
294
|
+
When running on AWS (EKS with IRSA, EC2, or Lambda), the IAM role needs the following permissions depending on which features are enabled:
|
|
295
|
+
|
|
296
|
+
**AWS Certificate Manager (ACM)**
|
|
297
|
+
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"Effect": "Allow",
|
|
301
|
+
"Action": [
|
|
302
|
+
"acm:RequestCertificate",
|
|
303
|
+
"acm:DescribeCertificate",
|
|
304
|
+
"acm:ListCertificates",
|
|
305
|
+
"acm:DeleteCertificate",
|
|
306
|
+
"acm:RenewCertificate",
|
|
307
|
+
"acm:ExportCertificate",
|
|
308
|
+
"acm:GetCertificate",
|
|
309
|
+
"acm:ListTagsForCertificate",
|
|
310
|
+
"acm:AddTagsToCertificate"
|
|
311
|
+
],
|
|
312
|
+
"Resource": "*"
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**AWS ACM Private CA (ACM-PCA)**
|
|
317
|
+
|
|
318
|
+
```json
|
|
319
|
+
{
|
|
320
|
+
"Effect": "Allow",
|
|
321
|
+
"Action": [
|
|
322
|
+
"acm-pca:IssueCertificate",
|
|
323
|
+
"acm-pca:GetCertificate",
|
|
324
|
+
"acm-pca:RevokeCertificate",
|
|
325
|
+
"acm-pca:ListCertificateAuthorities",
|
|
326
|
+
"acm-pca:DescribeCertificateAuthority",
|
|
327
|
+
"acm-pca:GetCertificateAuthorityCertificate"
|
|
328
|
+
],
|
|
329
|
+
"Resource": "*"
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Route53 (ACM DNS Validation)**
|
|
334
|
+
|
|
335
|
+
```json
|
|
336
|
+
{
|
|
337
|
+
"Effect": "Allow",
|
|
338
|
+
"Action": [
|
|
339
|
+
"route53:ChangeResourceRecordSets",
|
|
340
|
+
"route53:ListHostedZones",
|
|
341
|
+
"route53:GetHostedZone",
|
|
342
|
+
"route53:ListResourceRecordSets"
|
|
343
|
+
],
|
|
344
|
+
"Resource": [
|
|
345
|
+
"arn:aws:route53:::hostedzone/*"
|
|
346
|
+
]
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**AWS Secrets Manager (Certificate Storage)**
|
|
351
|
+
|
|
352
|
+
```json
|
|
353
|
+
{
|
|
354
|
+
"Effect": "Allow",
|
|
355
|
+
"Action": [
|
|
356
|
+
"secretsmanager:CreateSecret",
|
|
357
|
+
"secretsmanager:PutSecretValue",
|
|
358
|
+
"secretsmanager:GetSecretValue",
|
|
359
|
+
"secretsmanager:DescribeSecret",
|
|
360
|
+
"secretsmanager:UpdateSecret",
|
|
361
|
+
"secretsmanager:TagResource"
|
|
362
|
+
],
|
|
363
|
+
"Resource": "arn:aws:secretsmanager:*:*:secret:certmesh/*"
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Vault AWS IAM Auth (STS)**
|
|
368
|
+
|
|
369
|
+
```json
|
|
370
|
+
{
|
|
371
|
+
"Effect": "Allow",
|
|
372
|
+
"Action": [
|
|
373
|
+
"sts:AssumeRole",
|
|
374
|
+
"sts:GetCallerIdentity"
|
|
375
|
+
],
|
|
376
|
+
"Resource": "*"
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
> **Tip:** For EKS deployments with IRSA, create a single IAM role with only the permissions you need, then reference it in your Helm values: `serviceAccount.annotations."eks.amazonaws.com/role-arn"`.
|
|
381
|
+
|
|
382
|
+
### Test Suite
|
|
383
|
+
|
|
384
|
+
- **538+ tests** across the test suite
|
|
385
|
+
- **87%+ coverage** (80% minimum enforced in CI)
|
|
386
|
+
- Tests use `pytest`, `pytest-mock`, `responses`, `moto`, and `freezegun`
|
|
387
|
+
|
|
388
|
+
### CI
|
|
389
|
+
|
|
390
|
+
GitHub Actions runs on every push and PR:
|
|
391
|
+
|
|
392
|
+
| Job | Matrix | Description |
|
|
393
|
+
|-----|--------|-------------|
|
|
394
|
+
| **lint** | Python 3.10 - 3.14 | `ruff check` + `ruff format --check` |
|
|
395
|
+
| **test** | Python 3.10 - 3.14 | `pytest` with coverage |
|
|
396
|
+
| **build** | Python 3.14 | `python -m build` + `twine check` |
|
|
397
|
+
| **docker-build** | - | Docker image build + smoke test |
|
|
398
|
+
| **auto-tag** | - | Auto-version bump and tag on merge to main |
|
|
399
|
+
| **publish-pypi** | - | Publish to PyPI via trusted publisher |
|
|
400
|
+
|
|
401
|
+
## License
|
|
402
|
+
|
|
403
|
+
MIT -- see [LICENSE](LICENSE) for details.
|