+
webstorm
gcp
//
graphdb
micronaut
+
+
+
+
+
macos
+
haiku
+
+
+
webpack
+
+
+
webpack
+
+
rocket
nest
unix
+
+
aurelia
?
sails
+
raspbian
+
+
~
termux
+
notepad++
+
+
+
%
+
websocket
+
matplotlib
nuxt
+
npm
+
+
pinecone
+
+
istio
+
crystal
+
+
+
+
+
+
+
cassandra
+
+
pascal
+
eclipse
jax
xml
backbone
elasticsearch
influxdb
+
+
+
+
fedora
+
+
+
+
+
Back to Blog
Implementing Container Security with Podman on Rocky Linux 🔐
rocky-linux podman container-security

Implementing Container Security with Podman on Rocky Linux 🔐

Published Jul 15, 2025

Master rootless container security with Podman on Rocky Linux 9. Learn to implement defense-in-depth strategies, SELinux integration, secure image management, and enterprise-grade container runtime security.

5 min read
0 views
Table of Contents

In the evolving landscape of container technology, security has become paramount. Podman, with its daemonless, rootless architecture, represents a paradigm shift in container security. This comprehensive guide demonstrates how to implement enterprise-grade container security using Podman on Rocky Linux 9, covering everything from rootless containers to advanced SELinux policies and secure supply chain management.

🌟 Why Podman for Container Security?

Podman’s architecture fundamentally differs from traditional container runtimes, offering inherent security advantages that make it ideal for security-conscious enterprises and compliance-driven environments.

Security-First Architecture

  • Daemonless Design - No persistent daemon means reduced attack surface 🛡️
  • Rootless Containers - Run containers without root privileges by default 👤
  • SELinux Integration - Native support for mandatory access controls 🔒
  • User Namespaces - Strong isolation between containers and host 🏰
  • Systemd Integration - Leverage systemd’s security features 🔧

📋 Prerequisites and Security Baseline

System Requirements

# Rocky Linux 9 minimal installation
- CPU: 2+ cores (4 recommended)
- RAM: 4 GB minimum (8 GB recommended)
- Storage: 20 GB for system + container storage
- Network: Properly configured firewall
- SELinux: Enforcing mode

Initial Security Hardening

# Update system
sudo dnf update -y

# Install security tools
sudo dnf install -y \
  aide \
  audit \
  rkhunter \
  fail2ban \
  firewalld \
  policycoreutils-python-utils \
  setroubleshoot-server

# Enable and configure firewall
sudo systemctl enable --now firewalld
sudo firewall-cmd --set-default-zone=drop
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload

# Configure audit daemon
sudo systemctl enable --now auditd
sudo auditctl -e 1  # Enable auditing

SELinux Configuration

# Ensure SELinux is enforcing
sudo setenforce 1
sudo sed -i 's/SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config

# Install SELinux utilities
sudo dnf install -y \
  selinux-policy-devel \
  setools-console \
  policycoreutils-devel

# Check SELinux status
sestatus

🔧 Installing and Securing Podman

Installation

# Install Podman and security tools
sudo dnf install -y \
  podman \
  podman-plugins \
  podman-compose \
  buildah \
  skopeo \
  crun \
  fuse-overlayfs \
  container-selinux

# Verify installation
podman version
podman info --debug

Configure Secure Defaults

# Configure containers.conf for security
sudo tee /etc/containers/containers.conf << 'EOF'
[containers]
# Use crun for better security features
runtime = "crun"

# Default capabilities (minimal set)
default_capabilities = [
  "CHOWN",
  "DAC_OVERRIDE",
  "FOWNER",
  "FSETID",
  "KILL",
  "NET_BIND_SERVICE",
  "SETFCAP",
  "SETGID",
  "SETPCAP",
  "SETUID"
]

# Security options
no_new_privileges = true
seccomp_profile = "/usr/share/containers/seccomp.json"

# Default ulimits
default_ulimits = [
  "nofile=1024:1024",
  "nproc=1024:1024"
]

[engine]
# Runtime security
runtime_supports_nocgroups = ["crun"]
runtime_supports_json = ["crun", "runc"]

# Image security
pull_policy = "always"
EOF

# Configure registries
sudo tee /etc/containers/registries.conf << 'EOF'
unqualified-search-registries = ["registry.access.redhat.com", "registry.fedoraproject.org", "docker.io"]

