Security & Compliance

Security best practices, secrets management, compliance frameworks, and infrastructure hardening

Security: Everyone's Responsibility

Security isn't just the security team's job, it's everyone's responsibility. One misconfigured S3 bucket, one leaked API key, one SQL injection vulnerability can compromise your entire system. Modern security is about defense in depth: layers of protection at the network, infrastructure, application, and data levels. This lesson covers security fundamentals, secrets management (never hardcode credentials!), authentication and authorization, infrastructure hardening, compliance frameworks (SOC 2, GDPR, HIPAA), and practical tools for securing your systems. Security is hard, but ignoring it is catastrophic.

Security Fundamentals, CIA Triad

Security starts with three core principles: Confidentiality, Integrity, and Availability.

Confidentiality

Goal: Keep data private

  • Encryption (at rest, in transit)
  • Access controls (who can see what)
  • Authentication (who are you)
  • Strong passwords, MFA
  • Data classification
Integrity

Goal: Keep data accurate

  • Checksums, hashing
  • Digital signatures
  • Audit logs (who changed what)
  • Input validation
  • Version control
Availability

Goal: Keep systems accessible

  • Redundancy (no single point of failure)
  • DDoS protection
  • Rate limiting
  • Backups and disaster recovery
  • High availability architecture

Defense in Depth (Layered Security)

7
Application Security
  • Input validation, output encoding
  • OWASP Top 10 protection
  • Secure coding practices
  • Application firewalls (WAF)
6
Data Security
  • Encryption at rest (AES-256)
  • Encryption in transit (TLS 1.3)
  • Data loss prevention (DLP)
  • Secrets management (Vault, Secrets Manager)
5
Authentication & Authorization
  • Multi-factor authentication (MFA)
  • OAuth 2.0 / OpenID Connect
  • Role-based access control (RBAC)
  • Least privilege principle
4
Infrastructure Security
  • OS hardening (CIS benchmarks)
  • Patch management
  • Container security (scan images)
  • Kubernetes security policies
3
Network Security
  • Firewalls, security groups
  • Network segmentation (VPCs, subnets)
  • DDoS protection (CloudFlare, AWS Shield)
  • VPN, private networks
2
Perimeter Security
  • IDS/IPS (intrusion detection/prevention)
  • Web application firewall (WAF)
  • Rate limiting, throttling
  • API gateway security
1
Physical Security
  • Data center access controls
  • Hardware security modules (HSM)
  • Physical device security
Principle: If one layer fails, others still protect

Secrets Management, Never Hardcode Credentials

Secrets (API keys, passwords, tokens) must NEVER be in code or config files. Use dedicated secret managers.

❌ BAD: Hardcoded Secrets
# config.py
DATABASE_URL = "postgres://user:pass123@db:5432/mydb"
API_KEY = "sk-proj-abc123xyz"
AWS_SECRET = "wJalrXUtnFEMI/K7MDENG"

Problems:
• Committed to Git (leaked!)
• Hard to rotate
• Same secrets for all environments
• Visible to everyone with code access

✅ GOOD: Secret Manager
# config.py
import boto3
client = boto3.client('secretsmanager')
secret = client.get_secret_value(
  SecretId='prod/db'
)

Benefits:
• Never in code/version control
• Easy rotation
• Environment-specific
• Audit trail (who accessed when)

Secret Management Tools

ToolBest ForFeaturesPricing
HashiCorp VaultMulti-cloud, dynamic secretsDynamic secrets, encryption as service, PKIFree (open-source), Enterprise $$$
AWS Secrets ManagerAWS workloadsAuto rotation, RDS integration, versioning$0.40/secret/month + API calls
AWS SSM Parameter StoreSimple AWS secretsFree tier, KMS encryption, hierarchicalFree (standard), $0.05/param (advanced)
GCP Secret ManagerGCP workloadsVersioning, IAM integration, replication$0.06/secret/month
Azure Key VaultAzure workloadsKeys, secrets, certificates, HSM-backed$0.03/10k operations
DopplerDeveloper-friendly, SaaSMulti-environment, integrations, GUIFree tier, $36+/user/month

