fixes, cleanup, pyproject.toml
This commit is contained in:
@@ -29,24 +29,24 @@ def make_arg_parser():
|
|||||||
description="push TLS privkey & certificate to MikroTik RouterOS router",
|
description="push TLS privkey & certificate to MikroTik RouterOS router",
|
||||||
)
|
)
|
||||||
|
|
||||||
subparsers = parser.add_subparsers(dest="subcommand")
|
subparsers = parser.add_subparsers(dest="subcommand", required=True)
|
||||||
|
|
||||||
install_parser = subparsers.add_parser(
|
deploy_parser = subparsers.add_parser(
|
||||||
"install", help="push TLS privkey & certificate to MikroTik RouterOS router"
|
"deploy", help="deploy TLS privkey & certificate to MikroTik RouterOS router"
|
||||||
)
|
)
|
||||||
install_parser.add_argument(
|
deploy_parser.add_argument("--ssh-config", type=Path, help="ssh config file")
|
||||||
"-k", "--privkey", type=Path, required=True, help="private key file"
|
deploy_parser.add_argument("--ssh-user", help="target ssh user")
|
||||||
|
deploy_parser.add_argument("--ssh-port", type=int, help="target ssh port")
|
||||||
|
deploy_parser.add_argument("--ssh-host", required=True, help="target ssh host")
|
||||||
|
deploy_parser.add_argument(
|
||||||
|
"-k", "--private-key", type=Path, required=True, help="PEM private key file"
|
||||||
)
|
)
|
||||||
install_parser.add_argument(
|
deploy_parser.add_argument(
|
||||||
"--cert", type=Path, required=True, help="certificate file"
|
"--cert", type=Path, required=True, help="PEM certificate file"
|
||||||
)
|
)
|
||||||
install_parser.add_argument(
|
deploy_parser.add_argument(
|
||||||
"--chain", type=Path, help="separate certificate chain file (optional)"
|
"--chain", type=Path, help="separate certificate chain file (optional)"
|
||||||
)
|
)
|
||||||
install_parser.add_argument("--ssh-config", type=Path, help="ssh config file")
|
|
||||||
install_parser.add_argument("--ssh-host", required=True, help="target ssh host")
|
|
||||||
install_parser.add_argument("--ssh-user", help="target ssh user")
|
|
||||||
install_parser.add_argument("--ssh-port", type=int, help="target ssh port")
|
|
||||||
|
|
||||||
fingerprint_parser = subparsers.add_parser(
|
fingerprint_parser = subparsers.add_parser(
|
||||||
"fingerprint", aliases=["fpr"], help="calculate fingerprint of certificate(s)"
|
"fingerprint", aliases=["fpr"], help="calculate fingerprint of certificate(s)"
|
||||||
@@ -54,22 +54,21 @@ def make_arg_parser():
|
|||||||
fingerprint_parser.add_argument(
|
fingerprint_parser.add_argument(
|
||||||
dest="files",
|
dest="files",
|
||||||
metavar="cert.pem",
|
metavar="cert.pem",
|
||||||
nargs='+',
|
nargs="+",
|
||||||
type=Path,
|
type=Path,
|
||||||
help="PEM certificate file to read",
|
help="PEM certificate file to read",
|
||||||
)
|
)
|
||||||
|
|
||||||
skid_parser = subparsers.add_parser(
|
skid_parser = subparsers.add_parser(
|
||||||
#"skid", help="calculate SubjectKeyIdentifier of certificate(s) or key(s)"
|
|
||||||
"skid", help="show the SubjectKeyIdentifier of certificate(s)"
|
"skid", help="show the SubjectKeyIdentifier of certificate(s)"
|
||||||
)
|
)
|
||||||
skid_parser.add_argument(
|
skid_parser.add_argument(
|
||||||
dest="files",
|
dest="files",
|
||||||
#metavar="file.pem",
|
# metavar="file.pem",
|
||||||
metavar="cert.pem",
|
metavar="cert.pem",
|
||||||
nargs='+',
|
nargs="+",
|
||||||
type=Path,
|
type=Path,
|
||||||
#help="PEM file to read",
|
# help="PEM file to read",
|
||||||
help="PEM certificate file to read",
|
help="PEM certificate file to read",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -85,10 +84,10 @@ def parse_args():
|
|||||||
def main():
|
def main():
|
||||||
args, parser = parse_args()
|
args, parser = parse_args()
|
||||||
|
|
||||||
if args.subcommand == "install":
|
if args.subcommand == "deploy":
|
||||||
assert ":" not in args.ssh_host
|
assert ":" not in args.ssh_host
|
||||||
|
|
||||||
privkey_data = args.privkey.read_text()
|
privkey_data = args.private_key.read_text()
|
||||||
cert_data = args.cert.read_text()
|
cert_data = args.cert.read_text()
|
||||||
chain_data = args.chain.read_text() if args.chain is not None else None
|
chain_data = args.chain.read_text() if args.chain is not None else None
|
||||||
|
|
||||||
@@ -106,7 +105,6 @@ def main():
|
|||||||
|
|
||||||
ros_remote.use_certificate(fingerprint)
|
ros_remote.use_certificate(fingerprint)
|
||||||
|
|
||||||
|
|
||||||
elif args.subcommand in ("fingerprint", "fpr"):
|
elif args.subcommand in ("fingerprint", "fpr"):
|
||||||
for path in args.files:
|
for path in args.files:
|
||||||
try:
|
try:
|
||||||
@@ -116,7 +114,7 @@ def main():
|
|||||||
exc.add_note(f"path={path}")
|
exc.add_note(f"path={path}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
elif args.subcommand in ("skid"):
|
elif args.subcommand == "skid":
|
||||||
for path in args.files:
|
for path in args.files:
|
||||||
try:
|
try:
|
||||||
for cert_obj in x509.load_pem_x509_certificates(path.read_bytes()):
|
for cert_obj in x509.load_pem_x509_certificates(path.read_bytes()):
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class SSHConnector(Connector):
|
|||||||
self, cmdline: str, text: bool = False, capture: bool = False
|
self, cmdline: str, text: bool = False, capture: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
cmd = self._ssh_args([self.ssh_host, cmdline])
|
cmd = self._ssh_args([self.ssh_host, cmdline])
|
||||||
#print("running: ", shlex.join(cmd))
|
# print("running: ", shlex.join(cmd))
|
||||||
if capture:
|
if capture:
|
||||||
return subprocess.check_output(cmd, text=text)
|
return subprocess.check_output(cmd, text=text)
|
||||||
subprocess.run(cmd, check=True)
|
subprocess.run(cmd, check=True)
|
||||||
@@ -106,7 +106,9 @@ class SSHConnector(Connector):
|
|||||||
def create_remote_files(self, content_by_name: dict, remote_directory: str):
|
def create_remote_files(self, content_by_name: dict, remote_directory: str):
|
||||||
if not content_by_name:
|
if not content_by_name:
|
||||||
raise ValueError("require at least one file to copy")
|
raise ValueError("require at least one file to copy")
|
||||||
with tempfile.TemporaryDirectory(dir=self.temporary_directory, prefix="mtik-connector-tmp") as td:
|
with tempfile.TemporaryDirectory(
|
||||||
|
dir=self.temporary_directory, prefix="mtik-connector-tmp"
|
||||||
|
) as td:
|
||||||
tempfile_paths = []
|
tempfile_paths = []
|
||||||
|
|
||||||
# Write the files to a temporary directory
|
# Write the files to a temporary directory
|
||||||
@@ -127,5 +129,5 @@ class SSHConnector(Connector):
|
|||||||
f"{self.ssh_host}:{remote_directory}",
|
f"{self.ssh_host}:{remote_directory}",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
#print("running: ", shlex.join(cmd))
|
# print("running: ", shlex.join(cmd))
|
||||||
subprocess.run(cmd, check=True)
|
subprocess.run(cmd, check=True)
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ class RouterOS:
|
|||||||
raise ValueError(f"illegal fingerprint {fingerprint!r}")
|
raise ValueError(f"illegal fingerprint {fingerprint!r}")
|
||||||
cmds = [
|
cmds = [
|
||||||
f'/ip/service set api-ssl,www-ssl certificate=[/certificate find where fingerprint="{fingerprint}"]',
|
f'/ip/service set api-ssl,www-ssl certificate=[/certificate find where fingerprint="{fingerprint}"]',
|
||||||
f':put [:serialize to=json value={{[/certificate get [/ip/service get api-ssl certificate] fingerprint],[/certificate get [/ip/service get www-ssl certificate] fingerprint]}}]'
|
":put [:serialize to=json value={[/certificate get [/ip/service get api-ssl certificate] fingerprint],[/certificate get [/ip/service get www-ssl certificate] fingerprint]}]",
|
||||||
]
|
]
|
||||||
remote_cmdline = "\n".join(cmds)
|
remote_cmdline = "\n".join(cmds)
|
||||||
raw_result = self.connector.invoke_remote_command(
|
raw_result = self.connector.invoke_remote_command(
|
||||||
|
|||||||
40
pyproject.toml
Normal file
40
pyproject.toml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[project]
|
||||||
|
name = "mtik-cert-pusher"
|
||||||
|
version = "0.0.1"
|
||||||
|
description = "Script that pushes a TLS private key and certificate chain to a host running MikroTik RouterOS"
|
||||||
|
authors = [
|
||||||
|
{name = "Darsey Litzenberger",email = "dlitz@dlitz.net"}
|
||||||
|
]
|
||||||
|
license = "MIT"
|
||||||
|
#readme = "README.md"
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
dependencies = [
|
||||||
|
"cryptography (>=40.0.0)"
|
||||||
|
]
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"black (>=26.3.1,<27.0.0)",
|
||||||
|
"isort (>=8.0.1,<9.0.0)"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
mtik-cert-pusher = "mtik_cert_pusher.__main__:main"
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
# make black compatible with isort
|
||||||
|
line_length = 88
|
||||||
|
|
||||||
|
[tool.flake8]
|
||||||
|
max-line-length=88
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
# make isort compatible with black
|
||||||
|
multi_line_output = 3
|
||||||
|
line_length = 88
|
||||||
|
include_trailing_comma = true
|
||||||
Reference in New Issue
Block a user