{"id":13337932,"url":"https://github.com/mikey-no/cert_tool","last_synced_at":"2025-03-11T08:32:05.687Z","repository":{"id":37240454,"uuid":"438030615","full_name":"mikey-no/cert_tool","owner":"mikey-no","description":"Using the python cryptography module to create x509 certificates in turn for selfsigned, TLS and MTLS Servers","archived":false,"fork":false,"pushed_at":"2024-06-06T21:35:27.000Z","size":145,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-23T20:11:21.096Z","etag":null,"topics":["fastapi","multiprocessing","pytest","python","requests","ssl","tls"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikey-no.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-13T21:30:24.000Z","updated_at":"2024-06-06T21:35:30.000Z","dependencies_parsed_at":"2024-10-23T19:27:59.523Z","dependency_job_id":"3e92a8f6-fcaf-449e-bcc2-f3ccb7f13498","html_url":"https://github.com/mikey-no/cert_tool","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikey-no%2Fcert_tool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikey-no%2Fcert_tool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikey-no%2Fcert_tool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikey-no%2Fcert_tool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikey-no","download_url":"https://codeload.github.com/mikey-no/cert_tool/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243000833,"owners_count":20219751,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastapi","multiprocessing","pytest","python","requests","ssl","tls"],"created_at":"2024-07-29T19:15:16.235Z","updated_at":"2025-03-11T08:32:05.410Z","avatar_url":"https://github.com/mikey-no.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CertTools\nUsing python [cryptography module](https://pypi.org/project/cryptography/) to create x509 certificates for:\n- self signed TLS Server\n- CA signed TLS Server\n- CA signed TLS Server and client Mutual TLS Certificate\n\nServer is created with [FastAPI](https://fastapi.tiangolo.com/) and [Uvicorn](https://www.uvicorn.org/).\nClient with [requests](https://docs.python-requests.org/en/latest/) making use of the certificates.\n\nThe servers and client are run with [pytest](https://docs.pytest.org/), testing the above certificates are all working. \n\nThe FastAPI Uvicorn server is run in another process than the clients using [multiprocessing](https://docs.python.org/3/library/multiprocessing.html).\n\n\u003e You could then use these certificates and keys within a TLS terminating proxy in front of your application without \n\u003e wondering if the certificates are even working or not. :relieved:\n\n\u003e I would only use this in a lab context. You would have to trust the certificate authority!!\n\nAn update of python and requirements for creating a leaf csr file has shown locally to be successful (5 Jun 2024)\nThe CSR was checked with  certutil .\\dev-DESKTOP-ZZZZZZ56_csr.pem\n\n\n## Runs on\n\n- Python 3.10 and 3.12.3 (Windows 10, Ubuntu 20.04)\n- pytests do not run on the Ubuntu OS for a reason(s) I do not understand (error: \"... port in use ...\" - but not so \nfar as I can tell)...\n\n# Setup\n\nfrom the project root folder ```cert_tool```\n```commandline\npython -m venv venv\n.\\venv\\scripts\\activate.bat\npip install -r requirements.txt\n```\n\n# Test\n\n```commandline\ncd cert_tool\npython -m pytest --capture=no\n```\n\n- **pytest --capture=no**  - option shows the standard output as the tests run\n- **python -m**            - calling via python will also add the current directory to sys.path (see: [pytest usage](https://www.pytest.org/en/7.1.x/how-to/usage.html#usage)) \n\n# Run\n\n## Run from the CA\n\nInitialise the Certificate Authority\n\n```commandline\npython .\\app\\main_root.py --prefix dev --create_root --location certs\\dev\\root\n```\n\n## Run the api web interface to the root CA\n\nAssuming your CA is running from a host with this url: 'localhost'\n\n```commandline\npython .\\app\\main_api.py --prefix dev --location certs\\dev\\root\n```\nIn another window open...\n```commandline\nfirefox http://localhost\n```\n\nSee the API docs: http://localhost/docs\n\nThe ca works on http not https to enable a client to start the communication with no prior root ca installed.\n\n### settings.ini\nmain_api will take a settings.ini file in subdirectory of the current working directory with the prefix and location values.\n\n## On the leaf server\n\nRun the command to request a certificate from the CA\n```commandline\npython .\\app\\main_leaf.py --prefix dev --ca_url http://localhost --san leaf.example.internal redleaf.example.internal --location cert\\dev\\leaf\n```\n\nThe root ca signed cert is downloaded to ```cert\\dev\\leaf\\\u003cleaf fdqn\u003e_cert.pem```, see the console output.\n\nwhere:\n1) --ca_url is the url of the CA\n2) --san is a optional list of subject alternate names\n   1) The CA assumes you want localhost and the socket.fqdn() name from the leaf server adding to the san list by default\n3) prefix of the ca and leaf server must match\n\nThe leaf cert name is the response back from the CA and is saved to a file prefixed with the socket.fqdn() name pem file.\n\n## Run from the Leaf Server (from command line only)\n\nInitialise the Leaf private, public and create a certificate signing request\n\n```commandline\npython .\\app\\main_leaf.py --prefix dev --san abc.example.internal bcd.example.internal\n```\n\n## Run from the CA (again)\n\nSign the certificate signing request creating a leaf certificate, using the command line tool rather than the root_api\nweb api.\n\n```commandline\npython .\\app\\main_root.py --prefix dev --sign_csr certs/dev/{socket.getfqdn()}_csr.pem\n```\n\n## Run just CertTool\n\nThis command is show for completeness, it is not used anymore, it was one of the development stages the application \npassed through.\n\nJust CertTool, without the functionality broken out into separate programmes (as above)\n\n```commandline\npython .\\app\\CertTool.py\n```\n\nThen open in a web browser: \n\n- http:      ```https://localhost:5000```\n- tls:       ```https://localhost:5001```\n- mtls:      ```https://localhost:5002```\n\nCertTool would need to be commented differently to run each of the above configurations. The 'recipes' are included \nin the script (CertTool.py). \n\n- NB 1: the hostname of the leaf server will be automatically used in the certificate file name\n- NB 2: to prefix must be the same for each of these three commands\n\nThe command to run mTLS not implemented in a stand-alone application like has been done with the leaf and root scripts.\nThe functionality is within CertTool.py, just not exposed.\n\n## Overview of how it works\n\n1. import\n```python\nfrom multiprocessing import Process\n```\n- for example TLS Server running with uvicorn, note the certificate and private key are passed in as parameters to the function. \n  - the private key relates to the certificate and as 'only you' have the private key then the cert must be yours\n```python\n\ndef tls_server(cert_file: pathlib.Path, private_key_file: pathlib.Path):\n    host = 'localhost'\n    port = 5001\n    log.info(f'Running TLS server: {host}:{port}')\n    uvicorn.run(app,\n                host=host,\n                port=port,\n                log_level=\"debug\",\n                ssl_keyfile=private_key_file,\n                ssl_certfile=cert_file,\n                )\n```\n2. run the TLS Server process \n  - yield the new process, pass in the parameters as an enum to the tls_server above\n```python\n\ndef tls_web_server_process(cert_path, private_key_path):\n    log.info(f'Starting TLS server process: {cert_path}')\n    p = Process(target=tls_server, args=(cert_path, private_key_path,), daemon=True)\n    p.start()\n    log.info(f'TLS Server process started with cert: {cert_path}')\n    yield p\n    p.kill()  # Cleanup after test\n    log.info('TLS Server process stopped')\n    return\n```\n3. in the test function after the certs are created run the tls web server\n  - then call the returned iterator (from the above yield generator to close the server down when the tests are complete)\n```python\n    web_server_process_handle = tls_web_server_process(cert_tool_leaf.cert_file, cert_tool_leaf.private_key_file)\n    next(web_server_process_handle)  # use next to use the yielded iterator\n    log.info('testing the web server and certs')\n    r = requests.get('https://localhost:5001', verify=cert_tool_root.cert_file, )\n    # assert some tests on r\n    try:\n        next(web_server_process_handle)\n    except StopIteration:\n        pass\n```\n\n# Other\n\n1) The private key may be encrypted (but has not been fully tested)\n2) Not sure why I didn't use the [TestClient functionality in Starlettle](https://www.starlette.io/testclient/) more\n3) Log settings not fully tested or implemented\n4) Requests needs to be retired and replaced with httpx\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikey-no%2Fcert_tool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikey-no%2Fcert_tool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikey-no%2Fcert_tool/lists"}