add logging system
This commit is contained in:
parent
8a88b1aba0
commit
407658f291
@ -4,8 +4,12 @@ Utility for generating OpenVPN client configuration files.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import logging
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
|
# Set up logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def generate_client_config(username: str, email: str) -> Tuple[bool, str]:
|
def generate_client_config(username: str, email: str) -> Tuple[bool, str]:
|
||||||
"""
|
"""
|
||||||
Generates a .ovpn file for a given user.
|
Generates a .ovpn file for a given user.
|
||||||
@ -17,6 +21,8 @@ def generate_client_config(username: str, email: str) -> Tuple[bool, str]:
|
|||||||
Returns:
|
Returns:
|
||||||
A tuple containing a boolean indicating success and a message.
|
A tuple containing a boolean indicating success and a message.
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"Starting client configuration generation for user: {username}, email: {email}")
|
||||||
|
|
||||||
easyrsa_dir = "/home/arthur/openvpn-ca/"
|
easyrsa_dir = "/home/arthur/openvpn-ca/"
|
||||||
ca_path = "/home/arthur/openvpn-ca/pki/ca.crt"
|
ca_path = "/home/arthur/openvpn-ca/pki/ca.crt"
|
||||||
ta_path = "/home/arthur/openvpn-ca/ta.key"
|
ta_path = "/home/arthur/openvpn-ca/ta.key"
|
||||||
@ -24,13 +30,26 @@ def generate_client_config(username: str, email: str) -> Tuple[bool, str]:
|
|||||||
client_key_path = f"/home/arthur/openvpn-ca/pki/private/{username}.key"
|
client_key_path = f"/home/arthur/openvpn-ca/pki/private/{username}.key"
|
||||||
output_path = f"generated-clients/{username}.ovpn"
|
output_path = f"generated-clients/{username}.ovpn"
|
||||||
|
|
||||||
|
logger.info(f"EasyRSA directory: {easyrsa_dir}")
|
||||||
|
logger.info(f"CA certificate path: {ca_path}")
|
||||||
|
logger.info(f"TA key path: {ta_path}")
|
||||||
|
logger.info(f"Client certificate path: {client_crt_path}")
|
||||||
|
logger.info(f"Client key path: {client_key_path}")
|
||||||
|
logger.info(f"Output path: {output_path}")
|
||||||
|
|
||||||
# config password into env
|
# config password into env
|
||||||
password = email
|
password = email
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["EASYRSA_PASSOUT"] = f"pass:{password}"
|
env["EASYRSA_PASSOUT"] = f"pass:{password}"
|
||||||
|
|
||||||
|
logger.info(f"Set EASYRSA_PASSOUT environment variable (length: {len(password)})")
|
||||||
|
|
||||||
# Step 1: Generate the client certificate
|
# Step 1: Generate the client certificate
|
||||||
|
logger.info("Step 1: Starting client certificate generation")
|
||||||
try:
|
try:
|
||||||
command = ["./easyrsa", "--batch", "build-client-full", username]
|
command = ["./easyrsa", "--batch", "build-client-full", username]
|
||||||
|
logger.info(f"Executing command: {' '.join(command)} in directory: {easyrsa_dir}")
|
||||||
|
|
||||||
process = subprocess.run(
|
process = subprocess.run(
|
||||||
command,
|
command,
|
||||||
cwd=easyrsa_dir,
|
cwd=easyrsa_dir,
|
||||||
@ -39,42 +58,80 @@ def generate_client_config(username: str, email: str) -> Tuple[bool, str]:
|
|||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True
|
text=True
|
||||||
)
|
)
|
||||||
except FileNotFoundError:
|
|
||||||
|
logger.info("EasyRSA command completed successfully")
|
||||||
|
if process.stdout:
|
||||||
|
logger.info(f"EasyRSA stdout: {process.stdout.strip()}")
|
||||||
|
if process.stderr:
|
||||||
|
logger.warning(f"EasyRSA stderr: {process.stderr.strip()}")
|
||||||
|
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
logger.error(f"FileNotFoundError: EasyRSA script not found in {easyrsa_dir}")
|
||||||
|
logger.error(f"Error details: {e}")
|
||||||
return False, f"Error: 'easyrsa' script not found in {easyrsa_dir}. Please check the path."
|
return False, f"Error: 'easyrsa' script not found in {easyrsa_dir}. Please check the path."
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
return False, f"Error generating certificate for user: {username}. Stderr: {e.stderr}"
|
logger.error(f"CalledProcessError: EasyRSA command failed with return code {e.returncode}")
|
||||||
|
logger.error(f"EasyRSA stdout: {e.stdout}")
|
||||||
|
logger.error(f"EasyRSA stderr: {e.stderr}")
|
||||||
|
return False, f"Error generating certificate for user: {username}. Return code: {e.returncode}. Stdout: {e.stdout}. Stderr: {e.stderr}"
|
||||||
|
|
||||||
# Step 2: Verify that all required files exist
|
# Step 2: Verify that all required files exist
|
||||||
for f in [ca_path, ta_path, client_crt_path, client_key_path]:
|
logger.info("Step 2: Verifying required certificate files exist")
|
||||||
if not os.path.isfile(f):
|
required_files = [
|
||||||
return False, f"Error: Cannot read file '{f}'. File not found after generation."
|
("CA Certificate", ca_path),
|
||||||
|
("TA Key", ta_path),
|
||||||
|
("Client Certificate", client_crt_path),
|
||||||
|
("Client Key", client_key_path)
|
||||||
|
]
|
||||||
|
|
||||||
|
for file_desc, file_path in required_files:
|
||||||
|
if os.path.isfile(file_path):
|
||||||
|
logger.info(f"✓ Found {file_desc}: {file_path}")
|
||||||
|
else:
|
||||||
|
logger.error(f"✗ Missing {file_desc}: {file_path}")
|
||||||
|
return False, f"Error: Cannot read file '{file_path}' ({file_desc}). File not found after generation."
|
||||||
|
|
||||||
# Step 3: Read the content of the files
|
# Step 3: Read the content of the files
|
||||||
|
logger.info("Step 3: Reading certificate file contents")
|
||||||
try:
|
try:
|
||||||
|
logger.info(f"Reading CA certificate from: {ca_path}")
|
||||||
with open(ca_path, 'r') as f:
|
with open(ca_path, 'r') as f:
|
||||||
ca_content = f.read()
|
ca_content = f.read()
|
||||||
|
logger.info(f"CA certificate loaded (length: {len(ca_content)} chars)")
|
||||||
|
|
||||||
|
logger.info(f"Reading client certificate from: {client_crt_path}")
|
||||||
with open(client_crt_path, 'r') as f:
|
with open(client_crt_path, 'r') as f:
|
||||||
client_crt_content = f.read()
|
client_crt_content = f.read()
|
||||||
|
logger.info(f"Client certificate loaded (length: {len(client_crt_content)} chars)")
|
||||||
|
|
||||||
|
logger.info(f"Reading client key from: {client_key_path}")
|
||||||
with open(client_key_path, 'r') as f:
|
with open(client_key_path, 'r') as f:
|
||||||
client_key_content = f.read()
|
client_key_content = f.read()
|
||||||
|
logger.info(f"Client key loaded (length: {len(client_key_content)} chars)")
|
||||||
|
|
||||||
|
logger.info(f"Reading TA key from: {ta_path}")
|
||||||
with open(ta_path, 'r') as f:
|
with open(ta_path, 'r') as f:
|
||||||
ta_content = f.read()
|
ta_content = f.read()
|
||||||
|
logger.info(f"TA key loaded (length: {len(ta_content)} chars)")
|
||||||
|
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
|
logger.error(f"IOError while reading certificate files: {e}")
|
||||||
return False, f"Error reading files: {e}"
|
return False, f"Error reading files: {e}"
|
||||||
|
|
||||||
# Step 4: Assemble the .ovpn configuration
|
# Step 4: Assemble the .ovpn configuration
|
||||||
|
logger.info("Step 4: Assembling OVPN configuration")
|
||||||
ovpn_config = f"""
|
ovpn_config = f"""
|
||||||
client
|
client
|
||||||
dev tun
|
dev tun
|
||||||
proto udp
|
proto udp
|
||||||
remote 14.241.240.102 1194 # use FTP IP address
|
remote 14.241.240.102 1194 # use FTP IP address
|
||||||
resolv-retry infinite
|
resolv-retry infinite
|
||||||
nobind
|
nobind
|
||||||
persist-key
|
persist-key
|
||||||
persist-tun
|
persist-tun
|
||||||
remote-cert-tls server
|
remote-cert-tls server
|
||||||
cipher AES-256-GCM
|
cipher AES-256-GCM
|
||||||
# push mac address info
|
# push mac address info
|
||||||
push-peer-info
|
push-peer-info
|
||||||
verb 3
|
verb 3
|
||||||
|
|
||||||
@ -95,21 +152,32 @@ verb 3
|
|||||||
</tls-auth>
|
</tls-auth>
|
||||||
key-direction 1
|
key-direction 1
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"OVPN configuration assembled (length: {len(ovpn_config)} chars)")
|
||||||
|
|
||||||
# Step 5: Write the configuration to the output file
|
# Step 5: Write the configuration to the output file
|
||||||
|
logger.info("Step 5: Writing OVPN configuration to file")
|
||||||
try:
|
try:
|
||||||
output_dir = os.path.dirname(output_path)
|
output_dir = os.path.dirname(output_path)
|
||||||
|
logger.info(f"Checking output directory: {output_dir}")
|
||||||
|
|
||||||
if not os.path.isdir(output_dir) or not os.access(output_dir, os.W_OK):
|
if not os.path.isdir(output_dir) or not os.access(output_dir, os.W_OK):
|
||||||
|
logger.warning(f"Output directory {output_dir} is not writable, using local directory")
|
||||||
local_output_dir = "generated-clients"
|
local_output_dir = "generated-clients"
|
||||||
if not os.path.exists(local_output_dir):
|
if not os.path.exists(local_output_dir):
|
||||||
|
logger.info(f"Creating local output directory: {local_output_dir}")
|
||||||
os.makedirs(local_output_dir)
|
os.makedirs(local_output_dir)
|
||||||
local_output_path = os.path.join(local_output_dir, f"{username}.ovpn")
|
local_output_path = os.path.join(local_output_dir, f"{username}.ovpn")
|
||||||
|
logger.info(f"Writing to local path: {local_output_path}")
|
||||||
with open(local_output_path, 'w') as f:
|
with open(local_output_path, 'w') as f:
|
||||||
f.write(ovpn_config)
|
f.write(ovpn_config)
|
||||||
|
logger.info(f"Successfully wrote {len(ovpn_config)} chars to {local_output_path}")
|
||||||
return True, f"Successfully generated client config. Could not write to server path. Saved config locally to: {local_output_path}"
|
return True, f"Successfully generated client config. Could not write to server path. Saved config locally to: {local_output_path}"
|
||||||
|
|
||||||
|
logger.info(f"Writing to server path: {output_path}")
|
||||||
with open(output_path, 'w') as f:
|
with open(output_path, 'w') as f:
|
||||||
f.write(ovpn_config)
|
f.write(ovpn_config)
|
||||||
|
logger.info(f"Successfully wrote {len(ovpn_config)} chars to {output_path}")
|
||||||
return True, f"Successfully generated client config: {output_path}"
|
return True, f"Successfully generated client config: {output_path}"
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
|
logger.error(f"IOError while writing OVPN file: {e}")
|
||||||
return False, f"Error writing to file: {e}"
|
return False, f"Error writing to file: {e}"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user