AWS Secrets Manager (Python)

# Install
pip install boto3
# Retrieve secrets from AWS Secrets Manager
import boto3
import json
from botocore.exceptions import ClientError

def get_secret(secret_name, region_name="us-east-1"):
    """Retrieve secret from AWS Secrets Manager"""

    # Create client
    session = boto3.session.Session()
    client = session.client(
        service_name='secretsmanager',
        region_name=region_name
    )

    try:
        get_secret_value_response = client.get_secret_value(
            SecretId=secret_name
        )
    except ClientError as e:
        # Handle errors
        if e.response['Error']['Code'] == 'ResourceNotFoundException':
            print(f"Secret {secret_name} not found")
        elif e.response['Error']['Code'] == 'InvalidRequestException':
            print(f"Invalid request for {secret_name}")
        elif e.response['Error']['Code'] == 'InvalidParameterException':
            print(f"Invalid parameter for {secret_name}")
        raise e
    else:
        # Decrypt and return secret
        if 'SecretString' in get_secret_value_response:
            secret = get_secret_value_response['SecretString']
            return json.loads(secret)
        else:
            # Binary secret
            return get_secret_value_response['SecretBinary']

# Usage
db_credentials = get_secret("prod/database")
DATABASE_URL = f"postgresql://{db_credentials['username']}:{db_credentials['password']}@{db_credentials['host']}:5432/{db_credentials['dbname']}"

api_keys = get_secret("prod/api-keys")
STRIPE_SECRET_KEY = api_keys['stripe_secret']
SENDGRID_API_KEY = api_keys['sendgrid_api_key']

HashiCorp Vault (Python)

# Install
pip install hvac
# Vault client in Python
import hvac
import os

# Initialize Vault client
client = hvac.Client(
    url='https://vault.example.com:8200',
    token=os.environ['VAULT_TOKEN']  # Never hardcode!
)

# Check if authenticated
if not client.is_authenticated():
    raise Exception("Not authenticated to Vault")

# Read secret (KV v2)
secret = client.secrets.kv.v2.read_secret_version(
    path='prod/database',
    mount_point='secret'
)

db_credentials = secret['data']['data']
DATABASE_URL = f"postgresql://{db_credentials['username']}:{db_credentials['password']}@{db_credentials['host']}:5432/{db_credentials['dbname']}"

# Write secret
client.secrets.kv.v2.create_or_update_secret(
    path='prod/api-keys',
    secret=dict(
        stripe_key='sk_live_...',
        sendgrid_key='SG...'
    ),
    mount_point='secret'
)

# Dynamic database credentials (Vault generates temporary creds)
db_creds = client.secrets.database.generate_credentials(
    name='postgres-role'
)
# Credentials auto-expire after TTL

Environment Variables (Simplest Approach)

# .env file (NEVER commit to Git!)
# .env
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
STRIPE_SECRET_KEY=sk_test_...
SENDGRID_API_KEY=SG...
# Python: Load from environment
import os
from dotenv import load_dotenv

# Load .env file (development only!)
load_dotenv()

# Access secrets
DATABASE_URL = os.getenv('DATABASE_URL')
STRIPE_SECRET_KEY = os.getenv('STRIPE_SECRET_KEY')

if not DATABASE_URL:
    raise ValueError("DATABASE_URL not set")

# In production: set env vars in deployment platform
# (Heroku, Railway, AWS ECS, Kubernetes Secrets, etc.)
Secrets Management Best Practices:
• NEVER commit secrets to Git (add .env to .gitignore)
• Use different secrets for dev/staging/prod
• Rotate secrets regularly (automated if possible)
• Use short-lived credentials when available
• Audit secret access (who accessed what, when)
• Encrypt secrets at rest (KMS, HSM)
• Principle of least privilege (only grant necessary access)

Authentication & Authorization

Authentication: Who are you? Authorization: What are you allowed to do?

Authentication Methods

