Day 1/90: Building a Hardened Python Security Environment
90 Day Python Security Scripting Challenge
The Problem with Default Setups
Most developers pip install security tools globally and call it done. That approach fails the moment two projects need conflicting dependency versions, or worse, when a typosquatted package slips into your install chain. Day 1 is about building a setup that prevents both problems.
Step 1: pyenv for Version Control
# Install pyenv
curl https://pyenv.run | bash
# Install target versions
pyenv install 3.12.1
pyenv install 3.11.7
# Pin per project
cd ~/sec-projects/recon-tool
pyenv local 3.12.1
python --version # confirms 3.12.1
Step 2: Isolated Environments with pipenv
pip install pipenv
mkdir ~/sec-projects/packet-lab && cd ~/sec-projects/packet-lab
pipenv --python 3.12
pipenv install requests scapy cryptography paramiko
pipenv lock # generates Pipfile.lock with hashes
The Pipfile.lock pins every transitive dependency with SHA256 checksums. Running pipenv install --deploy on another machine will refuse to proceed if any hash mismatches.
Step 3: Docker Sandbox for Dangerous Operations
Packet sniffing and raw socket operations belong in a container, not on your host:
FROM python:3.12-slim
RUN apt-get update && apt-get install -y nmap tcpdump iputils-ping
COPY Pipfile Pipfile.lock ./
RUN pip install pipenv && pipenv install --system --deploy
RUN groupadd -r seclab && useradd -r -g seclab labuser
USER labuser
WORKDIR /workspace
docker build -t packet-lab .
docker run -it --rm --cap-add=NET_RAW --cap-add=NET_ADMIN packet-lab bash
NET_RAW allows raw socket access for scapy. NET_ADMIN allows interface configuration for sniffing. The non-root user inside the container limits blast radius if something goes wrong.
Step 4: Security Linting from Day 1
Install bandit to catch your own security mistakes:
pipenv install --dev bandit
bandit -r . -ll
Sample output on intentionally bad code:
>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: 'admin123'
Severity: Low Confidence: Medium
Location: ./test_creds.py:3
Catching this in development beats discovering it in a code review or, worse, in production logs.
Verification
import sys
print(f"Python {sys.version}")
checks = {
'requests': 'requests',
'scapy': 'scapy.all',
'cryptography': 'cryptography.fernet',
'paramiko': 'paramiko',
'nmap': 'nmap',
}
for name, module in checks.items():
try:
__import__(module)
print(f" [+] {name} loaded")
except ImportError:
print(f" [-] {name} MISSING")
Environment is locked. Tomorrow: building a TCP port scanner inside this sandbox.
Top comments (0)