kong-deck-tools 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.
- kong_deck_tools-0.1.0/LICENSE +21 -0
- kong_deck_tools-0.1.0/PKG-INFO +144 -0
- kong_deck_tools-0.1.0/README.md +115 -0
- kong_deck_tools-0.1.0/pyproject.toml +45 -0
- kong_deck_tools-0.1.0/setup.cfg +4 -0
- kong_deck_tools-0.1.0/src/kong_deck_tools/__init__.py +8 -0
- kong_deck_tools-0.1.0/src/kong_deck_tools/hydrate.py +135 -0
- kong_deck_tools-0.1.0/src/kong_deck_tools/templatize.py +236 -0
- kong_deck_tools-0.1.0/src/kong_deck_tools.egg-info/PKG-INFO +144 -0
- kong_deck_tools-0.1.0/src/kong_deck_tools.egg-info/SOURCES.txt +12 -0
- kong_deck_tools-0.1.0/src/kong_deck_tools.egg-info/dependency_links.txt +1 -0
- kong_deck_tools-0.1.0/src/kong_deck_tools.egg-info/entry_points.txt +3 -0
- kong_deck_tools-0.1.0/src/kong_deck_tools.egg-info/requires.txt +1 -0
- kong_deck_tools-0.1.0/src/kong_deck_tools.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Michael Tan
|
|
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.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kong-deck-tools
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Kong API Gateway configuration tools for certificate management and cross-environment comparison
|
|
5
|
+
Author: Michael Tan
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/michaeltan/kong-deck-tools
|
|
8
|
+
Project-URL: Repository, https://github.com/michaeltan/kong-deck-tools
|
|
9
|
+
Keywords: kong,api-gateway,deck,configuration,certificates
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: System Administrators
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: System :: Systems Administration
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: ruamel.yaml>=0.18.0
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# kong-deck-tools
|
|
31
|
+
|
|
32
|
+
Kong API Gateway configuration tools for certificate management and cross-environment comparison.
|
|
33
|
+
|
|
34
|
+
## Overview
|
|
35
|
+
|
|
36
|
+
This package provides CLI tools for managing Kong API Gateway configurations:
|
|
37
|
+
|
|
38
|
+
1. **Extract certificates** from Kong configurations into separate files, allowing templates to be safely committed to git while keeping sensitive certificate data separate
|
|
39
|
+
2. **Enforce consistent key ordering** across all configurations, making it easy to compare configurations across different environments (local, staging, production)
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install kong-deck-tools
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
### kong-templatize
|
|
50
|
+
|
|
51
|
+
Splits a Kong configuration into a template and a certificate values file:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
kong-templatize config.yaml
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Input:** `config.yaml` (full Kong configuration with certificates)
|
|
58
|
+
|
|
59
|
+
**Output:**
|
|
60
|
+
- `config.tmpl.yaml` - Template with Helm-style placeholders for certificates
|
|
61
|
+
- `config.certs.values.yaml` - Extracted certificate values (name, cert, key)
|
|
62
|
+
|
|
63
|
+
The script also prettifies the template by reordering YAML keys for consistency and readability.
|
|
64
|
+
|
|
65
|
+
### kong-hydrate
|
|
66
|
+
|
|
67
|
+
Reconstructs a full Kong configuration from template and values:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
kong-hydrate config.tmpl.yaml
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Input:** `config.tmpl.yaml` (template file; values file `config.certs.values.yaml` is derived automatically)
|
|
74
|
+
|
|
75
|
+
**Output:** `config.rendered.yaml` (complete Kong configuration)
|
|
76
|
+
|
|
77
|
+
## Workflow with Kong deck
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# 1. Export current Kong configuration
|
|
81
|
+
deck gateway dump -o config.yaml
|
|
82
|
+
|
|
83
|
+
# 2. Extract certificates and create template
|
|
84
|
+
kong-templatize config.yaml
|
|
85
|
+
|
|
86
|
+
# 3. Commit template to git (certificates stay separate)
|
|
87
|
+
git add config.tmpl.yaml
|
|
88
|
+
git commit -m "Update Kong configuration"
|
|
89
|
+
|
|
90
|
+
# 4. Before deploying, hydrate the template with certificates
|
|
91
|
+
kong-hydrate config.tmpl.yaml
|
|
92
|
+
|
|
93
|
+
# 5. Compare with current Kong state
|
|
94
|
+
deck gateway diff config.rendered.yaml
|
|
95
|
+
|
|
96
|
+
# 6. Apply changes
|
|
97
|
+
deck gateway sync config.rendered.yaml
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Key Ordering
|
|
101
|
+
|
|
102
|
+
The `kong-templatize` command enforces consistent key ordering to make configs:
|
|
103
|
+
- **Human-readable**: Important fields (name, enabled) appear first
|
|
104
|
+
- **Diff-friendly**: Consistent ordering reduces noise in git diffs
|
|
105
|
+
- **Hierarchical**: Configuration objects (routes, plugins) appear after their properties
|
|
106
|
+
|
|
107
|
+
Key ordering by entity type:
|
|
108
|
+
- **Plugins**: name -> enabled -> config -> protocols -> tags
|
|
109
|
+
- **Services**: name -> enabled -> host -> port -> protocol -> timeouts -> tags -> plugins -> routes
|
|
110
|
+
- **Routes**: name -> hosts -> paths -> protocols -> strip_path -> preserve_host -> ... -> plugins
|
|
111
|
+
- **Upstreams**: name -> algorithm -> slots -> hash_* -> tags -> healthchecks -> targets
|
|
112
|
+
- **Consumers**: username -> custom_id -> tags
|
|
113
|
+
|
|
114
|
+
## Requirements
|
|
115
|
+
|
|
116
|
+
- Python 3.8+
|
|
117
|
+
- Kong deck CLI (for dumping/syncing configurations)
|
|
118
|
+
|
|
119
|
+
## Development
|
|
120
|
+
|
|
121
|
+
### Install in development mode
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
git clone https://github.com/michaeltan/kong-deck-tools.git
|
|
125
|
+
cd kong-deck-tools
|
|
126
|
+
pip install -e .
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Publishing to PyPI
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Install uv (if not already installed)
|
|
133
|
+
brew install uv
|
|
134
|
+
|
|
135
|
+
# Build the package
|
|
136
|
+
uv build
|
|
137
|
+
|
|
138
|
+
# Upload to PyPI
|
|
139
|
+
uv publish
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# kong-deck-tools
|
|
2
|
+
|
|
3
|
+
Kong API Gateway configuration tools for certificate management and cross-environment comparison.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides CLI tools for managing Kong API Gateway configurations:
|
|
8
|
+
|
|
9
|
+
1. **Extract certificates** from Kong configurations into separate files, allowing templates to be safely committed to git while keeping sensitive certificate data separate
|
|
10
|
+
2. **Enforce consistent key ordering** across all configurations, making it easy to compare configurations across different environments (local, staging, production)
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install kong-deck-tools
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### kong-templatize
|
|
21
|
+
|
|
22
|
+
Splits a Kong configuration into a template and a certificate values file:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
kong-templatize config.yaml
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Input:** `config.yaml` (full Kong configuration with certificates)
|
|
29
|
+
|
|
30
|
+
**Output:**
|
|
31
|
+
- `config.tmpl.yaml` - Template with Helm-style placeholders for certificates
|
|
32
|
+
- `config.certs.values.yaml` - Extracted certificate values (name, cert, key)
|
|
33
|
+
|
|
34
|
+
The script also prettifies the template by reordering YAML keys for consistency and readability.
|
|
35
|
+
|
|
36
|
+
### kong-hydrate
|
|
37
|
+
|
|
38
|
+
Reconstructs a full Kong configuration from template and values:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
kong-hydrate config.tmpl.yaml
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Input:** `config.tmpl.yaml` (template file; values file `config.certs.values.yaml` is derived automatically)
|
|
45
|
+
|
|
46
|
+
**Output:** `config.rendered.yaml` (complete Kong configuration)
|
|
47
|
+
|
|
48
|
+
## Workflow with Kong deck
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# 1. Export current Kong configuration
|
|
52
|
+
deck gateway dump -o config.yaml
|
|
53
|
+
|
|
54
|
+
# 2. Extract certificates and create template
|
|
55
|
+
kong-templatize config.yaml
|
|
56
|
+
|
|
57
|
+
# 3. Commit template to git (certificates stay separate)
|
|
58
|
+
git add config.tmpl.yaml
|
|
59
|
+
git commit -m "Update Kong configuration"
|
|
60
|
+
|
|
61
|
+
# 4. Before deploying, hydrate the template with certificates
|
|
62
|
+
kong-hydrate config.tmpl.yaml
|
|
63
|
+
|
|
64
|
+
# 5. Compare with current Kong state
|
|
65
|
+
deck gateway diff config.rendered.yaml
|
|
66
|
+
|
|
67
|
+
# 6. Apply changes
|
|
68
|
+
deck gateway sync config.rendered.yaml
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Key Ordering
|
|
72
|
+
|
|
73
|
+
The `kong-templatize` command enforces consistent key ordering to make configs:
|
|
74
|
+
- **Human-readable**: Important fields (name, enabled) appear first
|
|
75
|
+
- **Diff-friendly**: Consistent ordering reduces noise in git diffs
|
|
76
|
+
- **Hierarchical**: Configuration objects (routes, plugins) appear after their properties
|
|
77
|
+
|
|
78
|
+
Key ordering by entity type:
|
|
79
|
+
- **Plugins**: name -> enabled -> config -> protocols -> tags
|
|
80
|
+
- **Services**: name -> enabled -> host -> port -> protocol -> timeouts -> tags -> plugins -> routes
|
|
81
|
+
- **Routes**: name -> hosts -> paths -> protocols -> strip_path -> preserve_host -> ... -> plugins
|
|
82
|
+
- **Upstreams**: name -> algorithm -> slots -> hash_* -> tags -> healthchecks -> targets
|
|
83
|
+
- **Consumers**: username -> custom_id -> tags
|
|
84
|
+
|
|
85
|
+
## Requirements
|
|
86
|
+
|
|
87
|
+
- Python 3.8+
|
|
88
|
+
- Kong deck CLI (for dumping/syncing configurations)
|
|
89
|
+
|
|
90
|
+
## Development
|
|
91
|
+
|
|
92
|
+
### Install in development mode
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git clone https://github.com/michaeltan/kong-deck-tools.git
|
|
96
|
+
cd kong-deck-tools
|
|
97
|
+
pip install -e .
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Publishing to PyPI
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Install uv (if not already installed)
|
|
104
|
+
brew install uv
|
|
105
|
+
|
|
106
|
+
# Build the package
|
|
107
|
+
uv build
|
|
108
|
+
|
|
109
|
+
# Upload to PyPI
|
|
110
|
+
uv publish
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "kong-deck-tools"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Kong API Gateway configuration tools for certificate management and cross-environment comparison"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Michael Tan"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["kong", "api-gateway", "deck", "configuration", "certificates"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Intended Audience :: System Administrators",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.8",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Topic :: System :: Systems Administration",
|
|
30
|
+
"Topic :: Utilities",
|
|
31
|
+
]
|
|
32
|
+
dependencies = [
|
|
33
|
+
"ruamel.yaml>=0.18.0",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/michaeltan/kong-deck-tools"
|
|
38
|
+
Repository = "https://github.com/michaeltan/kong-deck-tools"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
kong-templatize = "kong_deck_tools.templatize:main"
|
|
42
|
+
kong-hydrate = "kong_deck_tools.hydrate:main"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
where = ["src"]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""
|
|
2
|
+
kong-deck-tools: Kong API Gateway configuration management tools.
|
|
3
|
+
|
|
4
|
+
Tools for managing Kong configurations by extracting certificates into separate
|
|
5
|
+
files and enforcing consistent key ordering for easy cross-environment comparison.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
hydrate.py
|
|
4
|
+
Renders a Kong template file by substituting certificate values from values file.
|
|
5
|
+
This reverses the templatize operation.
|
|
6
|
+
|
|
7
|
+
Usage: kong-hydrate <template_file>
|
|
8
|
+
Example: kong-hydrate config.tmpl.yaml
|
|
9
|
+
|
|
10
|
+
Uses ruamel.yaml for format preservation to ensure lossless round-trips.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import re
|
|
14
|
+
import sys
|
|
15
|
+
from io import StringIO
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from ruamel.yaml import YAML
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def load_certificate_values(file_path):
|
|
21
|
+
"""Load certificate values from values file."""
|
|
22
|
+
with open(file_path, 'r') as f:
|
|
23
|
+
content = f.read()
|
|
24
|
+
|
|
25
|
+
# Split by 'name:' but keep the delimiter
|
|
26
|
+
parts = re.split(r'(?=^name: )', content, flags=re.MULTILINE)
|
|
27
|
+
|
|
28
|
+
yaml = YAML()
|
|
29
|
+
yaml.preserve_quotes = True
|
|
30
|
+
|
|
31
|
+
certs = []
|
|
32
|
+
for part in parts:
|
|
33
|
+
part = part.strip()
|
|
34
|
+
if part:
|
|
35
|
+
try:
|
|
36
|
+
cert_doc = yaml.load(StringIO(part))
|
|
37
|
+
if cert_doc and 'name' in cert_doc:
|
|
38
|
+
certs.append(cert_doc)
|
|
39
|
+
except Exception:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
return certs
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def load_yaml(file_path):
|
|
46
|
+
"""Load a single YAML document with format preservation."""
|
|
47
|
+
yaml = YAML()
|
|
48
|
+
yaml.preserve_quotes = True
|
|
49
|
+
yaml.default_flow_style = False
|
|
50
|
+
|
|
51
|
+
with open(file_path, 'r') as f:
|
|
52
|
+
return yaml.load(f)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def main():
|
|
56
|
+
if len(sys.argv) < 2:
|
|
57
|
+
print("Usage: kong-hydrate <template_file>")
|
|
58
|
+
print("Example: kong-hydrate config.tmpl.yaml")
|
|
59
|
+
sys.exit(1)
|
|
60
|
+
|
|
61
|
+
template_file = sys.argv[1]
|
|
62
|
+
|
|
63
|
+
# Validate input file exists
|
|
64
|
+
if not Path(template_file).exists():
|
|
65
|
+
print(f"Error: Template file '{template_file}' not found")
|
|
66
|
+
sys.exit(1)
|
|
67
|
+
|
|
68
|
+
# Derive basename by stripping .tmpl.yaml or .tmpl.yml extension
|
|
69
|
+
basename = template_file
|
|
70
|
+
for ext in ['.tmpl.yaml', '.tmpl.yml']:
|
|
71
|
+
if basename.endswith(ext):
|
|
72
|
+
basename = basename[:-len(ext)]
|
|
73
|
+
break
|
|
74
|
+
|
|
75
|
+
values_file = f"{basename}.certs.values.yaml"
|
|
76
|
+
output_file = f"{basename}.rendered.yaml"
|
|
77
|
+
|
|
78
|
+
if not Path(values_file).exists():
|
|
79
|
+
print(f"Error: Values file '{values_file}' not found")
|
|
80
|
+
sys.exit(1)
|
|
81
|
+
|
|
82
|
+
print("Rendering Kong configuration...")
|
|
83
|
+
print(f" Template: {template_file}")
|
|
84
|
+
print(f" Values: {values_file}")
|
|
85
|
+
print("")
|
|
86
|
+
|
|
87
|
+
# Load template
|
|
88
|
+
template = load_yaml(template_file)
|
|
89
|
+
|
|
90
|
+
# Load certificate values
|
|
91
|
+
cert_values = load_certificate_values(values_file)
|
|
92
|
+
|
|
93
|
+
# Create a mapping of SNI name to certificate data
|
|
94
|
+
cert_map = {}
|
|
95
|
+
for cert_doc in cert_values:
|
|
96
|
+
if cert_doc and 'name' in cert_doc:
|
|
97
|
+
cert_map[cert_doc['name']] = {
|
|
98
|
+
'cert': cert_doc.get('cert', ''),
|
|
99
|
+
'key': cert_doc.get('key', '')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Substitute certificates in template
|
|
103
|
+
if 'certificates' in template:
|
|
104
|
+
for cert in template['certificates']:
|
|
105
|
+
if 'snis' in cert and len(cert['snis']) > 0:
|
|
106
|
+
sni_name = cert['snis'][0]['name']
|
|
107
|
+
if sni_name in cert_map:
|
|
108
|
+
print(f" Substituting certificate for: {sni_name}")
|
|
109
|
+
cert_value = cert_map[sni_name]['cert']
|
|
110
|
+
key_value = cert_map[sni_name]['key']
|
|
111
|
+
|
|
112
|
+
# Ensure keys end with newline to match Kong's format
|
|
113
|
+
if not key_value.endswith('\n'):
|
|
114
|
+
key_value = key_value + '\n'
|
|
115
|
+
|
|
116
|
+
cert['cert'] = cert_value
|
|
117
|
+
cert['key'] = key_value
|
|
118
|
+
|
|
119
|
+
# Write rendered output with format preservation
|
|
120
|
+
yaml = YAML()
|
|
121
|
+
yaml.preserve_quotes = True
|
|
122
|
+
yaml.default_flow_style = False
|
|
123
|
+
yaml.width = 4096 # Prevent line wrapping
|
|
124
|
+
|
|
125
|
+
with open(output_file, 'w') as f:
|
|
126
|
+
yaml.dump(template, f)
|
|
127
|
+
|
|
128
|
+
print("")
|
|
129
|
+
print("Configuration rendered successfully!")
|
|
130
|
+
print(f" Output: {output_file}")
|
|
131
|
+
print("")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
if __name__ == '__main__':
|
|
135
|
+
main()
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
templatize.py
|
|
4
|
+
Splits Kong configuration into template and values files, then prettifies.
|
|
5
|
+
This creates diff-friendly, Helm-ready configuration files.
|
|
6
|
+
|
|
7
|
+
Usage: kong-templatize <config_file>
|
|
8
|
+
Example: kong-templatize config.yaml
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import sys
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from ruamel.yaml import YAML
|
|
14
|
+
from ruamel.yaml.comments import CommentedMap
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Key ordering definitions for each entity type
|
|
18
|
+
PLUGIN_KEY_ORDER = ['name', 'enabled', 'config', 'protocols', 'tags']
|
|
19
|
+
SERVICE_KEY_ORDER = ['name', 'enabled', 'host', 'port', 'protocol',
|
|
20
|
+
'connect_timeout', 'read_timeout', 'write_timeout',
|
|
21
|
+
'retries', 'tags']
|
|
22
|
+
SERVICE_TRAILING_KEYS = ['plugins', 'routes']
|
|
23
|
+
ROUTE_KEY_ORDER = ['name', 'hosts', 'paths', 'protocols', 'strip_path',
|
|
24
|
+
'preserve_host', 'https_redirect_status_code', 'path_handling',
|
|
25
|
+
'regex_priority', 'request_buffering', 'response_buffering', 'tags']
|
|
26
|
+
ROUTE_TRAILING_KEYS = ['plugins']
|
|
27
|
+
UPSTREAM_KEY_ORDER = ['name', 'algorithm', 'slots', 'hash_on', 'hash_fallback',
|
|
28
|
+
'hash_on_cookie_path', 'use_srv_name', 'tags']
|
|
29
|
+
UPSTREAM_TRAILING_KEYS = ['healthchecks', 'targets']
|
|
30
|
+
TARGET_KEY_ORDER = ['target', 'weight', 'tags']
|
|
31
|
+
CONSUMER_KEY_ORDER = ['username', 'custom_id', 'tags']
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def reorder_keys(obj, key_order, trailing_keys=None):
|
|
35
|
+
"""Reorder keys in a CommentedMap according to specified order."""
|
|
36
|
+
if not isinstance(obj, dict):
|
|
37
|
+
return obj
|
|
38
|
+
|
|
39
|
+
trailing_keys = trailing_keys or []
|
|
40
|
+
ordered = CommentedMap()
|
|
41
|
+
|
|
42
|
+
# First, add keys in specified order
|
|
43
|
+
for key in key_order:
|
|
44
|
+
if key in obj:
|
|
45
|
+
ordered[key] = obj[key]
|
|
46
|
+
|
|
47
|
+
# Then add remaining keys (except trailing ones)
|
|
48
|
+
all_specified = set(key_order) | set(trailing_keys)
|
|
49
|
+
for key in obj:
|
|
50
|
+
if key not in all_specified:
|
|
51
|
+
ordered[key] = obj[key]
|
|
52
|
+
|
|
53
|
+
# Finally add trailing keys
|
|
54
|
+
for key in trailing_keys:
|
|
55
|
+
if key in obj:
|
|
56
|
+
ordered[key] = obj[key]
|
|
57
|
+
|
|
58
|
+
return ordered
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def reorder_plugins(plugins):
|
|
62
|
+
"""Reorder keys in plugin configurations."""
|
|
63
|
+
if not plugins:
|
|
64
|
+
return plugins
|
|
65
|
+
return [reorder_keys(p, PLUGIN_KEY_ORDER) for p in plugins]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def reorder_routes(routes):
|
|
69
|
+
"""Reorder keys in route configurations."""
|
|
70
|
+
if not routes:
|
|
71
|
+
return routes
|
|
72
|
+
result = []
|
|
73
|
+
for route in routes:
|
|
74
|
+
ordered = reorder_keys(route, ROUTE_KEY_ORDER, ROUTE_TRAILING_KEYS)
|
|
75
|
+
if 'plugins' in ordered:
|
|
76
|
+
ordered['plugins'] = reorder_plugins(ordered['plugins'])
|
|
77
|
+
result.append(ordered)
|
|
78
|
+
return result
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def reorder_services(services):
|
|
82
|
+
"""Reorder keys in service configurations."""
|
|
83
|
+
if not services:
|
|
84
|
+
return services
|
|
85
|
+
result = []
|
|
86
|
+
for service in services:
|
|
87
|
+
ordered = reorder_keys(service, SERVICE_KEY_ORDER, SERVICE_TRAILING_KEYS)
|
|
88
|
+
if 'plugins' in ordered:
|
|
89
|
+
ordered['plugins'] = reorder_plugins(ordered['plugins'])
|
|
90
|
+
if 'routes' in ordered:
|
|
91
|
+
ordered['routes'] = reorder_routes(ordered['routes'])
|
|
92
|
+
result.append(ordered)
|
|
93
|
+
return result
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def reorder_targets(targets):
|
|
97
|
+
"""Reorder keys in target configurations."""
|
|
98
|
+
if not targets:
|
|
99
|
+
return targets
|
|
100
|
+
return [reorder_keys(t, TARGET_KEY_ORDER) for t in targets]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def reorder_upstreams(upstreams):
|
|
104
|
+
"""Reorder keys in upstream configurations."""
|
|
105
|
+
if not upstreams:
|
|
106
|
+
return upstreams
|
|
107
|
+
result = []
|
|
108
|
+
for upstream in upstreams:
|
|
109
|
+
ordered = reorder_keys(upstream, UPSTREAM_KEY_ORDER, UPSTREAM_TRAILING_KEYS)
|
|
110
|
+
if 'targets' in ordered:
|
|
111
|
+
ordered['targets'] = reorder_targets(ordered['targets'])
|
|
112
|
+
result.append(ordered)
|
|
113
|
+
return result
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def reorder_consumers(consumers):
|
|
117
|
+
"""Reorder keys in consumer configurations."""
|
|
118
|
+
if not consumers:
|
|
119
|
+
return consumers
|
|
120
|
+
return [reorder_keys(c, CONSUMER_KEY_ORDER) for c in consumers]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def prettify_config(config):
|
|
124
|
+
"""Prettify the entire configuration by reordering keys."""
|
|
125
|
+
if 'plugins' in config:
|
|
126
|
+
config['plugins'] = reorder_plugins(config['plugins'])
|
|
127
|
+
if 'services' in config:
|
|
128
|
+
config['services'] = reorder_services(config['services'])
|
|
129
|
+
if 'upstreams' in config:
|
|
130
|
+
config['upstreams'] = reorder_upstreams(config['upstreams'])
|
|
131
|
+
if 'consumers' in config:
|
|
132
|
+
config['consumers'] = reorder_consumers(config['consumers'])
|
|
133
|
+
return config
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def extract_certificates(config):
|
|
137
|
+
"""Extract certificates from config into a list of certificate values."""
|
|
138
|
+
certs = []
|
|
139
|
+
if 'certificates' in config and config['certificates']:
|
|
140
|
+
for cert in config['certificates']:
|
|
141
|
+
if 'snis' in cert and cert['snis']:
|
|
142
|
+
cert_entry = CommentedMap()
|
|
143
|
+
cert_entry['name'] = cert['snis'][0]['name']
|
|
144
|
+
cert_entry['cert'] = cert.get('cert', '')
|
|
145
|
+
cert_entry['key'] = cert.get('key', '')
|
|
146
|
+
certs.append(cert_entry)
|
|
147
|
+
return certs
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def create_template(config):
|
|
151
|
+
"""Create template by replacing certificate values with Helm placeholders."""
|
|
152
|
+
if 'certificates' in config and config['certificates']:
|
|
153
|
+
for cert in config['certificates']:
|
|
154
|
+
cert['cert'] = "{{ .Values.certificates[.snis[0].name].cert }}"
|
|
155
|
+
cert['key'] = "{{ .Values.certificates[.snis[0].name].key }}"
|
|
156
|
+
return config
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def main():
|
|
160
|
+
if len(sys.argv) < 2:
|
|
161
|
+
print("Usage: kong-templatize <config_file>")
|
|
162
|
+
print("Example: kong-templatize config.yaml")
|
|
163
|
+
sys.exit(1)
|
|
164
|
+
|
|
165
|
+
input_file = sys.argv[1]
|
|
166
|
+
|
|
167
|
+
# Validate input file exists
|
|
168
|
+
input_path = Path(input_file)
|
|
169
|
+
if not input_path.exists():
|
|
170
|
+
print(f"Error: Input file '{input_file}' not found")
|
|
171
|
+
sys.exit(1)
|
|
172
|
+
|
|
173
|
+
# Extract basename (remove .yaml or .yml extension)
|
|
174
|
+
basename = input_file
|
|
175
|
+
for ext in ['.yaml', '.yml']:
|
|
176
|
+
if basename.endswith(ext):
|
|
177
|
+
basename = basename[:-len(ext)]
|
|
178
|
+
break
|
|
179
|
+
|
|
180
|
+
# Define output files
|
|
181
|
+
template_file = f"{basename}.tmpl.yaml"
|
|
182
|
+
values_file = f"{basename}.certs.values.yaml"
|
|
183
|
+
|
|
184
|
+
print(f"Processing Kong configuration: {input_file}")
|
|
185
|
+
print("")
|
|
186
|
+
|
|
187
|
+
# Initialize YAML parser
|
|
188
|
+
yaml = YAML()
|
|
189
|
+
yaml.preserve_quotes = True
|
|
190
|
+
yaml.default_flow_style = False
|
|
191
|
+
yaml.width = 4096 # Prevent line wrapping
|
|
192
|
+
|
|
193
|
+
# Load input configuration
|
|
194
|
+
with open(input_file, 'r') as f:
|
|
195
|
+
config = yaml.load(f)
|
|
196
|
+
|
|
197
|
+
# Step 1: Extract certificates to values file
|
|
198
|
+
print("Extracting certificates to values file...")
|
|
199
|
+
certs = extract_certificates(config)
|
|
200
|
+
|
|
201
|
+
if certs:
|
|
202
|
+
with open(values_file, 'w') as f:
|
|
203
|
+
for cert in certs:
|
|
204
|
+
yaml.dump(cert, f)
|
|
205
|
+
print(f" Certificates extracted to: {values_file}")
|
|
206
|
+
else:
|
|
207
|
+
print(" No certificates found or extraction failed")
|
|
208
|
+
# Create empty values file
|
|
209
|
+
with open(values_file, 'w') as f:
|
|
210
|
+
pass
|
|
211
|
+
|
|
212
|
+
# Step 2: Create template with Helm placeholders
|
|
213
|
+
print("Creating template with Helm placeholders...")
|
|
214
|
+
template = create_template(config)
|
|
215
|
+
print(f" Template created: {template_file}")
|
|
216
|
+
print("")
|
|
217
|
+
|
|
218
|
+
# Step 3: Prettify the template file with key reordering
|
|
219
|
+
print("Prettifying template structure...")
|
|
220
|
+
template = prettify_config(template)
|
|
221
|
+
|
|
222
|
+
# Write template file
|
|
223
|
+
with open(template_file, 'w') as f:
|
|
224
|
+
yaml.dump(template, f)
|
|
225
|
+
|
|
226
|
+
print("")
|
|
227
|
+
print("Kong configuration processed successfully!")
|
|
228
|
+
print("")
|
|
229
|
+
print("Files created:")
|
|
230
|
+
print(f" Template: {template_file}")
|
|
231
|
+
print(f" Values: {values_file}")
|
|
232
|
+
print("")
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
if __name__ == '__main__':
|
|
236
|
+
main()
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kong-deck-tools
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Kong API Gateway configuration tools for certificate management and cross-environment comparison
|
|
5
|
+
Author: Michael Tan
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/michaeltan/kong-deck-tools
|
|
8
|
+
Project-URL: Repository, https://github.com/michaeltan/kong-deck-tools
|
|
9
|
+
Keywords: kong,api-gateway,deck,configuration,certificates
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: System Administrators
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: System :: Systems Administration
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: ruamel.yaml>=0.18.0
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# kong-deck-tools
|
|
31
|
+
|
|
32
|
+
Kong API Gateway configuration tools for certificate management and cross-environment comparison.
|
|
33
|
+
|
|
34
|
+
## Overview
|
|
35
|
+
|
|
36
|
+
This package provides CLI tools for managing Kong API Gateway configurations:
|
|
37
|
+
|
|
38
|
+
1. **Extract certificates** from Kong configurations into separate files, allowing templates to be safely committed to git while keeping sensitive certificate data separate
|
|
39
|
+
2. **Enforce consistent key ordering** across all configurations, making it easy to compare configurations across different environments (local, staging, production)
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install kong-deck-tools
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
### kong-templatize
|
|
50
|
+
|
|
51
|
+
Splits a Kong configuration into a template and a certificate values file:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
kong-templatize config.yaml
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Input:** `config.yaml` (full Kong configuration with certificates)
|
|
58
|
+
|
|
59
|
+
**Output:**
|
|
60
|
+
- `config.tmpl.yaml` - Template with Helm-style placeholders for certificates
|
|
61
|
+
- `config.certs.values.yaml` - Extracted certificate values (name, cert, key)
|
|
62
|
+
|
|
63
|
+
The script also prettifies the template by reordering YAML keys for consistency and readability.
|
|
64
|
+
|
|
65
|
+
### kong-hydrate
|
|
66
|
+
|
|
67
|
+
Reconstructs a full Kong configuration from template and values:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
kong-hydrate config.tmpl.yaml
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Input:** `config.tmpl.yaml` (template file; values file `config.certs.values.yaml` is derived automatically)
|
|
74
|
+
|
|
75
|
+
**Output:** `config.rendered.yaml` (complete Kong configuration)
|
|
76
|
+
|
|
77
|
+
## Workflow with Kong deck
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# 1. Export current Kong configuration
|
|
81
|
+
deck gateway dump -o config.yaml
|
|
82
|
+
|
|
83
|
+
# 2. Extract certificates and create template
|
|
84
|
+
kong-templatize config.yaml
|
|
85
|
+
|
|
86
|
+
# 3. Commit template to git (certificates stay separate)
|
|
87
|
+
git add config.tmpl.yaml
|
|
88
|
+
git commit -m "Update Kong configuration"
|
|
89
|
+
|
|
90
|
+
# 4. Before deploying, hydrate the template with certificates
|
|
91
|
+
kong-hydrate config.tmpl.yaml
|
|
92
|
+
|
|
93
|
+
# 5. Compare with current Kong state
|
|
94
|
+
deck gateway diff config.rendered.yaml
|
|
95
|
+
|
|
96
|
+
# 6. Apply changes
|
|
97
|
+
deck gateway sync config.rendered.yaml
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Key Ordering
|
|
101
|
+
|
|
102
|
+
The `kong-templatize` command enforces consistent key ordering to make configs:
|
|
103
|
+
- **Human-readable**: Important fields (name, enabled) appear first
|
|
104
|
+
- **Diff-friendly**: Consistent ordering reduces noise in git diffs
|
|
105
|
+
- **Hierarchical**: Configuration objects (routes, plugins) appear after their properties
|
|
106
|
+
|
|
107
|
+
Key ordering by entity type:
|
|
108
|
+
- **Plugins**: name -> enabled -> config -> protocols -> tags
|
|
109
|
+
- **Services**: name -> enabled -> host -> port -> protocol -> timeouts -> tags -> plugins -> routes
|
|
110
|
+
- **Routes**: name -> hosts -> paths -> protocols -> strip_path -> preserve_host -> ... -> plugins
|
|
111
|
+
- **Upstreams**: name -> algorithm -> slots -> hash_* -> tags -> healthchecks -> targets
|
|
112
|
+
- **Consumers**: username -> custom_id -> tags
|
|
113
|
+
|
|
114
|
+
## Requirements
|
|
115
|
+
|
|
116
|
+
- Python 3.8+
|
|
117
|
+
- Kong deck CLI (for dumping/syncing configurations)
|
|
118
|
+
|
|
119
|
+
## Development
|
|
120
|
+
|
|
121
|
+
### Install in development mode
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
git clone https://github.com/michaeltan/kong-deck-tools.git
|
|
125
|
+
cd kong-deck-tools
|
|
126
|
+
pip install -e .
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Publishing to PyPI
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Install uv (if not already installed)
|
|
133
|
+
brew install uv
|
|
134
|
+
|
|
135
|
+
# Build the package
|
|
136
|
+
uv build
|
|
137
|
+
|
|
138
|
+
# Upload to PyPI
|
|
139
|
+
uv publish
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/kong_deck_tools/__init__.py
|
|
5
|
+
src/kong_deck_tools/hydrate.py
|
|
6
|
+
src/kong_deck_tools/templatize.py
|
|
7
|
+
src/kong_deck_tools.egg-info/PKG-INFO
|
|
8
|
+
src/kong_deck_tools.egg-info/SOURCES.txt
|
|
9
|
+
src/kong_deck_tools.egg-info/dependency_links.txt
|
|
10
|
+
src/kong_deck_tools.egg-info/entry_points.txt
|
|
11
|
+
src/kong_deck_tools.egg-info/requires.txt
|
|
12
|
+
src/kong_deck_tools.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ruamel.yaml>=0.18.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
kong_deck_tools
|