Advanced Container Security Techniques

Advanced Container Security Techniques

Software Bill of Materials (SBOM) generation provides comprehensive visibility into container contents. SBOM documents list all components, libraries, and dependencies within containers, enabling precise vulnerability tracking and compliance reporting. Modern container scanners generate SBOM data in standardized formats like SPDX or CycloneDX.

#!/usr/bin/env python3
# generate_container_sbom.py - Generate comprehensive SBOM for containers

import json
import subprocess
import hashlib
from datetime import datetime
from typing import Dict, List, Any

class ContainerSBOMGenerator:
    def __init__(self, image_name: str):
        self.image_name = image_name
        self.sbom = {
            "spdxVersion": "SPDX-2.3",
            "creationInfo": {
                "created": datetime.now().isoformat(),
                "creators": ["Tool: container-sbom-generator-1.0"]
            },
            "name": f"SBOM for {image_name}",
            "packages": []
        }
    
    def generate_sbom(self) -> Dict[str, Any]:
        """Generate complete SBOM for container image"""
        # Get image manifest
        manifest = self._get_image_manifest()
        
        # Analyze each layer
        for layer in manifest['layers']:
            self._analyze_layer(layer)
        
        # Add OS packages
        self._add_os_packages()
        
        # Add language-specific dependencies
        self._add_application_dependencies()
        
        # Calculate image checksum
        self._add_image_metadata()
        
        return self.sbom
    
    def _analyze_layer(self, layer: Dict[str, Any]):
        """Analyze individual container layer"""
        layer_id = layer['digest']
        
        # Extract layer
        subprocess.run([
            'docker', 'save', self.image_name, '-o', 'image.tar'
        ], check=True)
        
        # Analyze layer contents
        subprocess.run([
            'tar', '-xf', 'image.tar', f'{layer_id}/layer.tar'
        ], check=True)
        
        # Scan for files and packages
        files = self._scan_layer_files(f'{layer_id}/layer.tar')
        
        for file_info in files:
            package = {
                "SPDXID": f"SPDXRef-{hashlib.sha256(file_info['path'].encode()).hexdigest()[:8]}",
                "name": file_info['name'],
                "downloadLocation": file_info.get('source', 'NOASSERTION'),
                "filesAnalyzed": True,
                "verification": {
                    "sha256": file_info['sha256']
                },
                "licenseConcluded": file_info.get('license', 'NOASSERTION')
            }
            self.sbom['packages'].append(package)
    
    def _add_os_packages(self):
        """Add OS-level packages to SBOM"""
        # Get package list based on OS
        os_packages = self._detect_and_list_os_packages()
        
        for pkg in os_packages:
            package = {
                "SPDXID": f"SPDXRef-{pkg['name']}-{pkg['version']}",
                "name": pkg['name'],
                "version": pkg['version'],
                "supplier": pkg.get('supplier', 'OS Vendor'),
                "downloadLocation": pkg.get('repository', 'NOASSERTION'),
                "licenseConcluded": pkg.get('license', 'NOASSERTION'),
                "externalRefs": [
                    {
                        "referenceCategory": "SECURITY",
                        "referenceType": "vulnerability",
                        "referenceLocator": vuln
                    } for vuln in pkg.get('vulnerabilities', [])
                ]
            }
            self.sbom['packages'].append(package)
    
    def _add_application_dependencies(self):
        """Add application-level dependencies to SBOM"""
        # Detect package managers
        if self._file_exists_in_image('package.json'):
            self._add_npm_dependencies()
        if self._file_exists_in_image('requirements.txt'):
            self._add_python_dependencies()
        if self._file_exists_in_image('go.mod'):
            self._add_go_dependencies()
        if self._file_exists_in_image('pom.xml'):
            self._add_maven_dependencies()
    
    def export_sbom(self, format: str = 'json') -> str:
        """Export SBOM in requested format"""
        if format == 'json':
            return json.dumps(self.sbom, indent=2)
        elif format == 'cyclonedx':
            return self._convert_to_cyclonedx()
        else:
            raise ValueError(f"Unsupported format: {format}")

# Container runtime security policies
def generate_security_policies():
    """Generate OPA policies for container security"""
    policies = {
        "docker": {
            "image": {
                "deny": [
                    # No root user
                    {
                        "msg": "Container runs as root user",
                        "expr": 'input.Config.User == "" or input.Config.User == "root" or input.Config.User == "0"'
                    },
                    # No privileged ports
                    {
                        "msg": "Container exposes privileged ports",
                        "expr": 'any([port.HostPort < 1024 | port = input.Config.ExposedPorts[_]])'
                    },
                    # Required security options
                    {
                        "msg": "Missing security options",
                        "expr": 'not input.Config.Labels["security.scan.date"]'
                    },
                    # No sensitive environment variables
                    {
                        "msg": "Sensitive data in environment variables",
                        "expr": 'any([contains(env, "PASSWORD") or contains(env, "KEY") or contains(env, "SECRET") | env = input.Config.Env[_]])'
                    }
                ]
            }
        }
    }
    
    return policies

Distroless and minimal base images provide enhanced security by eliminating unnecessary components. These images contain only application runtime dependencies, removing shells, package managers, and other tools attackers commonly exploit. While distroless images complicate debugging, they significantly reduce attack surface and vulnerability count.