196 lines
6.5 KiB
Python
196 lines
6.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Probe minimal cert_store payloads for Console uploads."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import base64
|
|
import getpass
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
from certctl.console import NitroConsoleClient, NitroError
|
|
|
|
|
|
def _read_bytes(path: str) -> bytes:
|
|
return Path(path).expanduser().read_bytes()
|
|
|
|
|
|
def _b64_bytes(data: bytes) -> str:
|
|
return base64.b64encode(data).decode("ascii").rstrip("%")
|
|
|
|
|
|
def _load_console_password(username: str, console: str, provided: Optional[str]) -> str:
|
|
if provided:
|
|
return provided
|
|
env_pw = os.environ.get("CERTCTL_CONSOLE_PASSWORD")
|
|
if env_pw:
|
|
return env_pw
|
|
return getpass.getpass(f"Console password for {username}@{console}: ")
|
|
|
|
|
|
def _load_key_password(provided: Optional[str]) -> str:
|
|
if provided:
|
|
return provided
|
|
env_pw = os.environ.get("CERTCTL_KEY_PASSPHRASE")
|
|
if env_pw:
|
|
return env_pw
|
|
return getpass.getpass("Key passphrase (AES-256): ")
|
|
|
|
|
|
def _probe_server(
|
|
client: NitroConsoleClient,
|
|
*,
|
|
name: str,
|
|
cert_path: str,
|
|
key_path: str,
|
|
passphrase: str,
|
|
domain: Optional[str],
|
|
cert_file_name: Optional[str],
|
|
cert_type: Optional[str],
|
|
include_key_file: bool,
|
|
dry_run: bool,
|
|
) -> None:
|
|
cert_bytes = _read_bytes(cert_path)
|
|
key_bytes = _read_bytes(key_path)
|
|
cert_b64 = _b64_bytes(cert_bytes)
|
|
key_b64 = _b64_bytes(key_bytes)
|
|
payload = {
|
|
"cert_store": {
|
|
"name": name,
|
|
"cert_format": "PEM",
|
|
"cert_data": {"file_name": cert_file_name or f"{name}.pem", "file_data": cert_b64},
|
|
"key_data": key_b64,
|
|
"password": passphrase,
|
|
}
|
|
}
|
|
if cert_type:
|
|
payload["cert_store"]["cert_type"] = cert_type
|
|
if domain:
|
|
payload["cert_store"]["domain"] = domain
|
|
if include_key_file:
|
|
payload["cert_store"]["key_file"] = name
|
|
print(
|
|
"[probe] server payload sizes:"
|
|
f" cert_b64={len(cert_b64)}"
|
|
f" key_b64={len(key_b64)}"
|
|
)
|
|
if dry_run:
|
|
print("[probe] dry run; skipping server cert_store upload.")
|
|
return
|
|
response = client.post_json("/nitro/v2/config/cert_store", payload)
|
|
print("[probe] server response:", response)
|
|
|
|
|
|
def _probe_ca(
|
|
client: NitroConsoleClient,
|
|
*,
|
|
name: str,
|
|
cert_path: str,
|
|
cert_file_name: Optional[str],
|
|
cert_type: Optional[str],
|
|
dry_run: bool,
|
|
) -> None:
|
|
cert_bytes = _read_bytes(cert_path)
|
|
cert_b64 = _b64_bytes(cert_bytes)
|
|
payload = {
|
|
"cert_store": {
|
|
"name": name,
|
|
"cert_format": "PEM",
|
|
"cert_data": {"file_name": cert_file_name or f"{name}.pem", "file_data": cert_b64},
|
|
}
|
|
}
|
|
if cert_type:
|
|
payload["cert_store"]["cert_type"] = cert_type
|
|
print(f"[probe] CA payload sizes: cert_b64={len(cert_b64)}")
|
|
if dry_run:
|
|
print("[probe] dry run; skipping CA cert_store upload.")
|
|
return
|
|
response = client.post_json("/nitro/v2/config/cert_store", payload)
|
|
print("[probe] CA response:", response)
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(
|
|
description="Probe minimal cert_store uploads (server cert/key and optional CA cert)."
|
|
)
|
|
parser.add_argument("--console", required=True, help="Console base URL, e.g. https://192.168.0.1")
|
|
parser.add_argument("--user", required=True, help="Console username")
|
|
parser.add_argument("--password", help="Console password (or CERTCTL_CONSOLE_PASSWORD)")
|
|
parser.add_argument("--timeout", type=int, default=60, help="HTTP timeout in seconds")
|
|
parser.add_argument("--insecure", action="store_true", help="Disable TLS verification")
|
|
parser.add_argument("--ca-bundle", help="CA bundle path for TLS verification")
|
|
parser.add_argument("--dry-run", action="store_true", help="Print sizes only; do not POST")
|
|
|
|
parser.add_argument("--name", help="Cert_store name for server cert")
|
|
parser.add_argument("--cert", dest="cert_path", help="Server certificate path (PEM)")
|
|
parser.add_argument("--key", dest="key_path", help="Server key path (PEM)")
|
|
parser.add_argument("--key-pass", dest="key_pass", help="Key passphrase")
|
|
parser.add_argument("--domain", help="Domain for server cert_store entry")
|
|
parser.add_argument("--cert-file-name", help="Override server cert file_name field")
|
|
parser.add_argument("--cert-type", help="Set cert_type in server payload (e.g., server_cert)")
|
|
parser.add_argument(
|
|
"--include-key-file",
|
|
action="store_true",
|
|
help="Include key_file field in payload",
|
|
)
|
|
|
|
parser.add_argument("--ca-name", help="Cert_store name for CA cert")
|
|
parser.add_argument("--ca-cert", dest="ca_cert_path", help="CA certificate path (PEM)")
|
|
parser.add_argument("--ca-cert-file-name", help="Override CA cert file_name field")
|
|
parser.add_argument("--ca-cert-type", help="Set cert_type in CA payload (e.g., root_cert)")
|
|
|
|
args = parser.parse_args()
|
|
|
|
if not args.name and not args.ca_name:
|
|
raise SystemExit("Provide --name for server probe and/or --ca-name for CA probe.")
|
|
if args.name and not (args.cert_path and args.key_path):
|
|
raise SystemExit("Server probe requires --name, --cert, and --key.")
|
|
if args.ca_name and not args.ca_cert_path:
|
|
raise SystemExit("CA probe requires --ca-name and --ca-cert.")
|
|
|
|
verify: object
|
|
if args.insecure:
|
|
verify = False
|
|
elif args.ca_bundle:
|
|
verify = args.ca_bundle
|
|
else:
|
|
verify = True
|
|
|
|
client = NitroConsoleClient(base=args.console, verify=verify, timeout=args.timeout)
|
|
password = _load_console_password(args.user, args.console, args.password)
|
|
client.login(args.user, password)
|
|
|
|
if args.ca_name:
|
|
_probe_ca(
|
|
client,
|
|
name=args.ca_name,
|
|
cert_path=args.ca_cert_path,
|
|
cert_file_name=args.ca_cert_file_name,
|
|
cert_type=args.ca_cert_type,
|
|
dry_run=args.dry_run,
|
|
)
|
|
|
|
if args.name:
|
|
key_pass = _load_key_password(args.key_pass)
|
|
_probe_server(
|
|
client,
|
|
name=args.name,
|
|
cert_path=args.cert_path,
|
|
key_path=args.key_path,
|
|
passphrase=key_pass,
|
|
domain=args.domain,
|
|
cert_file_name=args.cert_file_name,
|
|
cert_type=args.cert_type,
|
|
include_key_file=args.include_key_file,
|
|
dry_run=args.dry_run,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except NitroError as exc:
|
|
raise SystemExit(str(exc)) from exc
|