MethodHow It WorksUse Case
Password + MFAPassword + one-time code (TOTP, SMS)Traditional user login, admin access
OAuth 2.0Delegated authorization (Login with Google)Third-party login, API access delegation
JWT (JSON Web Token)Stateless tokens with signed claimsAPI authentication, microservices
API KeysLong-lived secret tokensService-to-service, simple APIs
mTLS (Mutual TLS)Client and server both present certificatesService mesh, high-security environments
SSO (Single Sign-On)One login for multiple apps (SAML, OIDC)Enterprise, employee access

JWT Authentication (Python)

# Install
pip install pyjwt flask
# JWT authentication in Flask
from flask import Flask, request, jsonify
import jwt
import datetime
from functools import wraps

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'  # Use env var in production!

def token_required(f):
    """Decorator to require valid JWT token"""
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.headers.get('Authorization')

        if not token:
            return jsonify({'message': 'Token is missing'}), 401

        try:
            # Remove 'Bearer ' prefix
            if token.startswith('Bearer '):
                token = token[7:]

            # Decode token
            data = jwt.decode(
                token,
                app.config['SECRET_KEY'],
                algorithms=["HS256"]
            )
            current_user = data['user_id']
        except jwt.ExpiredSignatureError:
            return jsonify({'message': 'Token has expired'}), 401
        except jwt.InvalidTokenError:
            return jsonify({'message': 'Invalid token'}), 401

        return f(current_user, *args, **kwargs)

    return decorated

@app.route('/login', methods=['POST'])
def login():
    """Login endpoint - returns JWT"""
    auth = request.json

    # Validate credentials (check database)
    if auth.get('username') == 'admin' and auth.get('password') == 'password':
        # Create token
        token = jwt.encode({
            'user_id': 123,
            'username': 'admin',
            'exp': datetime.datetime.now(timezone.utc) + datetime.timedelta(hours=24)
        }, app.config['SECRET_KEY'], algorithm="HS256")

        return jsonify({'token': token})

    return jsonify({'message': 'Invalid credentials'}), 401

@app.route('/protected', methods=['GET'])
@token_required
def protected(current_user):
    """Protected endpoint - requires valid token"""
    return jsonify({'message': f'Hello user {current_user}!'})

# Usage:
# 1. POST /login with username/password → get token
# 2. GET /protected with header: Authorization: Bearer <token>

Role-Based Access Control (RBAC)

# RBAC in Python
from enum import Enum
from functools import wraps
from flask import jsonify

class Role(Enum):
    ADMIN = "admin"
    USER = "user"
    VIEWER = "viewer"

class Permission(Enum):
    READ = "read"
    WRITE = "write"
    DELETE = "delete"
    ADMIN = "admin"

# Define role permissions
ROLE_PERMISSIONS = {
    Role.ADMIN: [Permission.READ, Permission.WRITE, Permission.DELETE, Permission.ADMIN],
    Role.USER: [Permission.READ, Permission.WRITE],
    Role.VIEWER: [Permission.READ]
}

def require_permission(permission):
    """Decorator to check user has required permission"""
    def decorator(f):
        @wraps(f)
        def decorated_function(current_user, *args, **kwargs):
            # Get user role from database/token
            user_role = get_user_role(current_user)

            # Check permission
            if permission not in ROLE_PERMISSIONS.get(user_role, []):
                return jsonify({'message': 'Insufficient permissions'}), 403

            return f(current_user, *args, **kwargs)
        return decorated_function
    return decorator

@app.route('/users/<user_id>', methods=['DELETE'])
@token_required
@require_permission(Permission.DELETE)
def delete_user(current_user, user_id):
    """Only admins can delete users"""
    # Delete user logic
    return jsonify({'message': f'User {user_id} deleted'})

@app.route('/reports', methods=['GET'])
@token_required
@require_permission(Permission.READ)
def view_reports(current_user):
    """All authenticated users can view reports"""
    return jsonify({'reports': []})
Authentication Best Practices:
• Always use HTTPS (encrypt credentials in transit)
• Implement MFA for privileged accounts
• Use strong password policies (min length, complexity)
• Hash passwords with bcrypt/argon2 (NEVER store plaintext)
• Implement account lockout after failed attempts
• Use short-lived tokens (15 min - 1 hour)
• Rotate API keys regularly
• Log all authentication events

