nebula-config-kit 0.0.1__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.
- nebula_config_kit-0.0.1/PKG-INFO +203 -0
- nebula_config_kit-0.0.1/README.md +170 -0
- nebula_config_kit-0.0.1/pyproject.toml +116 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/__init__.py +72 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/cli/__init__.py +82 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/cli/_config.py +52 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/cli/_context.py +55 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/cli/_hosts.py +73 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/cli/_output.py +118 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/config_gen.py +238 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/config_loader.py +30 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/exceptions.py +47 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/firewall.py +33 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/hosts.py +74 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/models.py +126 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/nebula.config.template.yml +427 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/network.py +13 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/orchestration.py +163 -0
- nebula_config_kit-0.0.1/src/nebula_config_kit/types.py +29 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nebula-config-kit
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Define your Nebula mesh network once, generate validated configs for every host
|
|
5
|
+
Keywords: nebula,vpn,mesh-network,overlay-network,network-automation,configuration-management,infrastructure,pki
|
|
6
|
+
Author: Dmitry Tatarkin
|
|
7
|
+
Author-email: Dmitry Tatarkin <tatarkin@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: System Administrators
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: System :: Networking
|
|
13
|
+
Classifier: Topic :: System :: Systems Administration
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Classifier: Environment :: Console
|
|
17
|
+
Classifier: Framework :: Pydantic :: 2
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Requires-Dist: pki-kit>=0.0.2
|
|
22
|
+
Requires-Dist: pydantic>=2.0
|
|
23
|
+
Requires-Dist: ruamel-yaml>=0.18
|
|
24
|
+
Requires-Dist: typer>=0.15 ; extra == 'cli'
|
|
25
|
+
Requires-Dist: rich>=13.0 ; extra == 'cli'
|
|
26
|
+
Requires-Python: >=3.12
|
|
27
|
+
Project-URL: Homepage, https://github.com/dtatarkin/nebula-config-kit
|
|
28
|
+
Project-URL: Repository, https://github.com/dtatarkin/nebula-config-kit
|
|
29
|
+
Project-URL: Issues, https://github.com/dtatarkin/nebula-config-kit/issues
|
|
30
|
+
Project-URL: Changelog, https://github.com/dtatarkin/nebula-config-kit/releases
|
|
31
|
+
Provides-Extra: cli
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# nebula-config-kit
|
|
35
|
+
|
|
36
|
+
**Stop hand-crafting Nebula configs. Define your mesh network once, generate configs for every host.**
|
|
37
|
+
|
|
38
|
+
nebula-config-kit is a Python library and CLI for managing [Nebula](https://github.com/slackhq/nebula) overlay network configurations. It takes a single declarative YAML file describing your entire network — hosts, lighthouses, relays, firewall rules — and generates validated, ready-to-deploy Nebula configs for each node.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Why?
|
|
43
|
+
|
|
44
|
+
Managing a Nebula mesh network means juggling per-host YAML files that share 90% of their content but differ in subtle, error-prone ways. nebula-config-kit solves this:
|
|
45
|
+
|
|
46
|
+
- **Single source of truth** — one config file defines your entire network topology
|
|
47
|
+
- **Type-safe validation** — Pydantic models catch misconfigurations before deployment (duplicate IPs, missing lighthouses, invalid rules)
|
|
48
|
+
- **Automatic resolution** — lighthouse maps, relay lists, and firewall rules are computed per-host from your network definition
|
|
49
|
+
- **PKI integration** — built-in certificate management via pki-kit (CA creation, host cert signing, revocation)
|
|
50
|
+
- **Comment-preserving templates** — generated configs retain the original Nebula YAML comments for readability
|
|
51
|
+
|
|
52
|
+
## Quick start
|
|
53
|
+
|
|
54
|
+
### Install
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# With CLI
|
|
58
|
+
pip install nebula-config-kit[cli]
|
|
59
|
+
|
|
60
|
+
# Library only
|
|
61
|
+
pip install nebula-config-kit
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Define your network
|
|
65
|
+
|
|
66
|
+
Create `nebula-network.config.yml`:
|
|
67
|
+
|
|
68
|
+
```yaml
|
|
69
|
+
network:
|
|
70
|
+
cidr: 10.10.0.0/16
|
|
71
|
+
|
|
72
|
+
certs:
|
|
73
|
+
ca_name: "My Network CA"
|
|
74
|
+
ca_duration: 3650d
|
|
75
|
+
host_duration: 365d
|
|
76
|
+
|
|
77
|
+
hosts:
|
|
78
|
+
defaults:
|
|
79
|
+
listen_port: 4242
|
|
80
|
+
tun_dev: nebula1
|
|
81
|
+
hosts:
|
|
82
|
+
lighthouse1:
|
|
83
|
+
nebula_ip: 10.10.0.1
|
|
84
|
+
public_endpoints: ["203.0.113.10"]
|
|
85
|
+
webserver:
|
|
86
|
+
nebula_ip: 10.10.0.10
|
|
87
|
+
database:
|
|
88
|
+
nebula_ip: 10.10.0.20
|
|
89
|
+
|
|
90
|
+
firewall:
|
|
91
|
+
security_groups:
|
|
92
|
+
icmp:
|
|
93
|
+
port: any
|
|
94
|
+
proto: icmp
|
|
95
|
+
direction: any
|
|
96
|
+
ssh:
|
|
97
|
+
port: 22
|
|
98
|
+
proto: tcp
|
|
99
|
+
direction: in
|
|
100
|
+
https:
|
|
101
|
+
port: 443
|
|
102
|
+
proto: tcp
|
|
103
|
+
direction: in
|
|
104
|
+
firewall_default:
|
|
105
|
+
all: [icmp]
|
|
106
|
+
firewall_rules:
|
|
107
|
+
webserver:
|
|
108
|
+
all: [ssh, https]
|
|
109
|
+
database:
|
|
110
|
+
webserver: [ssh]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Generate configs
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# List all hosts
|
|
117
|
+
nebula-config hosts list
|
|
118
|
+
|
|
119
|
+
# Show resolved details for a host
|
|
120
|
+
nebula-config hosts show webserver
|
|
121
|
+
|
|
122
|
+
# Generate a complete Nebula config
|
|
123
|
+
nebula-config config generate webserver -o webserver.yml
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Use as a library
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from pathlib import Path
|
|
130
|
+
from nebula_config_kit import load_config, resolve_host, generate_host_config
|
|
131
|
+
from nebula_config_kit.types import HostName
|
|
132
|
+
|
|
133
|
+
config = load_config(path=Path("nebula-network.config.yml"))
|
|
134
|
+
host = resolve_host(name=HostName("webserver"), config=config)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Features
|
|
138
|
+
|
|
139
|
+
### Host resolution
|
|
140
|
+
|
|
141
|
+
Hosts inherit from `defaults` and can override any setting. Lighthouses are auto-detected from hosts with `public_endpoints`. Relays are identified by the `am_relay` flag. Each host gets a resolved config with the correct static host map, lighthouse list, and relay list — excluding itself.
|
|
142
|
+
|
|
143
|
+
### Security groups & firewall
|
|
144
|
+
|
|
145
|
+
Define reusable security groups, assign them to hosts or host groups, and nebula-config-kit resolves the full inbound/outbound firewall ruleset per host. Default rules apply to all hosts unless overridden.
|
|
146
|
+
|
|
147
|
+
### PKI management
|
|
148
|
+
|
|
149
|
+
Integrated certificate lifecycle:
|
|
150
|
+
|
|
151
|
+
- CA key and certificate generation
|
|
152
|
+
- Host certificate signing with correct Nebula IP and groups
|
|
153
|
+
- Certificate revocation
|
|
154
|
+
- Validity tracking and renewal hints
|
|
155
|
+
- SOPS-encrypted key storage support
|
|
156
|
+
|
|
157
|
+
### CLI output formats
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Table (default), JSON, or YAML
|
|
161
|
+
nebula-config hosts list --output json
|
|
162
|
+
nebula-config hosts show database --output yaml
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Custom templates
|
|
166
|
+
|
|
167
|
+
Override the built-in Nebula config template to include your own settings:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
nebula-config config generate webserver --template my-template.yml
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Configuration
|
|
174
|
+
|
|
175
|
+
| Environment Variable | Default | Description |
|
|
176
|
+
| --------------------------------- | --------------------------- | ------------------------------------------ |
|
|
177
|
+
| `NEBULA_NETWORK_CONFIG` | `nebula-network.config.yml` | Path to network config file |
|
|
178
|
+
| `NEBULA_CONFIG_KIT_PKI_PATH` | `.` | Root directory for PKI stores |
|
|
179
|
+
| `NEBULA_CONFIG_KIT_PKI_NAME` | `default` | PKI instance name |
|
|
180
|
+
| `NEBULA_CONFIG_KIT_SOPS_ARGS` | — | Extra SOPS arguments for encrypted keys |
|
|
181
|
+
| `NEBULA_CONFIG_KIT_OUTPUT_FORMAT` | `table` | CLI output format: `table`, `json`, `yaml` |
|
|
182
|
+
|
|
183
|
+
## Development
|
|
184
|
+
|
|
185
|
+
Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Install dependencies
|
|
189
|
+
uv sync --all-extras
|
|
190
|
+
|
|
191
|
+
# Run tests
|
|
192
|
+
just test
|
|
193
|
+
|
|
194
|
+
# Lint + type check
|
|
195
|
+
just lint
|
|
196
|
+
|
|
197
|
+
# All checks
|
|
198
|
+
just check
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# nebula-config-kit
|
|
2
|
+
|
|
3
|
+
**Stop hand-crafting Nebula configs. Define your mesh network once, generate configs for every host.**
|
|
4
|
+
|
|
5
|
+
nebula-config-kit is a Python library and CLI for managing [Nebula](https://github.com/slackhq/nebula) overlay network configurations. It takes a single declarative YAML file describing your entire network — hosts, lighthouses, relays, firewall rules — and generates validated, ready-to-deploy Nebula configs for each node.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Why?
|
|
10
|
+
|
|
11
|
+
Managing a Nebula mesh network means juggling per-host YAML files that share 90% of their content but differ in subtle, error-prone ways. nebula-config-kit solves this:
|
|
12
|
+
|
|
13
|
+
- **Single source of truth** — one config file defines your entire network topology
|
|
14
|
+
- **Type-safe validation** — Pydantic models catch misconfigurations before deployment (duplicate IPs, missing lighthouses, invalid rules)
|
|
15
|
+
- **Automatic resolution** — lighthouse maps, relay lists, and firewall rules are computed per-host from your network definition
|
|
16
|
+
- **PKI integration** — built-in certificate management via pki-kit (CA creation, host cert signing, revocation)
|
|
17
|
+
- **Comment-preserving templates** — generated configs retain the original Nebula YAML comments for readability
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
### Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# With CLI
|
|
25
|
+
pip install nebula-config-kit[cli]
|
|
26
|
+
|
|
27
|
+
# Library only
|
|
28
|
+
pip install nebula-config-kit
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Define your network
|
|
32
|
+
|
|
33
|
+
Create `nebula-network.config.yml`:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
network:
|
|
37
|
+
cidr: 10.10.0.0/16
|
|
38
|
+
|
|
39
|
+
certs:
|
|
40
|
+
ca_name: "My Network CA"
|
|
41
|
+
ca_duration: 3650d
|
|
42
|
+
host_duration: 365d
|
|
43
|
+
|
|
44
|
+
hosts:
|
|
45
|
+
defaults:
|
|
46
|
+
listen_port: 4242
|
|
47
|
+
tun_dev: nebula1
|
|
48
|
+
hosts:
|
|
49
|
+
lighthouse1:
|
|
50
|
+
nebula_ip: 10.10.0.1
|
|
51
|
+
public_endpoints: ["203.0.113.10"]
|
|
52
|
+
webserver:
|
|
53
|
+
nebula_ip: 10.10.0.10
|
|
54
|
+
database:
|
|
55
|
+
nebula_ip: 10.10.0.20
|
|
56
|
+
|
|
57
|
+
firewall:
|
|
58
|
+
security_groups:
|
|
59
|
+
icmp:
|
|
60
|
+
port: any
|
|
61
|
+
proto: icmp
|
|
62
|
+
direction: any
|
|
63
|
+
ssh:
|
|
64
|
+
port: 22
|
|
65
|
+
proto: tcp
|
|
66
|
+
direction: in
|
|
67
|
+
https:
|
|
68
|
+
port: 443
|
|
69
|
+
proto: tcp
|
|
70
|
+
direction: in
|
|
71
|
+
firewall_default:
|
|
72
|
+
all: [icmp]
|
|
73
|
+
firewall_rules:
|
|
74
|
+
webserver:
|
|
75
|
+
all: [ssh, https]
|
|
76
|
+
database:
|
|
77
|
+
webserver: [ssh]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Generate configs
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# List all hosts
|
|
84
|
+
nebula-config hosts list
|
|
85
|
+
|
|
86
|
+
# Show resolved details for a host
|
|
87
|
+
nebula-config hosts show webserver
|
|
88
|
+
|
|
89
|
+
# Generate a complete Nebula config
|
|
90
|
+
nebula-config config generate webserver -o webserver.yml
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Use as a library
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from pathlib import Path
|
|
97
|
+
from nebula_config_kit import load_config, resolve_host, generate_host_config
|
|
98
|
+
from nebula_config_kit.types import HostName
|
|
99
|
+
|
|
100
|
+
config = load_config(path=Path("nebula-network.config.yml"))
|
|
101
|
+
host = resolve_host(name=HostName("webserver"), config=config)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Features
|
|
105
|
+
|
|
106
|
+
### Host resolution
|
|
107
|
+
|
|
108
|
+
Hosts inherit from `defaults` and can override any setting. Lighthouses are auto-detected from hosts with `public_endpoints`. Relays are identified by the `am_relay` flag. Each host gets a resolved config with the correct static host map, lighthouse list, and relay list — excluding itself.
|
|
109
|
+
|
|
110
|
+
### Security groups & firewall
|
|
111
|
+
|
|
112
|
+
Define reusable security groups, assign them to hosts or host groups, and nebula-config-kit resolves the full inbound/outbound firewall ruleset per host. Default rules apply to all hosts unless overridden.
|
|
113
|
+
|
|
114
|
+
### PKI management
|
|
115
|
+
|
|
116
|
+
Integrated certificate lifecycle:
|
|
117
|
+
|
|
118
|
+
- CA key and certificate generation
|
|
119
|
+
- Host certificate signing with correct Nebula IP and groups
|
|
120
|
+
- Certificate revocation
|
|
121
|
+
- Validity tracking and renewal hints
|
|
122
|
+
- SOPS-encrypted key storage support
|
|
123
|
+
|
|
124
|
+
### CLI output formats
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Table (default), JSON, or YAML
|
|
128
|
+
nebula-config hosts list --output json
|
|
129
|
+
nebula-config hosts show database --output yaml
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Custom templates
|
|
133
|
+
|
|
134
|
+
Override the built-in Nebula config template to include your own settings:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
nebula-config config generate webserver --template my-template.yml
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Configuration
|
|
141
|
+
|
|
142
|
+
| Environment Variable | Default | Description |
|
|
143
|
+
| --------------------------------- | --------------------------- | ------------------------------------------ |
|
|
144
|
+
| `NEBULA_NETWORK_CONFIG` | `nebula-network.config.yml` | Path to network config file |
|
|
145
|
+
| `NEBULA_CONFIG_KIT_PKI_PATH` | `.` | Root directory for PKI stores |
|
|
146
|
+
| `NEBULA_CONFIG_KIT_PKI_NAME` | `default` | PKI instance name |
|
|
147
|
+
| `NEBULA_CONFIG_KIT_SOPS_ARGS` | — | Extra SOPS arguments for encrypted keys |
|
|
148
|
+
| `NEBULA_CONFIG_KIT_OUTPUT_FORMAT` | `table` | CLI output format: `table`, `json`, `yaml` |
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Install dependencies
|
|
156
|
+
uv sync --all-extras
|
|
157
|
+
|
|
158
|
+
# Run tests
|
|
159
|
+
just test
|
|
160
|
+
|
|
161
|
+
# Lint + type check
|
|
162
|
+
just lint
|
|
163
|
+
|
|
164
|
+
# All checks
|
|
165
|
+
just check
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "nebula-config-kit"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Define your Nebula mesh network once, generate validated configs for every host"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Dmitry Tatarkin", email = "tatarkin@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
license = "MIT"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
keywords = [
|
|
12
|
+
"nebula",
|
|
13
|
+
"vpn",
|
|
14
|
+
"mesh-network",
|
|
15
|
+
"overlay-network",
|
|
16
|
+
"network-automation",
|
|
17
|
+
"configuration-management",
|
|
18
|
+
"infrastructure",
|
|
19
|
+
"pki",
|
|
20
|
+
]
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Development Status :: 3 - Alpha",
|
|
23
|
+
"Intended Audience :: System Administrators",
|
|
24
|
+
"Intended Audience :: Developers",
|
|
25
|
+
"Topic :: System :: Networking",
|
|
26
|
+
"Topic :: System :: Systems Administration",
|
|
27
|
+
"Topic :: Security",
|
|
28
|
+
"Typing :: Typed",
|
|
29
|
+
"Environment :: Console",
|
|
30
|
+
"Framework :: Pydantic :: 2",
|
|
31
|
+
"Programming Language :: Python :: 3",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Programming Language :: Python :: 3.13",
|
|
34
|
+
]
|
|
35
|
+
dependencies = [
|
|
36
|
+
"pki-kit>=0.0.2",
|
|
37
|
+
"pydantic>=2.0",
|
|
38
|
+
"ruamel-yaml>=0.18",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Homepage = "https://github.com/dtatarkin/nebula-config-kit"
|
|
43
|
+
Repository = "https://github.com/dtatarkin/nebula-config-kit"
|
|
44
|
+
Issues = "https://github.com/dtatarkin/nebula-config-kit/issues"
|
|
45
|
+
Changelog = "https://github.com/dtatarkin/nebula-config-kit/releases"
|
|
46
|
+
|
|
47
|
+
[tool.uv.sources]
|
|
48
|
+
#pki-kit = { path = "lib/pki-kit", editable = true }
|
|
49
|
+
|
|
50
|
+
[project.optional-dependencies]
|
|
51
|
+
cli = ["typer>=0.15", "rich>=13.0"]
|
|
52
|
+
|
|
53
|
+
[project.scripts]
|
|
54
|
+
nebula-config = "nebula_config_kit.cli:main"
|
|
55
|
+
[dependency-groups]
|
|
56
|
+
dev = [
|
|
57
|
+
"codespell",
|
|
58
|
+
"mypy",
|
|
59
|
+
"pre-commit",
|
|
60
|
+
"pytest",
|
|
61
|
+
"python-dotenv[cli]",
|
|
62
|
+
"ruff",
|
|
63
|
+
"ty>=0.0.24",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[tool.uv.build-backend]
|
|
67
|
+
module-name = "nebula_config_kit"
|
|
68
|
+
|
|
69
|
+
[build-system]
|
|
70
|
+
requires = ["uv_build"]
|
|
71
|
+
build-backend = "uv_build"
|
|
72
|
+
|
|
73
|
+
[tool.ruff]
|
|
74
|
+
target-version = "py312"
|
|
75
|
+
line-length = 120
|
|
76
|
+
src = ["src"]
|
|
77
|
+
|
|
78
|
+
[tool.ruff.lint]
|
|
79
|
+
select = ["F", "E", "W", "I", "N", "UP", "B", "A", "C4", "DTZ", "T20", "SIM", "TCH", "RUF", "PT", "S", "ANN"]
|
|
80
|
+
|
|
81
|
+
[tool.ruff.lint.per-file-ignores]
|
|
82
|
+
"tests/**/*.py" = ["ANN", "S101"]
|
|
83
|
+
"src/nebula_config_kit/cli/**/*.py" = ["T20", "TCH"]
|
|
84
|
+
|
|
85
|
+
[tool.ruff.lint.isort]
|
|
86
|
+
known-first-party = ["nebula_config_kit"]
|
|
87
|
+
|
|
88
|
+
[tool.ruff.lint.flake8-type-checking]
|
|
89
|
+
runtime-evaluated-base-classes = ["pydantic.BaseModel"]
|
|
90
|
+
|
|
91
|
+
[tool.mypy]
|
|
92
|
+
strict = true
|
|
93
|
+
plugins = ["pydantic.mypy"]
|
|
94
|
+
mypy_path = "src"
|
|
95
|
+
|
|
96
|
+
[[tool.mypy.overrides]]
|
|
97
|
+
module = "tests.*"
|
|
98
|
+
disallow_untyped_decorators = false
|
|
99
|
+
|
|
100
|
+
[[tool.mypy.overrides]]
|
|
101
|
+
module = "nebula_config_kit.cli.*"
|
|
102
|
+
disallow_untyped_decorators = false
|
|
103
|
+
|
|
104
|
+
[[tool.mypy.overrides]]
|
|
105
|
+
module = "ruamel.*"
|
|
106
|
+
ignore_missing_imports = true
|
|
107
|
+
|
|
108
|
+
[tool.pytest.ini_options]
|
|
109
|
+
testpaths = ["tests"]
|
|
110
|
+
|
|
111
|
+
[tool.ty.rules]
|
|
112
|
+
unused-type-ignore-comment = "ignore"
|
|
113
|
+
unresolved-import = "ignore"
|
|
114
|
+
|
|
115
|
+
[tool.codespell]
|
|
116
|
+
skip = ".git,uv.lock,dist"
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""nebula-config-kit — Nebula overlay network configuration management."""
|
|
2
|
+
|
|
3
|
+
from ipaddress import IPv4Address, IPv4Network
|
|
4
|
+
|
|
5
|
+
from nebula_config_kit.config_gen import render_host_config
|
|
6
|
+
from nebula_config_kit.config_loader import DEFAULT_NEBULA_NETWORK_CONFIG_FILENAME, load_config
|
|
7
|
+
from nebula_config_kit.exceptions import (
|
|
8
|
+
ConfigFileError,
|
|
9
|
+
ConfigRenderError,
|
|
10
|
+
DuplicateIPError,
|
|
11
|
+
HostNotFoundError,
|
|
12
|
+
LighthouseConfigError,
|
|
13
|
+
NebulaConfigError,
|
|
14
|
+
)
|
|
15
|
+
from nebula_config_kit.firewall import resolve_firewall_rules
|
|
16
|
+
from nebula_config_kit.hosts import (
|
|
17
|
+
extract_lighthouses,
|
|
18
|
+
resolve_host_overrides,
|
|
19
|
+
resolve_lighthouses_for_host,
|
|
20
|
+
resolve_relays_for_host,
|
|
21
|
+
)
|
|
22
|
+
from nebula_config_kit.models import (
|
|
23
|
+
CertsConfig,
|
|
24
|
+
FirewallConfig,
|
|
25
|
+
HostConfig,
|
|
26
|
+
HostDefaults,
|
|
27
|
+
HostsConfig,
|
|
28
|
+
LighthouseInfo,
|
|
29
|
+
NebulaNetworkConfig,
|
|
30
|
+
NetworkConfig,
|
|
31
|
+
SecurityGroup,
|
|
32
|
+
)
|
|
33
|
+
from nebula_config_kit.network import get_prefix_length, make_sign_ip
|
|
34
|
+
from nebula_config_kit.orchestration import ResolvedHost, generate_host_config, resolve_host
|
|
35
|
+
from nebula_config_kit.types import Direction, FirewallRule, HostName, Protocol
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"DEFAULT_NEBULA_NETWORK_CONFIG_FILENAME",
|
|
39
|
+
"CertsConfig",
|
|
40
|
+
"ConfigFileError",
|
|
41
|
+
"ConfigRenderError",
|
|
42
|
+
"Direction",
|
|
43
|
+
"DuplicateIPError",
|
|
44
|
+
"FirewallConfig",
|
|
45
|
+
"FirewallRule",
|
|
46
|
+
"HostConfig",
|
|
47
|
+
"HostDefaults",
|
|
48
|
+
"HostName",
|
|
49
|
+
"HostNotFoundError",
|
|
50
|
+
"HostsConfig",
|
|
51
|
+
"IPv4Address",
|
|
52
|
+
"IPv4Network",
|
|
53
|
+
"LighthouseConfigError",
|
|
54
|
+
"LighthouseInfo",
|
|
55
|
+
"NebulaConfigError",
|
|
56
|
+
"NebulaNetworkConfig",
|
|
57
|
+
"NetworkConfig",
|
|
58
|
+
"Protocol",
|
|
59
|
+
"ResolvedHost",
|
|
60
|
+
"SecurityGroup",
|
|
61
|
+
"extract_lighthouses",
|
|
62
|
+
"generate_host_config",
|
|
63
|
+
"get_prefix_length",
|
|
64
|
+
"load_config",
|
|
65
|
+
"make_sign_ip",
|
|
66
|
+
"render_host_config",
|
|
67
|
+
"resolve_firewall_rules",
|
|
68
|
+
"resolve_host",
|
|
69
|
+
"resolve_host_overrides",
|
|
70
|
+
"resolve_lighthouses_for_host",
|
|
71
|
+
"resolve_relays_for_host",
|
|
72
|
+
]
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""nebula-config CLI — optional command-line interface."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from nebula_config_kit.cli._context import CliContext, OutputFormat
|
|
8
|
+
from nebula_config_kit.config_loader import DEFAULT_NEBULA_NETWORK_CONFIG_FILENAME
|
|
9
|
+
from nebula_config_kit.exceptions import NebulaConfigError
|
|
10
|
+
|
|
11
|
+
app = typer.Typer(
|
|
12
|
+
name="nebula-config",
|
|
13
|
+
help="Nebula overlay network configuration management.",
|
|
14
|
+
no_args_is_help=True,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _version_callback(value: bool) -> None:
|
|
19
|
+
if value:
|
|
20
|
+
from importlib.metadata import version
|
|
21
|
+
|
|
22
|
+
print(f"nebula-config {version('nebula-config-kit')}")
|
|
23
|
+
raise typer.Exit
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@app.callback()
|
|
27
|
+
def main_callback(
|
|
28
|
+
ctx: typer.Context,
|
|
29
|
+
config: Annotated[
|
|
30
|
+
str,
|
|
31
|
+
typer.Option(envvar="NEBULA_NETWORK_CONFIG", help="Path to network config file."),
|
|
32
|
+
] = DEFAULT_NEBULA_NETWORK_CONFIG_FILENAME,
|
|
33
|
+
pki_base_path: Annotated[
|
|
34
|
+
str,
|
|
35
|
+
typer.Option(envvar="NEBULA_CONFIG_KIT_PKI_PATH", help="Root directory for pki-kit stores."),
|
|
36
|
+
] = ".",
|
|
37
|
+
pki_name: Annotated[
|
|
38
|
+
str,
|
|
39
|
+
typer.Option(envvar="NEBULA_CONFIG_KIT_PKI_NAME", help="PKI instance name."),
|
|
40
|
+
] = "default",
|
|
41
|
+
sops_args: Annotated[
|
|
42
|
+
str | None,
|
|
43
|
+
typer.Option(envvar="NEBULA_CONFIG_KIT_SOPS_ARGS", help="Extra SOPS arguments (space-separated)."),
|
|
44
|
+
] = None,
|
|
45
|
+
output_format: Annotated[
|
|
46
|
+
OutputFormat,
|
|
47
|
+
typer.Option("--output-format", "-f", envvar="NEBULA_CONFIG_KIT_OUTPUT_FORMAT", help="Output format."),
|
|
48
|
+
] = OutputFormat.TABLE,
|
|
49
|
+
_version: Annotated[
|
|
50
|
+
bool | None,
|
|
51
|
+
typer.Option("--version", callback=_version_callback, is_eager=True, help="Show version and exit."),
|
|
52
|
+
] = None,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""Nebula overlay network configuration management."""
|
|
55
|
+
from pathlib import Path
|
|
56
|
+
|
|
57
|
+
ctx.obj = CliContext(
|
|
58
|
+
config_path=Path(config),
|
|
59
|
+
pki_base_path=Path(pki_base_path),
|
|
60
|
+
pki_name=pki_name,
|
|
61
|
+
sops_args=tuple(sops_args.split()) if sops_args else (),
|
|
62
|
+
output_format=output_format,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# Register subcommand groups (import after app is defined to avoid circular imports)
|
|
67
|
+
from nebula_config_kit.cli._config import config_app # noqa: E402
|
|
68
|
+
from nebula_config_kit.cli._hosts import hosts_app # noqa: E402
|
|
69
|
+
|
|
70
|
+
app.add_typer(config_app)
|
|
71
|
+
app.add_typer(hosts_app)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def main() -> None:
|
|
75
|
+
"""Entry point for the nebula-config CLI."""
|
|
76
|
+
try:
|
|
77
|
+
app()
|
|
78
|
+
except NebulaConfigError as exc:
|
|
79
|
+
from rich.console import Console
|
|
80
|
+
|
|
81
|
+
Console(stderr=True).print(f"[red]Error:[/red] {exc}")
|
|
82
|
+
raise typer.Exit(code=1) from None
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Config generation CLI subcommands."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from nebula_config_kit.cli._context import CliContext
|
|
9
|
+
|
|
10
|
+
config_app = typer.Typer(name="config", help="Configuration generation.", no_args_is_help=True)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _get_ctx(ctx: typer.Context) -> CliContext:
|
|
14
|
+
result: CliContext = ctx.obj
|
|
15
|
+
return result
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@config_app.command("generate")
|
|
19
|
+
def generate(
|
|
20
|
+
ctx: typer.Context,
|
|
21
|
+
name: Annotated[str, typer.Argument(help="Host name to generate config for.")],
|
|
22
|
+
output: Annotated[
|
|
23
|
+
Path | None, typer.Option("--output", "-o", help="Path to write the generated config file.")
|
|
24
|
+
] = None,
|
|
25
|
+
template: Annotated[Path | None, typer.Option(help="Custom Nebula config template.")] = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Generate Nebula configuration for a host."""
|
|
28
|
+
from nebula_config_kit.cli._context import nebula_pki_session
|
|
29
|
+
from nebula_config_kit.config_loader import load_config
|
|
30
|
+
from nebula_config_kit.exceptions import ConfigFileError
|
|
31
|
+
from nebula_config_kit.orchestration import generate_host_config
|
|
32
|
+
from nebula_config_kit.types import HostName
|
|
33
|
+
|
|
34
|
+
cli_ctx = _get_ctx(ctx=ctx)
|
|
35
|
+
config = load_config(cli_ctx.config_path)
|
|
36
|
+
if config is None:
|
|
37
|
+
raise ConfigFileError(message="Configuration file not found.")
|
|
38
|
+
|
|
39
|
+
with nebula_pki_session(cli_ctx) as pki:
|
|
40
|
+
config_yaml = generate_host_config(
|
|
41
|
+
HostName(name),
|
|
42
|
+
config=config,
|
|
43
|
+
pki=pki,
|
|
44
|
+
template_path=template,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if output is not None:
|
|
48
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
49
|
+
output.write_text(config_yaml)
|
|
50
|
+
print(f"Config written to {output}")
|
|
51
|
+
else:
|
|
52
|
+
print(config_yaml, end="")
|