crude EasyRSA class
This commit is contained in:
parent
e3acc9b7e0
commit
f671e1efa9
4 changed files with 141 additions and 1 deletions
|
@ -17,6 +17,14 @@ RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/
|
||||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
export DEBIAN_FRONTEND=noninteractive; \
|
||||||
|
apt-get update; apt-get -y install --no-install-recommends \
|
||||||
|
easy-rsa \
|
||||||
|
; rm -rf /var/lib/apt/lists/*; \
|
||||||
|
ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin;
|
||||||
|
|
||||||
# [Optional] Uncomment this line to install global node packages.
|
# [Optional] Uncomment this line to install global node packages.
|
||||||
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
|
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
|
||||||
|
|
||||||
|
|
112
api/kiwi_vpn_api/easyrsa.py
Normal file
112
api/kiwi_vpn_api/easyrsa.py
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
import subprocess
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from OpenSSL import crypto
|
||||||
|
from passlib import pwd
|
||||||
|
|
||||||
|
|
||||||
|
class EasyRSA:
|
||||||
|
__directory: Path | None
|
||||||
|
__ca_password: str | None
|
||||||
|
|
||||||
|
def __init__(self, directory: Path) -> None:
|
||||||
|
self.__directory = directory
|
||||||
|
|
||||||
|
def set_ca_password(self, password: str | None = None) -> None:
|
||||||
|
if password is None:
|
||||||
|
password = pwd.genword(length=32, charset="ascii_62")
|
||||||
|
|
||||||
|
self.__ca_password = password
|
||||||
|
print(self.__ca_password)
|
||||||
|
|
||||||
|
def __easyrsa(
|
||||||
|
self,
|
||||||
|
*easyrsa_args: str,
|
||||||
|
) -> subprocess.CompletedProcess:
|
||||||
|
return subprocess.run(
|
||||||
|
[
|
||||||
|
"easyrsa", "--batch",
|
||||||
|
f"--pki-dir={self.__directory}",
|
||||||
|
*easyrsa_args,
|
||||||
|
],
|
||||||
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __build_cert(
|
||||||
|
self,
|
||||||
|
cert_filename: Path,
|
||||||
|
*easyrsa_args: str,
|
||||||
|
) -> crypto.X509:
|
||||||
|
self.__easyrsa(*easyrsa_args)
|
||||||
|
|
||||||
|
with open(
|
||||||
|
self.__directory.joinpath(cert_filename), "r"
|
||||||
|
) as cert_file:
|
||||||
|
return crypto.load_certificate(
|
||||||
|
crypto.FILETYPE_PEM, cert_file.read()
|
||||||
|
)
|
||||||
|
|
||||||
|
def init_pki(self) -> bool:
|
||||||
|
self.__easyrsa("init-pki")
|
||||||
|
|
||||||
|
def build_ca(
|
||||||
|
self,
|
||||||
|
days: int = 365 * 50,
|
||||||
|
cn: str = "kiwi-ca"
|
||||||
|
) -> crypto.X509:
|
||||||
|
return self.__build_cert(
|
||||||
|
Path("ca.crt"),
|
||||||
|
|
||||||
|
f"--passout=pass:{self.__ca_password}",
|
||||||
|
f"--passin=pass:{self.__ca_password}",
|
||||||
|
|
||||||
|
# "--dn-mode=org",
|
||||||
|
# "--req-c=EX",
|
||||||
|
# "--req-st=EXAMPLE",
|
||||||
|
# "--req-city=EXAMPLE",
|
||||||
|
# "--req-org=EXAMPLE",
|
||||||
|
# "--req-ou=EXAMPLE",
|
||||||
|
# "--req-email=EXAMPLE",
|
||||||
|
|
||||||
|
f"--req-cn={cn}",
|
||||||
|
f"--days={days}",
|
||||||
|
|
||||||
|
"build-ca",
|
||||||
|
)
|
||||||
|
|
||||||
|
def issue(
|
||||||
|
self,
|
||||||
|
days: int = 365 * 50,
|
||||||
|
cn: str = "kiwi-vpn",
|
||||||
|
cert_type: str = "client"
|
||||||
|
) -> crypto.X509:
|
||||||
|
return self.__build_cert(
|
||||||
|
Path(f"issued/{cn}.crt"),
|
||||||
|
|
||||||
|
f"--passin=pass:{self.__ca_password}",
|
||||||
|
f"--days={days}",
|
||||||
|
|
||||||
|
f"build-{cert_type}-full",
|
||||||
|
cn,
|
||||||
|
"nopass",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
rsa = EasyRSA(Path("tmp/pki"))
|
||||||
|
rsa.init_pki()
|
||||||
|
rsa.set_ca_password()
|
||||||
|
|
||||||
|
ca = rsa.build_ca()
|
||||||
|
server = rsa.issue(cert_type="server", cn="kiwi-server")
|
||||||
|
client = rsa.issue(cert_type="client", cn="kiwi-client")
|
||||||
|
|
||||||
|
print(ca.get_subject())
|
||||||
|
print(server.get_subject())
|
||||||
|
print(client.get_subject())
|
||||||
|
|
||||||
|
date_format, encoding = "%Y%m%d%H%M%SZ", "ascii"
|
||||||
|
print(datetime.strptime(
|
||||||
|
client.get_notAfter().decode(encoding), date_format))
|
21
api/poetry.lock
generated
21
api/poetry.lock
generated
|
@ -292,6 +292,21 @@ typing-extensions = ">=3.7.4.3"
|
||||||
dotenv = ["python-dotenv (>=0.10.4)"]
|
dotenv = ["python-dotenv (>=0.10.4)"]
|
||||||
email = ["email-validator (>=1.0.3)"]
|
email = ["email-validator (>=1.0.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyopenssl"
|
||||||
|
version = "22.0.0"
|
||||||
|
description = "Python wrapper module around the OpenSSL library"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
cryptography = ">=35.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
test = ["flaky", "pretend", "pytest (>=3.0.1)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyparsing"
|
name = "pyparsing"
|
||||||
version = "3.0.7"
|
version = "3.0.7"
|
||||||
|
@ -462,7 +477,7 @@ standard = ["websockets (>=10.0)", "httptools (>=0.4.0)", "watchgod (>=0.6)", "p
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "13a440999017394ffb9361fe45548d43f8c3e2b039dabceccae6f585d439c464"
|
content-hash = "432d2933102f8a0091cec1b5484944a0211ca74c5dc9b65877d99d7bd160e4bb"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
anyio = [
|
anyio = [
|
||||||
|
@ -751,6 +766,10 @@ pydantic = [
|
||||||
{file = "pydantic-1.9.0-py3-none-any.whl", hash = "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3"},
|
{file = "pydantic-1.9.0-py3-none-any.whl", hash = "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3"},
|
||||||
{file = "pydantic-1.9.0.tar.gz", hash = "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a"},
|
{file = "pydantic-1.9.0.tar.gz", hash = "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a"},
|
||||||
]
|
]
|
||||||
|
pyopenssl = [
|
||||||
|
{file = "pyOpenSSL-22.0.0-py2.py3-none-any.whl", hash = "sha256:ea252b38c87425b64116f808355e8da644ef9b07e429398bfece610f893ee2e0"},
|
||||||
|
{file = "pyOpenSSL-22.0.0.tar.gz", hash = "sha256:660b1b1425aac4a1bea1d94168a85d99f0b3144c869dd4390d27629d0087f1bf"},
|
||||||
|
]
|
||||||
pyparsing = [
|
pyparsing = [
|
||||||
{file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
|
{file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
|
||||||
{file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
|
{file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
|
||||||
|
|
|
@ -12,6 +12,7 @@ uvicorn = "^0.17.6"
|
||||||
python-jose = {extras = ["cryptography"], version = "^3.3.0"}
|
python-jose = {extras = ["cryptography"], version = "^3.3.0"}
|
||||||
passlib = {extras = ["argon2", "bcrypt"], version = "^1.7.4"}
|
passlib = {extras = ["argon2", "bcrypt"], version = "^1.7.4"}
|
||||||
SQLAlchemy = "^1.4.32"
|
SQLAlchemy = "^1.4.32"
|
||||||
|
pyOpenSSL = "^22.0.0"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pytest = "^7.1.0"
|
pytest = "^7.1.0"
|
||||||
|
|
Loading…
Reference in a new issue