Application Security, OWASP Top 10

The OWASP Top 10 lists the most critical web application security risks. Protect against these.

#VulnerabilityDescriptionPrevention
1Broken Access ControlUsers can access unauthorized resourcesEnforce access controls server-side, deny by default
2Cryptographic FailuresSensitive data exposed due to weak cryptoEncrypt data at rest/transit, use strong algorithms
3InjectionSQL/NoSQL/OS command injectionUse parameterized queries, validate input
4Insecure DesignMissing security controls in designThreat modeling, secure design patterns
5Security MisconfigurationDefault configs, unnecessary features enabledHarden configs, disable unused features
6Vulnerable ComponentsUsing libraries with known vulnerabilitiesKeep dependencies updated, scan for CVEs
7Authentication FailuresWeak auth, session management issuesMFA, secure session management, rate limiting
8Data Integrity FailuresAssuming data hasn't been tampered withDigital signatures, integrity checks
9Logging FailuresInsufficient logging, no monitoringLog security events, monitor for anomalies
10SSRFServer-side request forgeryValidate/sanitize URLs, use allowlists

SQL Injection Prevention (Python)

# ❌ VULNERABLE to SQL injection
import sqlite3

def get_user_vulnerable(email):
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()

    # NEVER DO THIS - allows SQL injection!
    query = f"SELECT * FROM users WHERE email = '{email}'"
    cursor.execute(query)

    return cursor.fetchone()

# Attacker input: ' OR '1'='1
# Query becomes: SELECT * FROM users WHERE email = '' OR '1'='1'
# Returns ALL users!
# ✅ SAFE: Parameterized queries
import sqlite3

def get_user_safe(email):
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()

    # Use parameterized query - prevents injection
    query = "SELECT * FROM users WHERE email = ?"
    cursor.execute(query, (email,))

    return cursor.fetchone()

# With ORMs (even safer)
from sqlalchemy import create_engine, Column, String, Integer
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    email = Column(String)
    name = Column(String)

# Safe by default
user = session.query(User).filter_by(email=email).first()

XSS (Cross-Site Scripting) Prevention

# Flask: Auto-escaping with Jinja2
from flask import Flask, render_template, request
from markupsafe import escape

app = Flask(__name__)

@app.route('/search')
def search():
    query = request.args.get('q', '')

    # Jinja2 auto-escapes by default
    return render_template('search.html', query=query)

# template: search.html
# {{ query }} - automatically escaped
# Attacker input: <script>alert('XSS')</script>
# Rendered as: &lt;script&gt;alert('XSS')&lt;/script&gt;
# Browser shows the text, doesn't execute

# If you need to allow some HTML (dangerous!)
from bleach import clean

def sanitize_html(html):
    """Allow only safe HTML tags"""
    return clean(
        html,
        tags=['p', 'br', 'strong', 'em', 'a'],
        attributes={'a': ['href']},
        strip=True
    )

Input Validation

# Validate all user input
from flask import Flask, request, jsonify
from pydantic import BaseModel, EmailStr, field_validator
from typing import Optional

app = Flask(__name__)

class UserCreate(BaseModel):
    email: EmailStr  # Validates email format
    username: str
    age: Optional[int] = None

    @field_validator('username')
    @classmethod
    def username_alphanumeric(cls, v):
        if not v.isalnum():
            raise ValueError('Username must be alphanumeric')
        if len(v) < 3 or len(v) > 20:
            raise ValueError('Username must be 3-20 characters')
        return v

    @field_validator('age')
    @classmethod
    def age_range(cls, v):
        if v is not None and (v < 13 or v > 120):
            raise ValueError('Age must be between 13 and 120')
        return v

@app.route('/users', methods=['POST'])
def create_user():
    try:
        # Validate input
        user_data = UserCreate(**request.json)

        # Use validated data
        create_user_in_db(user_data)

        return jsonify({'message': 'User created'}), 201
    except ValueError as e:
        return jsonify({'error': str(e)}), 400
