< ... Output Omitted ... > try: # Read user input (no validation) device_ip = sys.argv[1] interface = sys.argv[2] interface_ip = sys.argv[3] subnet_mask = sys.argv[4] except IndexError: logging.error( "Usage: python configure-interface.py " ) raise SystemExit(2) < ... Output Omitted ... > from netmiko import ConnectHandler import logging import sys import ipaddress import re logging.basicConfig(level=logging.DEBUG) IF_PATTERN = re.compile(r"^[A-Za-z]+[0-9/]+$") def validate_ip_address(ip: str) -> str: try: ipaddress.ip_address(ip) return ip except ValueError: raise ValueError(f"Invalid IP address: {ip}") def validate_subnet_mask(mask: str) -> str: try: ipaddress.IPv4Network(f"0.0.0.0/{mask}") return mask except ValueError: raise ValueError(f"Invalid subnet mask: {mask}") def validate_interface(iface: str) -> str: if not IF_PATTERN.match(iface): raise ValueError(f"Invalid interface name: {iface}") return iface < ... Output Omitted ... > < ... Output Omitted ... > try: device_ip = validate_ip_address(sys.argv[1]) interface = validate_interface(sys.argv[2]) interface_ip = validate_ip_address(sys.argv[3]) subnet_mask = validate_subnet_mask(sys.argv[4]) except IndexError: logging.error( "Usage: python configure-interface.py " ) raise SystemExit(2) except ValueError as e: logging.error(f"Input validation failed: {e}") raise SystemExit(2) < ... Output Omitted ... > from dotenv import load_dotenv load_dotenv() NET_USERNAME=cisco NET_PASSWORD=cisco from netmiko import ConnectHandler import logging import sys import ipaddress import re from dotenv import load_dotenv import os load_dotenv() logging.basicConfig(level=logging.DEBUG) IF_PATTERN = re.compile(r"^[A-Za-z]+[0-9/]+$") USERNAME = os.environ.get("NET_USERNAME") PASSWORD = os.environ.get("NET_PASSWORD") < ... Output Omitted ... > # Hardcoded credentials (insecure) USERNAME = "cisco" PASSWORD = "cisco" < ... Output Omitted ... > < ... Output Omitted ... > try: device_ip = validate_ip_address(sys.argv[1]) interface = validate_interface(sys.argv[2]) interface_ip = validate_ip_address(sys.argv[3]) subnet_mask = validate_subnet_mask(sys.argv[4]) except IndexError: logging.error( "Usage: python configure-interface.py " ) raise SystemExit(2) except ValueError as e: logging.error(f"Input validation failed: {e}") raise SystemExit(2) if not USERNAME or not PASSWORD: logging.error("Missing credentials. Set NET_USERNAME and NET_PASSWORD in .env") raise SystemExit(2) < ... Output Omitted ... > < ... output omitted ... > def validate_interface(iface: str) -> str: if not IF_PATTERN.match(iface): raise ValueError(f"Invalid interface name: {iface}") return iface def get_vault_secrets(): try: import hvac client = hvac.Client( url=os.environ.get("VAULT_ADDR", "http://127.0.0.1:8200"), token=os.environ.get("VAULT_TOKEN") ) if not client.is_authenticated(): return None, None secret = client.secrets.kv.v2.read_secret_version( path="network/creds", mount_point="secret", raise_on_deleted_version=True ) data = secret["data"]["data"] return data.get("username"), data.get("password") except Exception: return None, None < ... Output Omitted ... > < ... Output Omitted ... > def get_vault_secrets(): ... USERNAME, PASSWORD = get_vault_secrets() if not USERNAME or not PASSWORD: logging.info("Vault unavailable, falling back to environment variables") USERNAME = os.environ.get("NET_USERNAME") PASSWORD = os.environ.get("NET_PASSWORD") try: device_ip = validate_ip_address(sys.argv[1]) < ... output omitted ... > < ... Output Omitted ... > device = { "device_type": "cisco_ios", "host": device_ip, "username": USERNAME, "password": PASSWORD, } # Leaks credentials into logs logging.debug(f"Connecting to device: {device}") logging.info(f"Connecting to device {device_ip}") < ... Output Omitted ... > from netmiko import ConnectHandler import logging import sys import ipaddress import re from dotenv import load_dotenv import os load_dotenv() logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.INFO) < ... Output Omitted ... > < ... Output Omitted ... > try: connection = ConnectHandler(**device) commands = [ f"interface {interface}", f"ip address {interface_ip} {subnet_mask}", "no shutdown", ] output = connection.send_config_set(commands) logging.info(f"Device response:\n{output}") logging.info(f"Applied IP {interface_ip} {subnet_mask} on {device_ip} ({interface})") connection.disconnect() < ... Output Omitted ... > < ... Output Omitted ... > except Exception as e: # Raw exception logging logging.error(f"Failed to configure device: {e}") logging.error(f"Configuration failed on device {device_ip}. Verify reachability and credentials.") raise SystemExit(1) solution task 1: from netmiko import ConnectHandler import logging import sys import ipaddress import re logging.basicConfig(level=logging.DEBUG) IF_PATTERN = re.compile(r"^[A-Za-z]+[0-9/]+$") def validate_ip_address(ip: str) -> str: try: ipaddress.ip_address(ip) return ip except ValueError: raise ValueError(f"Invalid IP address: {ip}") def validate_subnet_mask(mask: str) -> str: try: ipaddress.IPv4Network(f"0.0.0.0/{mask}") return mask except ValueError: raise ValueError(f"Invalid subnet mask: {mask}") def validate_interface(iface: str) -> str: if not IF_PATTERN.match(iface): raise ValueError(f"Invalid interface name: {iface}") return iface try: # Read user input (no validation) device_ip = validate_ip_address(sys.argv[1]) interface = validate_interface(sys.argv[2]) interface_ip = validate_ip_address(sys.argv[3]) subnet_mask = validate_subnet_mask(sys.argv[4]) except IndexError: logging.error( "Usage: python configure-interface.py " ) raise SystemExit(2) except ValueError as e: logging.error(f"Input validation failed: {e}") raise SystemExit(2) # Hardcoded credentials (insecure) USERNAME = "admin" PASSWORD = "Cisco123" device = { "device_type": "cisco_ios", "host": device_ip, "username": USERNAME, "password": PASSWORD, } # Leaks credentials into logs logging.debug(f"Connecting to device: {device}") try: connection = ConnectHandler(**device) commands = [ f"interface {interface}", f"ip address {interface_ip} {subnet_mask}", "no shutdown", ] output = connection.send_config_set(commands) logging.info(f"Device response:\n{output}") connection.disconnect() except Exception as e: # Raw exception logging logging.error(f"Failed to configure device: {e}") solution task2: from netmiko import ConnectHandler import logging import sys import ipaddress import re from dotenv import load_dotenv import os load_dotenv() logging.basicConfig(level=logging.DEBUG) IF_PATTERN = re.compile(r"^[A-Za-z]+[0-9/]+$") USERNAME = os.environ.get("NET_USERNAME") PASSWORD = os.environ.get("NET_PASSWORD") def validate_ip_address(ip: str) -> str: try: ipaddress.ip_address(ip) return ip except ValueError: raise ValueError(f"Invalid IP address: {ip}") def validate_subnet_mask(mask: str) -> str: try: ipaddress.IPv4Network(f"0.0.0.0/{mask}") return mask except ValueError: raise ValueError(f"Invalid subnet mask: {mask}") def validate_interface(iface: str) -> str: if not IF_PATTERN.match(iface): raise ValueError(f"Invalid interface name: {iface}") return iface try: # Read user input (no validation) device_ip = validate_ip_address(sys.argv[1]) interface = validate_interface(sys.argv[2]) interface_ip = validate_ip_address(sys.argv[3]) subnet_mask = validate_subnet_mask(sys.argv[4]) except IndexError: logging.error( "Usage: python configure-interface.py " ) raise SystemExit(2) except ValueError as e: logging.error(f"Input validation failed: {e}") raise SystemExit(2) if not USERNAME or not PASSWORD: logging.error("Missing credentials. Set NET_USERNAME and NET_PASSWORD in .env") raise SystemExit(2) device = { "device_type": "cisco_ios", "host": device_ip, "username": USERNAME, "password": PASSWORD, } # Leaks credentials into logs logging.debug(f"Connecting to device: {device}") try: connection = ConnectHandler(**device) commands = [ f"interface {interface}", f"ip address {interface_ip} {subnet_mask}", "no shutdown", ] output = connection.send_config_set(commands) logging.info(f"Device response:\n{output}") connection.disconnect() except Exception as e: # Raw exception logging logging.error(f"Failed to configure device: {e}") solution task 3 check with docker ps if the vault container is running, if not start it using the following command: docker run --name=vault --cap-add=IPC_LOCK -p 8200:8200 -d -e 'VAULT_DEV_ROOT_TOKEN_ID=cisco' -e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200' hashicorp/vault then check again with docker ps if the vault container is running. docker ps docker exec -e VAULT_ADDR=http://127.0.0.1:8200 -e VAULT_TOKEN=cisco vault vault kv put secret/network/creds username=cisco password=cisco docker exec -e VAULT_ADDR=http://127.0.0.1:8200 -e VAULT_TOKEN=cisco vault vault kv get secret/network/creds also check with pip list if hvac is installed - if not install with pip install hvac from netmiko import ConnectHandler import logging import sys import ipaddress import re from dotenv import load_dotenv import os load_dotenv() logging.basicConfig(level=logging.DEBUG) IF_PATTERN = re.compile(r"^[A-Za-z]+[0-9/]+$") def validate_ip_address(ip: str) -> str: try: ipaddress.ip_address(ip) return ip except ValueError: raise ValueError(f"Invalid IP address: {ip}") def validate_subnet_mask(mask: str) -> str: try: ipaddress.IPv4Network(f"0.0.0.0/{mask}") return mask except ValueError: raise ValueError(f"Invalid subnet mask: {mask}") def validate_interface(iface: str) -> str: if not IF_PATTERN.match(iface): raise ValueError(f"Invalid interface name: {iface}") return iface def get_vault_secrets(): try: import hvac client = hvac.Client( url=os.environ.get("VAULT_ADDR", "http://127.0.0.1:8200"), token=os.environ.get("VAULT_TOKEN") ) if not client.is_authenticated(): return None, None secret = client.secrets.kv.v2.read_secret_version( path="network/creds", mount_point="secret", raise_on_deleted_version=True ) data = secret["data"]["data"] return data.get("username"), data.get("password") except Exception: return None, None USERNAME, PASSWORD = get_vault_secrets() if not USERNAME or not PASSWORD: logging.info("Vault unavailable, falling back to environment variables") USERNAME = os.environ.get("NET_USERNAME") PASSWORD = os.environ.get("NET_PASSWORD") try: # Read user input (no validation) device_ip = validate_ip_address(sys.argv[1]) interface = validate_interface(sys.argv[2]) interface_ip = validate_ip_address(sys.argv[3]) subnet_mask = validate_subnet_mask(sys.argv[4]) except IndexError: logging.error( "Usage: python configure-interface.py " ) raise SystemExit(2) except ValueError as e: logging.error(f"Input validation failed: {e}") raise SystemExit(2) if not USERNAME or not PASSWORD: logging.error("Missing credentials. Set NET_USERNAME and NET_PASSWORD in .env") raise SystemExit(2) device = { "device_type": "cisco_ios", "host": device_ip, "username": USERNAME, "password": PASSWORD, } # Leaks credentials into logs logging.debug(f"Connecting to device: {device}") try: connection = ConnectHandler(**device) commands = [ f"interface {interface}", f"ip address {interface_ip} {subnet_mask}", "no shutdown", ] output = connection.send_config_set(commands) logging.info(f"Device response:\n{output}") connection.disconnect() except Exception as e: # Raw exception logging logging.error(f"Failed to configure device: {e}") solution task 4 from netmiko import ConnectHandler import logging import sys import ipaddress import re from dotenv import load_dotenv import os load_dotenv() logging.basicConfig(level=logging.INFO) IF_PATTERN = re.compile(r"^[A-Za-z]+[0-9/]+$") def validate_ip_address(ip: str) -> str: try: ipaddress.ip_address(ip) return ip except ValueError: raise ValueError(f"Invalid IP address: {ip}") def validate_subnet_mask(mask: str) -> str: try: ipaddress.IPv4Network(f"0.0.0.0/{mask}") return mask except ValueError: raise ValueError(f"Invalid subnet mask: {mask}") def validate_interface(iface: str) -> str: if not IF_PATTERN.match(iface): raise ValueError(f"Invalid interface name: {iface}") return iface def get_vault_secrets(): try: import hvac client = hvac.Client( url=os.environ.get("VAULT_ADDR", "http://127.0.0.1:8200"), token=os.environ.get("VAULT_TOKEN") ) if not client.is_authenticated(): return None, None secret = client.secrets.kv.v2.read_secret_version( path="network/creds", mount_point="secret", raise_on_deleted_version=True ) data = secret["data"]["data"] return data.get("username"), data.get("password") except Exception: return None, None USERNAME, PASSWORD = get_vault_secrets() if not USERNAME or not PASSWORD: logging.info("Vault unavailable, falling back to environment variables") USERNAME = os.environ.get("NET_USERNAME") PASSWORD = os.environ.get("NET_PASSWORD") try: # Read user input (no validation) device_ip = validate_ip_address(sys.argv[1]) interface = validate_interface(sys.argv[2]) interface_ip = validate_ip_address(sys.argv[3]) subnet_mask = validate_subnet_mask(sys.argv[4]) except IndexError: logging.error( "Usage: python configure-interface.py " ) raise SystemExit(2) except ValueError as e: logging.error(f"Input validation failed: {e}") raise SystemExit(2) if not USERNAME or not PASSWORD: logging.error("Missing credentials. Set NET_USERNAME and NET_PASSWORD in .env") raise SystemExit(2) device = { "device_type": "cisco_ios", "host": device_ip, "username": USERNAME, "password": PASSWORD, } # Leaks credentials into logs logging.debug(f"Connecting to device: {device}") logging.info(f"Connecting to device: {device_ip}") try: connection = ConnectHandler(**device) commands = [ f"interface {interface}", f"ip address {interface_ip} {subnet_mask}", "no shutdown", ] output = connection.send_config_set(commands) logging.info(f"Applied IP {interface_ip} {subnet_mask} on {device_ip} ({interface})") connection.disconnect() except Exception as e: # Raw exception logging logging.error(f"Failed to configure device: {e}") logging.error(f"Configuration failed on device {device_ip}. Verify reachability and credentials.") raise SystemExit(1)