Skip to content

Commit 5c10ff5

Browse files
committed
feat: support for proxmox clusters dehind a reverse proxy with certificate-based authentication
1 parent 34efd0c commit 5c10ff5

File tree

3 files changed

+42
-5
lines changed

3 files changed

+42
-5
lines changed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,25 @@ clusters:
8181
token_value: randomtokenvalue
8282
```
8383

84+
### Reverse proxies
85+
86+
`pvecontrol` supports certificate-based authentication to a reverse proxy. Which makes it suitable for use with tools like [teleport](https://goteleport.com/docs/enroll-resources/application-access/guides/connecting-apps/) using teleport apps.
87+
88+
```yaml
89+
clusters:
90+
- name: fr-par-1
91+
host: localhost
92+
user: pvecontrol@pve
93+
password: my.password.is.weak
94+
proxy_certificate_path: /tmp/proxmox-reverse-proxy.pem
95+
proxy_certificate_key_path: /tmp/proxmox-reverse-proxy
96+
```
97+
98+
CAUTION: environment variable and `~` expansion and are not supported.
99+
84100
### Better security
85101

86-
Instead of specifying users and passwords in plain text in the configuration file, you can use the shell command substitution syntax `$(...)` inside the `user` and `password` fields; for instance:
102+
Instead of specifying users, passwords and certificates paths in plain text in the configuration file, you can use the shell command substitution syntax `$(...)` inside the `user`, `password`, `proxy_certificate_path` and `proxy_certificate_path_key` fields; for instance:
87103

88104
```yaml
89105
clusters:

src/pvecontrol/__init__.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import logging
66
import re
77
import subprocess
8+
9+
from importlib.metadata import version
10+
811
import urllib3
912
import shtab
10-
from importlib.metadata import version
1113

1214
from pvecontrol import actions, node, vm, task, storage
1315
from pvecontrol.cluster import PVECluster
@@ -72,8 +74,8 @@ def filter_type(x):
7274

7375
def _parser():
7476
parser = argparse.ArgumentParser(
75-
description=f"Proxmox VE control CLI, version: {version(__name__)}",
76-
epilog="Made with love by Enix.io")
77+
description=f"Proxmox VE control CLI, version: {version(__name__)}", epilog="Made with love by Enix.io"
78+
)
7779
parser.add_argument("-v", "--verbose", action="store_true")
7880
parser.add_argument("--debug", action="store_true")
7981
parser.add_argument(
@@ -170,14 +172,31 @@ def run_auth_commands(clusterconfig):
170172
auth = {}
171173
regex = r"^\$\((.*)\)$"
172174

173-
for key in ("user", "password", "token_name", "token_value"):
175+
for key in (
176+
"user",
177+
"password",
178+
"token_name",
179+
"token_value",
180+
"proxy_certificate_path",
181+
"proxy_certificate_key_path",
182+
):
174183
value = clusterconfig.get(key)
175184
if value is not None:
176185
result = re.match(regex, value)
177186
if result:
178187
value = _execute_command(result.group(1))
179188
auth[key] = value
180189

190+
proxy_certificate = auth.get("proxy_certificate_path")
191+
proxy_certificate_key = auth.get("proxy_certificate_key_path")
192+
if proxy_certificate != "" and proxy_certificate_key != "":
193+
auth["cert"] = (proxy_certificate, proxy_certificate_key)
194+
195+
if "proxy_certificate_path" in auth:
196+
del auth["proxy_certificate_path"]
197+
if "proxy_certificate_key_path" in auth:
198+
del auth["proxy_certificate_key_path"]
199+
181200
logging.debug("Auth: %s", auth)
182201
# check for "incompatible" auth options
183202
if "password" in auth and ("token_name" in auth or "token_value" in auth):

src/pvecontrol/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
"host": str,
1111
"user": str,
1212
"password": confuse.Optional(str, None),
13+
"proxy_certificate_path": confuse.Optional(str, None),
14+
"proxy_certificate_key_path": confuse.Optional(str, None),
1315
"token_name": confuse.Optional(str, None),
1416
"token_value": confuse.Optional(str, None),
1517
"node": confuse.Optional(

0 commit comments

Comments
 (0)