Application Security Checklist:
□ Use parameterized queries (prevent SQL injection)
□ Escape output (prevent XSS)
□ Validate all input (allowlist, not denylist)
□ Use HTTPS everywhere
□ Set secure HTTP headers (CSP, X-Frame-Options, etc.)
□ Implement CSRF protection
□ Keep dependencies updated (scan for CVEs)
□ Use security headers (helmet.js for Node, flask-talisman for Flask)
□ Rate limiting on APIs
□ Regular security audits and pen testing

Infrastructure Hardening

Hardening reduces attack surface by disabling unnecessary services, applying patches, and following security benchmarks.

OS Hardening (Linux)

# Basic Linux hardening steps
# 1. Keep system updated
sudo apt update && sudo apt upgrade -y

# 2. Disable unused services
sudo systemctl disable bluetooth
sudo systemctl disable cups  # Printer service

# 3. Configure firewall (UFW)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp   # SSH
sudo ufw allow 80/tcp   # HTTP
sudo ufw allow 443/tcp  # HTTPS
sudo ufw enable

# 4. Secure SSH
# Edit /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no  # Use keys only
Port 2222  # Change default port (optional)
MaxAuthTries 3

# 5. Fail2ban (block brute-force attacks)
sudo apt install fail2ban
sudo systemctl enable fail2ban

# 6. Disable unused network protocols
sudo sysctl -w net.ipv4.conf.all.send_redirects=0
sudo sysctl -w net.ipv4.conf.all.accept_redirects=0

# 7. Set file permissions
chmod 600 /home/user/.ssh/authorized_keys
chmod 700 /home/user/.ssh

# 8. Remove unnecessary packages
sudo apt autoremove

Container Security

# Secure Dockerfile
# Use specific version tags, not 'latest'
FROM python:3.11.6-slim

# Create non-root user
RUN useradd -m -u 1000 appuser

# Set working directory
WORKDIR /app

# Copy dependencies first (layer caching)
COPY requirements.txt .

# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Change ownership to non-root user
RUN chown -R appuser:appuser /app

# Switch to non-root user
USER appuser

# Run as non-root
CMD ["python", "app.py"]
# Scan Docker images for vulnerabilities
# Using Trivy
docker run aquasec/trivy image myapp:latest

# Using Docker Scout
docker scout cves myapp:latest

# Using Snyk
snyk container test myapp:latest

Kubernetes Security

# Secure Pod configuration
apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 1000
    seccompProfile:
      type: RuntimeDefault

  containers:
  - name: app
    image: myapp:1.0.0

    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      runAsNonRoot: true
      capabilities:
        drop:
          - ALL

    resources:
      limits:
        memory: "512Mi"
        cpu: "500m"
      requests:
        memory: "256Mi"
        cpu: "250m"

    volumeMounts:
    - name: tmp
      mountPath: /tmp

  volumes:
  - name: tmp
    emptyDir: {}
Infrastructure Hardening Checklist:
□ Apply CIS Benchmarks for your OS
□ Automated patch management
□ Run containers as non-root
□ Use read-only filesystems where possible
□ Scan images for vulnerabilities before deployment
□ Network segmentation (VPCs, subnets)
□ Principle of least privilege (IAM roles)
□ Enable audit logging
□ Regular security assessments

Compliance Frameworks

Compliance frameworks define security and privacy requirements for specific industries or use cases.

FrameworkPurposeKey RequirementsWho Needs It
SOC 2Trust service criteria for SaaSSecurity, availability, confidentiality, privacy controlsB2B SaaS companies selling to enterprises
ISO 27001Information security managementISMS, risk assessment, controls implementationGlobal enterprises, European market
GDPREU data privacy regulationConsent, data portability, right to deletion, breach notificationCompanies with EU customers/employees
HIPAAUS healthcare data protectionPHI encryption, access controls, audit trails, BAAsHealthcare providers, health tech companies
PCI-DSSPayment card securitySecure cardholder data, encryption, access control, monitoringCompanies that process/store credit cards
FedRAMPUS federal cloud securityNIST controls, continuous monitoring, authorizationCloud providers serving US government

SOC 2 Trust Service Criteria

Security (Required)

Access controls, MFA, encryption, firewalls, IDS/IPS