[[registry]]
location = "docker.io"
blocked = false

[[registry.mirror]]
location = "mirror.gcr.io"

# Block insecure registries
[registries.insecure]
registries = []
EOF

🏃 Rootless Container Implementation

Setting Up Rootless Podman

# Enable lingering for user (allows user services to run without login)
sudo loginctl enable-linger $USER

# Configure subuid and subgid
sudo usermod --add-subuids 100000-165535 $USER
sudo usermod --add-subgids 100000-165535 $USER

# Verify mappings
grep $USER /etc/subuid /etc/subgid

# Configure user namespaces
echo "user.max_user_namespaces=28633" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Set up XDG runtime directory
export XDG_RUNTIME_DIR=/run/user/$(id -u)

Rootless Storage Configuration

# Configure storage for rootless containers
mkdir -p ~/.config/containers

tee ~/.config/containers/storage.conf << 'EOF'
[storage]
driver = "overlay"
runroot = "/run/user/1000/containers"
graphroot = "/home/user/.local/share/containers/storage"

[storage.options]
# Enable additional security options
mount_program = "/usr/bin/fuse-overlayfs"
mountopt = "nodev,metacopy=on"

[storage.options.overlay]
# Security mount options
mountopt = "nodev,metacopy=on"

# Size limits
size = "10G"
EOF

# Initialize rootless storage
podman system migrate
podman info

Rootless Networking

# Configure rootless networking
tee ~/.config/containers/containers.conf << 'EOF'
[network]
# Use slirp4netns for rootless networking
network_backend = "slirp4netns"

[engine]
# Rootless network configuration
network_cmd_options = [
  "enable_ipv6=false",
  "mtu=1500"
]
EOF

# Test rootless networking
podman run --rm alpine ping -c 3 8.8.8.8

🔒 SELinux Container Policies

Understanding Container SELinux Contexts

# View container SELinux contexts
ps -eZ | grep container

# Check available container types
seinfo -t | grep container

# Common container contexts:
# container_t - Standard container process
# container_file_t - Container files
# container_var_lib_t - Container persistent storage
# container_runtime_t - Container runtime processes

Custom SELinux Policies

# Create custom policy for application containers
cat > webapp_container.te << 'EOF'
policy_module(webapp_container, 1.0.0)

require {
    type container_t;
    type container_file_t;
    type httpd_port_t;
    type postgresql_port_t;
    class tcp_socket { name_connect };
    class file { read write };
}

# Allow web containers to connect to database
allow container_t postgresql_port_t:tcp_socket name_connect;

# Allow containers to read/write specific files
allow container_t container_file_t:file { read write };
EOF

# Compile and install policy
make -f /usr/share/selinux/devel/Makefile webapp_container.pp
sudo semodule -i webapp_container.pp

# Verify policy is loaded
sudo semodule -l | grep webapp_container

SELinux Container Labeling

# Run container with specific SELinux context
podman run -d \
  --name webapp \
  --security-opt label=type:container_webapp_t \
  --security-opt label=level:s0:c100,c200 \
  nginx:alpine

# Change file context for volumes
sudo semanage fcontext -a -t container_file_t "/data/webapp(/.*)?"
sudo restorecon -Rv /data/webapp

# Verify contexts
ls -laZ /data/webapp
podman inspect webapp | grep -A5 "SecurityOpt"

🛡️ Container Image Security

Secure Image Building with Buildah

# Create secure Containerfile
cat > Containerfile.secure << 'EOF'
# Use minimal base image
FROM registry.access.redhat.com/ubi9-minimal:latest

# Security labels
LABEL maintainer="[email protected]"
LABEL version="1.0"
LABEL security.scan="required"

# Create non-root user
RUN microdnf install -y shadow-utils && \
    microdnf clean all && \
    useradd -r -u 1001 -g 0 -s /sbin/nologin appuser

# Install only necessary packages
RUN microdnf install -y \
    python3 \
    python3-pip && \
    microdnf clean all && \
    rm -rf /var/cache/yum

# Copy application
COPY --chown=1001:0 app/ /app/

# Set secure permissions
RUN chmod -R g=u /app && \
    chmod -R o-rwx /app

# Security configurations
USER 1001
WORKDIR /app

