File size: 3,615 Bytes
91ab82e
 
 
 
 
 
 
 
 
 
497602c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91ab82e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/usr/bin/env python3
"""
Generate .htpasswd file for Nginx Basic Authentication.
Uses NGINX_USERNAME and NGINX_PASSWORD environment variables.
Supports bcrypt hashing with fallback mechanisms.
"""
import os
import sys

def generate_htpasswd():
    """
    Generate an .htpasswd file for Nginx Basic Authentication.

    Creates a password file with the specified username and password, hashed using
    the most secure available method. The file is saved to the path specified by
    HTPASSWD_PATH environment variable (default: /etc/nginx/.htpasswd).

    The function attempts to hash the password in the following order of preference:
    1. bcrypt (most secure, recommended for modern Nginx)
    2. openssl passwd with SHA-512 (-6 option)
    3. crypt module with SHA-512 method

    The generated file is created with read permissions for owner and group (0640).

    Environment Variables:
        NGINX_USERNAME: Username for authentication. Defaults to "admin" if not set.
        NGINX_PASSWORD: Password for authentication. Must be set and non-empty.
        HTPASSWD_PATH: Path where the .htpasswd file will be created.
                       Defaults to "/etc/nginx/.htpasswd".

    Raises:
        SystemExit: If NGINX_PASSWORD is not set or empty (exit code 1).
                   If password hashing fails (exit code 1).
                   If file creation fails (exit code 1).

    Returns:
        None: Prints success/error messages to stdout/stderr.

    Example:
        Set environment variables and run:
        >>> export NGINX_USERNAME=user
        >>> export NGINX_PASSWORD=secret
        >>> export HTPASSWD_PATH=/tmp/.htpasswd
        >>> generate_htpasswd()
        [SUCCESS] .htpasswd created successfully at /tmp/.htpasswd for user 'user'.
    """
    username = os.getenv("NGINX_USERNAME", "admin").strip()
    password = os.getenv("NGINX_PASSWORD", "").strip()

    if not password:
        print("[ERROR] NGINX_PASSWORD environment variable is not set or empty.", file=sys.stderr)
        sys.exit(1)

    target_path = os.getenv("HTPASSWD_PATH", "/etc/nginx/.htpasswd")

    # Attempt bcrypt hashing first (most secure and standard for modern Nginx)
    hashed_entry = None
    try:
        import bcrypt
        hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(rounds=12)).decode('utf-8')
        hashed_entry = f"{username}:{hashed_password}\n"
    except ImportError:
        pass

    # Fallback to crypt module or openssl if bcrypt is not available
    if not hashed_entry:
        try:
            import subprocess
            res = subprocess.run(["openssl", "passwd", "-6", password], capture_output=True, text=True, check=True)
            hashed_entry = f"{username}:{res.stdout.strip()}\n"
        except Exception:
            try:
                import crypt
                hashed_password = crypt.crypt(password, crypt.mksalt(crypt.METHOD_SHA512))
                hashed_entry = f"{username}:{hashed_password}\n"
            except Exception as e:
                print(f"[ERROR] Could not hash password: {e}", file=sys.stderr)
                sys.exit(1)

    try:
        os.makedirs(os.path.dirname(target_path), exist_ok=True)
        with open(target_path, "w", encoding="utf-8") as f:
            f.write(hashed_entry)
        os.chmod(target_path, 0o640)
        print(f"[SUCCESS] .htpasswd created successfully at {target_path} for user '{username}'.")
    except Exception as e:
        print(f"[ERROR] Failed to write {target_path}: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    generate_htpasswd()