Availability

Uptime monitoring, redundancy, disaster recovery, backups

Processing Integrity

Data accuracy, completeness, authorized processing

Confidentiality

Encrypt sensitive data, NDA, data classification

Privacy

Privacy policy, consent, data retention, deletion on request

GDPR Key Requirements

GDPR Principles:

1. LAWFULNESS - Legal basis for processing (consent, contract, etc.)
2. PURPOSE LIMITATION - Collect data for specific purposes
3. DATA MINIMIZATION - Only collect what's necessary
4. ACCURACY - Keep data accurate and up-to-date
5. STORAGE LIMITATION - Don't keep data longer than needed
6. INTEGRITY & CONFIDENTIALITY - Protect against unauthorized access
7. ACCOUNTABILITY - Demonstrate compliance

User Rights:
• Right to access (get copy of their data)
• Right to rectification (correct inaccurate data)
• Right to erasure ("right to be forgotten")
• Right to data portability (export data)
• Right to object to processing
• Right to restrict processing

Requirements:
• Obtain explicit consent before processing
• Data breach notification (72 hours)
• Privacy by design and default
• Data Protection Impact Assessment (DPIA) for high-risk processing
• Appoint Data Protection Officer (DPO) if applicable
• Cross-border data transfer protections

GDPR Implementation (Python Example)

# GDPR data subject rights implementation
from flask import Flask, request, jsonify, send_file
import json
from datetime import datetime, timezone

app = Flask(__name__)

@app.route('/user/<user_id>/data', methods=['GET'])
def export_user_data(user_id):
    """Right to data portability - export all user data"""

    # Gather all user data from databases
    user_data = {
        'user_info': get_user_info(user_id),
        'orders': get_user_orders(user_id),
        'preferences': get_user_preferences(user_id),
        'activity_log': get_user_activity(user_id),
        'exported_at': datetime.now(timezone.utc).isoformat()
    }

    # Create JSON file
    filename = f"user_data_{user_id}.json"
    with open(filename, 'w') as f:
        json.dump(user_data, f, indent=2)

    # Return file for download
    return send_file(filename, as_attachment=True)

@app.route('/user/<user_id>', methods=['DELETE'])
def delete_user_data(user_id):
    """Right to erasure - delete all user data"""

    # Verify user consent/request
    if not verify_deletion_request(user_id):
        return jsonify({'error': 'Invalid deletion request'}), 403

    # Delete from all systems
    delete_user_from_database(user_id)
    delete_user_from_analytics(user_id)
    delete_user_from_email_list(user_id)

    # Anonymize logs (can't delete for compliance)
    anonymize_user_logs(user_id)

    # Log deletion (audit trail)
    log_gdpr_deletion(user_id, datetime.now(timezone.utc))

    return jsonify({'message': 'User data deleted'}), 200

@app.route('/user/<user_id>/consent', methods=['POST'])
def update_consent(user_id):
    """Record user consent for data processing"""

    consent_data = {
        'user_id': user_id,
        'marketing_emails': request.json.get('marketing_emails', False),
        'analytics': request.json.get('analytics', False),
        'third_party_sharing': request.json.get('third_party_sharing', False),
        'timestamp': datetime.now(timezone.utc).isoformat(),
        'ip_address': request.remote_addr
    }

    # Store consent record
    save_consent_record(consent_data)

    return jsonify({'message': 'Consent updated'}), 200
Compliance Strategy:
• Start early - compliance takes months
• Document everything (policies, procedures, evidence)
• Use compliance automation tools (Vanta, Drata, Secureframe)
• Regular internal audits
• Employee security training
• Engage legal counsel for regulations
• Consider compliance-as-a-service for SOC 2/ISO

Security Scanning & Testing

Automate security testing to catch vulnerabilities before they reach production.

TypeWhat It ScansTools
SASTSource code for vulnerabilitiesSonarQube, Semgrep, Bandit (Python)
DASTRunning application (black-box testing)OWASP ZAP, Burp Suite
SCADependencies for known CVEsSnyk, Dependabot, Safety (Python)
Container ScanningDocker images for vulnerabilitiesTrivy, Clair, Docker Scout, Snyk
Secret ScanningCode/commits for leaked secretsGitGuardian, TruffleHog, GitHub Secret Scanning
IaC ScanningTerraform/CloudFormation misconfigsCheckov, tfsec, Terraform Sentinel