# Read-only root filesystem
VOLUME ["/tmp", "/var/tmp"]

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD python3 /app/healthcheck.py || exit 1

# Run as non-root
ENTRYPOINT ["python3"]
CMD ["/app/main.py"]
EOF

# Build with security scanning
buildah bud \
  --format docker \
  --layers \
  --label security.scan.date="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
  -t secure-app:latest \
  -f Containerfile.secure .

Image Vulnerability Scanning

# Install Trivy scanner
sudo dnf install -y epel-release
sudo dnf install -y trivy

# Scan image for vulnerabilities
trivy image --severity HIGH,CRITICAL secure-app:latest

# Scan with detailed output
trivy image \
  --format json \
  --output scan-results.json \
  --severity HIGH,CRITICAL \
  --vuln-type os,library \
  secure-app:latest

# Create scanning script
cat > /usr/local/bin/scan-image.sh << 'EOF'
#!/bin/bash
IMAGE=$1
SEVERITY=${2:-HIGH,CRITICAL}

echo "Scanning image: $IMAGE"
trivy image --severity $SEVERITY $IMAGE

if [ $? -ne 0 ]; then
    echo "Security vulnerabilities found!"
    exit 1
fi

echo "Image passed security scan"
EOF

chmod +x /usr/local/bin/scan-image.sh

Image Signing with Sigstore

# Install cosign
curl -L https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 -o cosign
chmod +x cosign
sudo mv cosign /usr/local/bin/

# Generate key pair
cosign generate-key-pair

# Sign container image
cosign sign --key cosign.key localhost/secure-app:latest

# Verify image signature
cosign verify --key cosign.pub localhost/secure-app:latest

# Configure Podman to require signatures
cat >> /etc/containers/policy.json << 'EOF'
{
  "default": [{"type": "insecureAcceptAnything"}],
  "transports": {
    "docker": {
      "localhost": [
        {
          "type": "signedBy",
          "keyType": "GPGKeys",
          "keyPath": "/etc/pki/containers/cosign.pub"
        }
      ]
    }
  }
}
EOF

🔐 Runtime Security Controls

Seccomp Profiles