Python Security Scanning

# Bandit - SAST for Python
# Install
pip install bandit

# Scan project
bandit -r . -f json -o bandit-report.json

# Common issues Bandit finds:
# - Hardcoded passwords
# - SQL injection vulnerabilities
# - Use of insecure random (random vs secrets)
# - Insecure deserialization (pickle)
# - Shell injection vulnerabilities
# Safety - check dependencies for CVEs
# Install
pip install safety

# Check current environment
safety check

# Check requirements.txt
safety check -r requirements.txt

# Generate report
safety check --json > safety-report.json

# In CI/CD
safety check --exit-code 1  # Fail build if vulnerabilities found

CI/CD Security Integration

# GitHub Actions - security scanning
name: Security Scan

on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      # SAST - Python code scanning
      - name: Bandit Security Scan
        run: |
          pip install bandit
          bandit -r . -f json -o bandit-report.json

      # SCA - Dependency vulnerabilities
      - name: Safety Check
        run: |
          pip install safety
          safety check --json > safety-report.json

      # Secret scanning
      - name: TruffleHog Secret Scan
        uses: trufflesecurity/trufflehog@main
        with:
          path: ./

      # Container scanning
      - name: Build Docker image
        run: docker build -t myapp:$GITHUB_SHA .

      - name: Trivy Container Scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:$GITHUB_SHA
          severity: 'CRITICAL,HIGH'
          exit-code: '1'  # Fail if vulnerabilities found

      # IaC scanning (Trivy config scan - successor to tfsec)
      - name: Terraform Security Scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'config'
          scan-ref: '.'
          severity: 'CRITICAL,HIGH'
          exit-code: '1'
Security Testing Best Practices:
• Run SAST on every commit (find issues early)
• Scan dependencies daily (new CVEs published constantly)
• Block deployment if critical vulnerabilities found
• Regular pen testing (annually or after major changes)
• Bug bounty program for production systems
• Security champions in each team
• Threat modeling for new features

Key Takeaways

  • CIA Triad: Confidentiality, Integrity, Availability, foundation of security
  • Defense in Depth: Layered security across network, infra, app, data levels
  • Secrets Management: NEVER hardcode credentials, use Vault, AWS Secrets Manager
  • Authentication: MFA everywhere, JWT for APIs, OAuth for third-party login
  • Authorization: RBAC, principle of least privilege, server-side enforcement
  • OWASP Top 10: Injection, broken auth, XSS, access control, protect against these
  • Infrastructure Hardening: Patch management, disable unused services, non-root containers
  • Compliance: SOC 2 (SaaS), GDPR (EU data), HIPAA (healthcare), PCI-DSS (payments)
  • Security Scanning: SAST, SCA, container scanning in CI/CD pipeline
  • Security is Continuous: Not a one-time project, requires ongoing vigilance

Security Implementation Roadmap

Phase 1: Foundation (Month 1-2)
  • Set up secrets management (AWS Secrets Manager or Vault)
  • Implement MFA for all admin accounts
  • Enable HTTPS everywhere
  • Basic input validation and parameterized queries
  • Set up basic monitoring and logging
Phase 2: Hardening (Month 3-4)
  • OS and container hardening
  • Implement RBAC and authorization
  • Security scanning in CI/CD (SAST, SCA, container scanning)
  • Regular dependency updates
  • Network segmentation (VPCs, security groups)
Phase 3: Compliance (Month 5-8)
  • Document security policies and procedures
  • Implement compliance controls (SOC 2, GDPR, etc.)
  • Employee security training
  • Third-party vendor assessments
  • Engage auditors for SOC 2 Type II
Phase 4: Maturity (Ongoing)
  • Regular penetration testing
  • Bug bounty program
  • Advanced threat detection (SIEM)
  • Incident response drills
  • Continuous compliance monitoring
  • Security champions program