# Create custom seccomp profile
cat > webapp-seccomp.json << 'EOF'
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "defaultErrnoRet": 1,
  "archMap": [
    {
      "architecture": "SCMP_ARCH_X86_64",
      "subArchitectures": [
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
      ]
    }
  ],
  "syscalls": [
    {
      "names": [
        "accept", "accept4", "access", "bind", "brk",
        "clock_gettime", "clone", "close", "connect",
        "dup", "dup2", "epoll_create", "epoll_ctl",
        "epoll_wait", "execve", "exit", "exit_group",
        "fcntl", "fstat", "futex", "getdents64",
        "getpid", "getppid", "getsockname", "getsockopt",
        "listen", "lseek", "mmap", "mprotect", "munmap",
        "open", "openat", "pipe", "poll", "pread64",
        "pwrite64", "read", "readlink", "recvfrom",
        "recvmsg", "rename", "rt_sigaction", "rt_sigprocmask",
        "sendmsg", "sendto", "set_tid_address", "setsockopt",
        "shutdown", "sigaltstack", "socket", "stat",
        "uname", "unlink", "wait4", "write"
      ],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}
EOF

# Run container with custom seccomp profile
podman run -d \
  --name secure-webapp \
  --security-opt seccomp=webapp-seccomp.json \
  --read-only \
  --tmpfs /tmp \
  --tmpfs /var/tmp \
  secure-app:latest

AppArmor Integration (if enabled)

# Install AppArmor utilities
sudo dnf install -y apparmor-utils

# Create AppArmor profile for containers
sudo tee /etc/apparmor.d/podman-container << 'EOF'
#include <tunables/global>

profile podman-container flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>
  
  # Deny network access
  deny network raw,
  
  # File access
  /usr/bin/podman ix,
  /usr/lib/** r,
  /proc/sys/kernel/random/uuid r,
  /dev/null rw,
  /dev/zero rw,
  /dev/urandom r,
  
  # Temp directories
  /tmp/** rw,
  /var/tmp/** rw,
  
  # Deny sensitive paths
  deny /etc/shadow r,
  deny /etc/passwd w,
  deny /root/** rwx,
  deny /home/** rwx,
}
EOF

# Load profile
sudo apparmor_parser -r /etc/apparmor.d/podman-container

# Run with AppArmor
podman run -d \
  --name apparmor-test \
  --security-opt apparmor=podman-container \
  nginx:alpine

Resource Limits and Cgroups

# Run container with resource limits
podman run -d \
  --name limited-app \
  --memory="512m" \
  --memory-swap="512m" \
  --cpus="0.5" \
  --pids-limit=100 \
  --ulimit nofile=1024:1024 \
  --ulimit nproc=512:512 \
  --read-only \
  --security-opt=no-new-privileges \
  secure-app:latest

# Create systemd unit with resource limits
podman generate systemd \
  --new \
  --name limited-app \
  --restart-policy=on-failure \
  --restart-sec=30 > ~/.config/systemd/user/limited-app.service

# Add additional security to systemd unit
cat >> ~/.config/systemd/user/limited-app.service << 'EOF'

# Additional security settings
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
NoNewPrivileges=yes
ReadOnlyPaths=/
ReadWritePaths=/tmp /var/tmp
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
MemoryDenyWriteExecute=yes
LockPersonality=yes
EOF

# Enable and start service
systemctl --user daemon-reload
systemctl --user enable --now limited-app.service

🌐 Network Security

Container Network Isolation

# Create isolated network
podman network create \
  --driver bridge \
  --subnet 10.88.0.0/24 \
  --gateway 10.88.0.1 \
  --opt isolate=true \
  secure-net

# Create network with custom firewall rules
cat > /etc/containers/networks/secure-net.conflist << 'EOF'
{
  "cniVersion": "0.4.0",
  "name": "secure-net",
  "plugins": [
    {
      "type": "bridge",
      "bridge": "cni-secure",
      "isGateway": true,
      "ipMasq": true,
      "hairpinMode": true,
      "ipam": {
        "type": "host-local",
        "routes": [{"dst": "0.0.0.0/0"}],
        "ranges": [[{"subnet": "10.88.0.0/24", "gateway": "10.88.0.1"}]]
      }
    },
    {
      "type": "firewall",
      "backend": "iptables",
      "forward": false,
      "masquerade": true
    },
    {
      "type": "tuning",
      "sysctl": {
        "net.ipv4.conf.all.forwarding": "0",
        "net.ipv4.conf.all.send_redirects": "0",
        "net.ipv4.conf.all.accept_redirects": "0"
      }
    }
  ]
}
EOF

# Run containers in isolated network
podman run -d \
  --name webapp \
  --network secure-net \
  --ip 10.88.0.10 \
  nginx:alpine

podman run -d \
  --name database \
  --network secure-net \
  --ip 10.88.0.20 \
  postgres:alpine

Network Policies with Firewall

# Configure firewall rules for containers
sudo firewall-cmd --new-zone=containers --permanent
sudo firewall-cmd --zone=containers --add-source=10.88.0.0/24 --permanent
sudo firewall-cmd --zone=containers --add-service=http --permanent
sudo firewall-cmd --zone=containers --add-service=https --permanent
sudo firewall-cmd --reload

# Create iptables rules for inter-container communication
sudo iptables -N CONTAINER-SECURITY
sudo iptables -A CONTAINER-SECURITY -s 10.88.0.10 -d 10.88.0.20 -p tcp --dport 5432 -j ACCEPT
sudo iptables -A CONTAINER-SECURITY -j DROP

# Apply rules to container traffic
sudo iptables -I FORWARD -s 10.88.0.0/24 -j CONTAINER-SECURITY

📁 Secure Volume Management

Encrypted Volumes

# Create encrypted volume
sudo dnf install -y cryptsetup

# Create encrypted container storage
sudo dd if=/dev/zero of=/var/lib/containers-encrypted.img bs=1G count=10
sudo cryptsetup luksFormat /var/lib/containers-encrypted.img
sudo cryptsetup open /var/lib/containers-encrypted.img containers-secure

# Format and mount
sudo mkfs.xfs /dev/mapper/containers-secure
sudo mkdir -p /var/lib/containers-secure
sudo mount /dev/mapper/containers-secure /var/lib/containers-secure

# Configure Podman to use encrypted storage
cat >> ~/.config/containers/storage.conf << 'EOF'
[storage]
driver = "overlay"
runroot = "/run/user/1000/containers"
graphroot = "/var/lib/containers-secure/storage"
EOF

Volume Security Labels

# Create volume with SELinux labels
podman volume create \
  --label security=high \
  --opt o=context=system_u:object_r:container_file_t:s0:c100,c200 \
  secure-data

# Mount with security options
podman run -d \
  --name secure-db \
  -v secure-data:/var/lib/postgresql/data:Z \
  --security-opt label=level:s0:c100,c200 \
  postgres:alpine

# Verify SELinux contexts
podman volume inspect secure-data
ls -laZ $(podman volume inspect secure-data --format '{{.Mountpoint}}')

🔍 Security Monitoring and Auditing

Container Activity Auditing

# Configure audit rules for container activities
sudo tee /etc/audit/rules.d/containers.rules << 'EOF'
# Monitor container runtime
-w /usr/bin/podman -p x -k container_runtime
-w /usr/bin/runc -p x -k container_runtime
-w /usr/bin/crun -p x -k container_runtime

# Monitor container storage
-w /var/lib/containers/ -p wa -k container_storage
-w /etc/containers/ -p wa -k container_config

# Monitor container processes
-a always,exit -F arch=b64 -S clone -F a0&0x7C020000 -k container_create
-a always,exit -F arch=b64 -S unshare -k container_unshare

# Monitor capability changes
-a always,exit -F arch=b64 -S capset -k container_capabilities
EOF

# Reload audit rules
sudo augenrules --load
sudo systemctl restart auditd

# Search audit logs for container events
sudo ausearch -k container_runtime -ts recent

Runtime Security Monitoring

# Create monitoring script
cat > /usr/local/bin/container-monitor.sh << 'EOF'
#!/bin/bash

# Monitor running containers
while true; do
    echo "=== Container Security Status $(date) ==="
    
    # Check for privileged containers
    echo "Checking for privileged containers..."
    podman ps --format "table {{.Names}}\t{{.SecurityOpt}}" | grep -i privileged
    
    # Check for containers running as root
    echo "Checking for root containers..."
    for container in $(podman ps -q); do
        user=$(podman exec $container id -u 2>/dev/null)
        if [ "$user" = "0" ]; then
            echo "WARNING: Container $(podman ps --filter id=$container --format {{.Names}}) running as root"
        fi
    done
    
    # Check for excessive capabilities
    echo "Checking container capabilities..."
    for container in $(podman ps -q); do
        caps=$(podman inspect $container --format '{{.EffectiveCaps}}')
        echo "Container $(podman ps --filter id=$container --format {{.Names}}): $caps"
    done
    
    sleep 300
done
EOF

chmod +x /usr/local/bin/container-monitor.sh

# Create systemd service for monitoring
sudo tee /etc/systemd/system/container-monitor.service << 'EOF'
[Unit]
Description=Container Security Monitor
After=podman.service

[Service]
Type=simple
ExecStart=/usr/local/bin/container-monitor.sh
Restart=always
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now container-monitor.service

Security Event Logging

# Configure container logging
cat >> ~/.config/containers/containers.conf << 'EOF'
[containers]
# Enable detailed logging
log_driver = "journald"
log_tag = "container/{{.Name}}/{{.ID}}"

[engine]
# Event logging
events_logger = "journald"
events_log_file_path = ""
EOF

# Create log analysis script
cat > /usr/local/bin/analyze-container-logs.sh << 'EOF'
#!/bin/bash

echo "=== Container Security Log Analysis ==="

# Check for authentication failures
echo "Authentication failures:"
journalctl -u podman --since "1 hour ago" | grep -i "auth\|fail\|denied"

# Check for SELinux denials
echo -e "\nSELinux denials:"
sudo ausearch -m AVC -ts recent | grep container

# Check for capability requests
echo -e "\nCapability requests:"
journalctl -u podman --since "1 hour ago" | grep -i "cap_\|capability"

# Check for network anomalies
echo -e "\nNetwork anomalies:"
journalctl -u podman --since "1 hour ago" | grep -i "connection refused\|timeout"
EOF

chmod +x /usr/local/bin/analyze-container-logs.sh

🚀 Secure Container Deployment

Production Deployment Example

# Create production-ready container deployment
cat > deploy-secure-app.sh << 'EOF'
#!/bin/bash
set -euo pipefail

APP_NAME="secure-webapp"
IMAGE="localhost/secure-app:latest"
NETWORK="secure-net"

# Pre-deployment checks
echo "Running pre-deployment security checks..."

# Scan image
trivy image --severity HIGH,CRITICAL --exit-code 1 $IMAGE || {
    echo "Image failed security scan"
    exit 1
}

# Verify image signature
cosign verify --key /etc/pki/containers/cosign.pub $IMAGE || {
    echo "Image signature verification failed"
    exit 1
}

# Create secure container
podman run -d \
  --name $APP_NAME \
  --network $NETWORK \
  --health-cmd='/app/healthcheck.sh' \
  --health-interval=30s \
  --health-retries=3 \
  --health-start-period=60s \
  --restart=on-failure:3 \
  --memory="1g" \
  --memory-swap="1g" \
  --cpus="1.0" \
  --pids-limit=200 \
  --read-only \
  --tmpfs /tmp:rw,noexec,nodev,nosuid,size=100m \
  --tmpfs /var/tmp:rw,noexec,nodev,nosuid,size=100m \
  --security-opt=no-new-privileges \
  --security-opt label=type:container_webapp_t \
  --security-opt seccomp=/etc/containers/seccomp/webapp.json \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --publish 8080:8080 \
  --env-file /etc/containers/webapp.env \
  --secret webapp-tls-cert,target=/etc/ssl/certs/webapp.crt \
  --secret webapp-tls-key,target=/etc/ssl/private/webapp.key \
  --log-driver=journald \
  --log-opt tag="{{.Name}}/{{.ID}}" \
  $IMAGE

echo "Container deployed successfully"
echo "Running post-deployment verification..."

# Verify container is running with correct security context
podman inspect $APP_NAME --format '{{.State.Status}}' | grep -q running
podman inspect $APP_NAME --format '{{.EffectiveCaps}}' | grep -q '^\[NET_BIND_SERVICE\]$'

echo "Deployment complete and verified"
EOF

chmod +x deploy-secure-app.sh

Container Secrets Management

# Create secret for sensitive data
echo -n "SuperSecretPassword123!" | podman secret create db-password -

# Create TLS certificates secret
podman secret create webapp-tls-cert /path/to/cert.pem
podman secret create webapp-tls-key /path/to/key.pem

# Use secrets in container
podman run -d \
  --name secure-db \
  --secret db-password \
  --env POSTGRES_PASSWORD_FILE=/run/secrets/db-password \
  postgres:alpine

# List and manage secrets
podman secret ls
podman secret inspect db-password

🔧 Troubleshooting Security Issues

Common Security Issues

# SELinux troubleshooting
# Check for denials
sudo ausearch -m AVC -ts recent

# Generate policy for denials
sudo ausearch -m AVC -ts recent | audit2allow -M mycontainer
sudo semodule -i mycontainer.pp

# Temporarily disable for testing (NOT for production)
sudo semanage permissive -a container_t

# Debug rootless issues
podman unshare cat /proc/self/uid_map
podman info --debug | grep -i rootless

# Check user namespaces
cat /proc/sys/user/max_user_namespaces

Security Scanning Automation

# Create CI/CD security scanning
cat > .gitlab-ci.yml << 'EOF'
stages:
  - build
  - security
  - deploy

variables:
  IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

build:
  stage: build
  script:
    - buildah bud -t $IMAGE_NAME .
    - buildah push $IMAGE_NAME

security-scan:
  stage: security
  script:
    - trivy image --exit-code 1 --severity HIGH,CRITICAL $IMAGE_NAME
    - |
      if [ $? -ne 0 ]; then
        echo "Security vulnerabilities found!"
        exit 1
      fi

sign-image:
  stage: security
  script:
    - cosign sign --key $COSIGN_KEY $IMAGE_NAME
  only:
    - main

deploy:
  stage: deploy
  script:
    - ./deploy-secure-app.sh
  only:
    - main
EOF

🎯 Security Best Practices

Container Security Checklist

  1. Image Security

    • ✅ Use minimal base images (UBI, Alpine)
    • ✅ Scan images for vulnerabilities
    • ✅ Sign and verify images
    • ✅ Regular image updates
    • ✅ Multi-stage builds
  2. Runtime Security

    • ✅ Run rootless containers
    • ✅ Drop all capabilities, add only required
    • ✅ Use read-only root filesystem
    • ✅ Implement resource limits
    • ✅ Enable SELinux/AppArmor
  3. Network Security

    • ✅ Isolate container networks
    • ✅ Implement firewall rules
    • ✅ Use TLS for all communications
    • ✅ Disable unnecessary protocols
    • ✅ Regular security audits
  4. Data Security

    • ✅ Encrypt sensitive data at rest
    • ✅ Use secrets management
    • ✅ Implement proper access controls
    • ✅ Regular backups
    • ✅ Audit data access
  5. Monitoring

    • ✅ Enable comprehensive logging
    • ✅ Monitor security events
    • ✅ Set up alerting
    • ✅ Regular security reviews
    • ✅ Incident response plan

Compliance Considerations

# CIS Benchmark compliance check
cat > cis-docker-benchmark.sh << 'EOF'
#!/bin/bash
echo "CIS Podman/Container Benchmark Check"

# 5.1 Ensure that, if applicable, an AppArmor Profile is enabled
echo -n "5.1 AppArmor Profile: "
podman inspect webapp --format '{{ .AppArmorProfile }}' || echo "Not configured"

# 5.2 Ensure that, if applicable, SELinux security options are set
echo -n "5.2 SELinux Options: "
podman inspect webapp --format '{{ .HostConfig.SecurityOpt }}' | grep -q label && echo "PASS" || echo "FAIL"

# 5.3 Ensure that Linux kernel capabilities are restricted
echo -n "5.3 Capabilities Restricted: "
caps=$(podman inspect webapp --format '{{ .EffectiveCaps }}')
[ "$caps" = "[]" ] && echo "PASS" || echo "FAIL - Has capabilities: $caps"

# 5.4 Ensure that privileged containers are not used
echo -n "5.4 No Privileged Containers: "
podman ps --format '{{ .Names }} {{ .Privileged }}' | grep -q true && echo "FAIL" || echo "PASS"

# 5.5 Ensure sensitive host system directories are not mounted
echo -n "5.5 No Sensitive Mounts: "
podman inspect webapp --format '{{ .Mounts }}' | grep -E '(/etc|/root|/var/run/docker.sock)' && echo "FAIL" || echo "PASS"
EOF

chmod +x cis-docker-benchmark.sh

📚 Advanced Security Topics

Supply Chain Security

# Implement SLSA compliance
cat > slsa-provenance.json << 'EOF'
{
  "_type": "https://in-toto.io/Statement/v0.1",
  "predicateType": "https://slsa.dev/provenance/v0.1",
  "subject": [{
    "name": "localhost/secure-app",
    "digest": {
      "sha256": "..."
    }
  }],
  "predicate": {
    "builder": {
      "id": "https://github.com/example/builder@v1"
    },
    "buildType": "https://example.com/container/v1",
    "invocation": {
      "configSource": {
        "uri": "git+https://github.com/example/app@refs/heads/main",
        "digest": {
          "sha1": "..."
        }
      }
    }
  }
}
EOF

# Sign provenance
cosign attest --key cosign.key --predicate slsa-provenance.json localhost/secure-app:latest

Zero Trust Container Architecture

# Implement zero trust principles
# 1. Never trust, always verify
# 2. Least privilege access
# 3. Assume breach

# Service mesh integration for zero trust
podman network create zero-trust-mesh

# Run with service mesh sidecar
podman pod create --name webapp-pod --network zero-trust-mesh

podman run -d \
  --pod webapp-pod \
  --name envoy-proxy \
  envoyproxy/envoy:latest

podman run -d \
  --pod webapp-pod \
  --name webapp \
  localhost/secure-app:latest

🌐 Resources and Next Steps

Learning Path

  1. Container Security Fundamentals - Understanding attack vectors
  2. SELinux Deep Dive - Advanced policy creation
  3. Supply Chain Security - SBOM and attestation
  4. Runtime Protection - Falco and runtime security
  5. Compliance Automation - Policy as Code

Useful Resources


Implementing container security with Podman on Rocky Linux 9 provides a robust foundation for running containers in production environments. By leveraging rootless containers, SELinux integration, and comprehensive security controls, you can build a defense-in-depth strategy that protects your containerized applications. Remember that security is an ongoing process – continuously monitor, audit, and improve your container security posture. Stay secure! 🔐