Files
2026-03-24 21:49:56 +01:00

20 KiB

Phase 2: Lab 01 - IAM & Sicurezza - Research

Researched: 2026-03-24 Domain: Docker Security, Linux User Management, IAM Parallels Confidence: HIGH

Summary

Phase 2 focuses on teaching IAM (Identity and Access Management) concepts through local Linux user management and Docker socket permissions. Students will learn to configure Linux users, groups, and Docker socket access control, drawing direct parallels to AWS IAM Users, Roles, and Policies.

Primary recommendation: Use standard Docker group-based permissions model for socket access, complemented by rootless Docker demonstrations for advanced security concepts. Avoid custom authentication layers - use Docker's native security model.

Standard Stack

Core

Library/Tool Version Purpose Why Standard
Docker Engine >= 24.0 Container runtime, socket permissions Project-wide standard, native permission model
Docker Compose V2 Multi-container orchestration Project-wide standard
Linux utilities (system) useradd, groupadd, chmod, chown Standard POSIX user management
BASH >= 4.0 Test scripting, validation Project-wide TDD approach

Supporting

Library/Tool Version Purpose When to Use
BATS Core latest Advanced test framework Optional: for complex test suites beyond basic bash
newuidmap/newgidmap (system) User namespace mapping For rootless Docker demonstrations

Alternatives Considered

Instead of Could Use Tradeoff
Docker group permissions Rootless Docker only Rootless is more secure but harder to teach beginners; start with group model, mention rootless as advanced topic
BASH scripts BATS framework BATS provides better testing primitives but adds dependency; use BASH for simplicity, BATS optional for advanced validation

Installation:

# Core utilities (typically pre-installed)
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# For rootless Docker (optional/advanced)
sudo apt-get install -y uidmap slirp4netns fuse-overlayfs

Architecture Patterns

labs/lab-01-iam/
├── tutorial/
│   ├── 01-create-users.md
│   ├── 02-docker-groups.md
│   ├── 03-socket-permissions.md
│   └── 04-verification.md
├── how-to-guides/
│   ├── add-user-to-docker-group.md
│   ├── verify-non-root-container.md
│   └── reset-docker-permissions.md
├── reference/
│   ├── docker-socket-permissions.md
│   ├── linux-users-groups.md
│   └── iam-parallels.md
├── explanation/
│   └── docker-iam-parallels.md
├── tests/
│   ├── 01-user-creation-test.sh
│   ├── 02-docker-access-test.sh
│   └── 03-non-root-test.sh
└── docker-compose.yml

Pattern 1: Docker Group-Based Socket Access

What: Standard Docker security model where adding users to docker group grants socket access When to use: Default teaching approach for Lab 1 Example:

# Source: Docker official documentation
# Create user without Docker access
sudo useradd -m -s /bin/bash student1

# Add to docker group for socket access
sudo usermod -aG docker student1

# Verify group membership
groups student1
# Output: student1 : student1 docker

# Test access (requires re-login for group changes to take effect)
su - student1
docker ps

Pattern 2: Non-Root Container Execution

What: Running containers as unprivileged users instead of root (default) When to use: ALL containers in Lab 1 (INF-01 requirement) Example:

# Source: Docker security best practices
FROM alpine:3.19
# Create non-root user
RUN addgroup -g 1000 appuser && \
    adduser -D -u 1000 -G appuser appuser
# Switch to non-root user
USER appuser
# Verify non-root execution
CMD ["sh", "-c", "whoami && sleep 3600"]
# docker-compose.yml
services:
  test-container:
    image: alpine:3.19
    user: "1000:1000"  # UID:GID for non-root
    command: ["sh", "-c", "whoami && sleep 3600"]

Pattern 3: IAM Parallels Documentation

What: Explicit mapping between Linux concepts and AWS IAM concepts When to use: In Explanation documents Example:

# Parallel: Linux User Management → AWS IAM

| Concepto Linux | AWS IAM Equivalente | Spiegazione |
|----------------|---------------------|-------------|
| Utente Linux (`student1`) | IAM User | Identità che può autenticarsi |
| Gruppo Linux (`docker`) | IAM Group | Collezione di utenti con stessi permessi |
| Permessi file/socket | IAM Policy | Regole che definiscono cosa è permesso |
| `/var/run/docker.sock` | Service Endpoint | Risorsa protetta da controlli accesso |
| `sudo` elevation | IAM Role Assumption | Temporanea elevazione privilegi |

Anti-Patterns to Avoid

  • Running containers as root: Violates INF-01, creates security risk
  • Using --privileged flag: Defeats container isolation, never use in teaching
  • chmod 777 on docker.sock: Breaks all security models
  • Teaching rootless Docker first: Too advanced for beginners, teach group model first
  • Skipping verification tests: TDD approach requires RED→GREEN→REFACTOR cycle

Don't Hand-Roll

Problem Don't Build Use Instead Why
Docker permission system Custom ACL scripts Native docker group membership Docker's built-in security model is battle-tested
User authentication PAM modules Standard Linux useradd/usermod Simpler, widely understood, POSIX compliant
Test framework Custom assertion library BASH builtins + BATS (optional) No dependency hell, students already know bash
Container user management Custom uid/gid mapping Docker USER directive, user namespaces Native Docker features handle edge cases

Key insight: Docker's permission model, while simple, is production-grade. Building custom authentication layers teaches wrong lessons about using established security patterns.

Common Pitfalls

Pitfall 1: Group Membership Requires Re-Login

What goes wrong: User added to docker group but docker ps still fails with "permission denied" Why it happens: Group membership is evaluated at login; current session doesn't see new groups How to avoid: Teach students to use newgrp docker OR su - user OR logout/login Warning signs: "Got permission denied while trying to connect to the Docker daemon socket"

Pitfall 2: Testing as Wrong User

What goes wrong: Test passes when run as root but fails as regular user Why it happens: Root can bypass Docker socket permissions How to avoid: All tests MUST run as non-privileged user, use sudo -u student1 for testing Warning signs: Test passes with sudo but fails without it

Pitfall 3: Insufficient Verification of Non-Root Execution

What goes wrong: Container configured with USER directive but still running as root Why it happens: Dockerfile USER directive not applied, or docker-compose user override missing, or container switches back to root How to avoid: Always verify with docker exec <container> whoami AND docker inspect <container> | grep User Warning signs: Container process shows as root in docker top or docker inspect

Pitfall 4: Socket Permissions After Docker Restart

What goes wrong: Docker daemon restart changes socket permissions Why it happens: Docker daemon may reset socket ownership on restart How to avoid: Document that docker group membership persists but socket may need verification Warning signs: Previously working docker commands fail after sudo systemctl restart docker

Code Examples

Verified patterns from official sources:

Creating Non-Root Dockerfile

# Source: Docker security best practices
FROM alpine:3.19

# Create non-root user with specific UID/GID for consistency
RUN addgroup -g 1000 appgroup && \
    adduser -D -u 1000 -G appgroup appuser

# Switch to non-root user BEFORE any operations that don't require root
USER appuser

# Verify non-root execution
CMD ["sh", "-c", "echo 'Running as:' && whoami"]

Verifying Container User Runtime

# Source: Docker CLI documentation
# Method 1: Execute whoami inside container
docker exec <container_name> whoami
# Expected output: appuser (NOT root)

# Method 2: Inspect container configuration
docker inspect <container_name> --format='{{.State.User}}'
# Note: May show empty if using docker-compose user directive

# Method 3: Check process on host
docker top <container_name>
# Look at USER column - should show UID (e.g., 1000), NOT 0 (root)

# Method 4: Comprehensive check script
#!/bin/bash
container_name=$1
actual_user=$(docker exec $container_name whoami)
echo "Container running as: $actual_user"
if [ "$actual_user" = "root" ]; then
    echo "FAIL: Container running as root!"
    exit 1
else
    echo "PASS: Container running as non-root user"
    exit 0
fi

Testing Docker Access Control

# Source: TDD approach for infrastructure
#!/bin/bash
# RED phase: Test should fail initially

# Test 1: Non-group member cannot access docker socket
test_unauthorized_access() {
    sudo useradd -m -s /bin/bash test_user 2>/dev/null || true
    if sudo -u test_user docker ps &>/dev/null; then
        echo "FAIL: test_user can access docker without being in docker group"
        return 1
    else
        echo "PASS: test_user correctly denied access"
        return 0
    fi
}

# Test 2: Group member can access docker socket
test_authorized_access() {
    sudo usermod -aG docker test_user
    # newgrp doesn't work in sudo, so we need to test differently
    # Check group membership instead
    if groups test_user | grep -q docker; then
        echo "PASS: test_user is in docker group"
        return 0
    else
        echo "FAIL: test_user not in docker group"
        return 1
    fi
}

# Test 3: Container runs as non-root
test_non_root_container() {
    # Create test container
    echo 'FROM alpine:3.19
RUN adduser -D -u 1000 testuser
USER testuser
CMD ["sh", "-c", "whoami"]' > /tmp/test.Dockerfile

    docker build -f /tmp/test.Dockerfile -t test-non-root . >/dev/null 2>&1
    result=$(docker run --rm test-non-root)

    if [ "$result" = "testuser" ]; then
        echo "PASS: Container runs as non-root user"
        return 0
    else
        echo "FAIL: Container running as $result (expected testuser)"
        return 1
    fi
}

# Run all tests
test_unauthorized_access && \
test_authorized_access && \
test_non_root_container && \
echo "All tests passed!" || echo "Some tests failed"

State of the Art

Old Approach Current Approach When Changed Impact
Rootful Docker only Rootless Docker available Docker 19.03+ Labs can now demonstrate true non-root Docker daemon
--user flag only User namespaces + userns-remap Docker 1.10+ Multiple isolation layers for defense-in-depth
Manual test scripts BATS framework adoption 2020+ Professional-grade test infrastructure for bash

Deprecated/outdated:

  • Docker socket as chmod 777: NEVER use, completely bypasses security
  • Running daemons as root inside container: Violates security best practices
  • Using --privileged flag: Defeats container isolation, only for edge cases in advanced labs

Validation Architecture

This section defines validation/testing approach for Phase 2 based on TDD methodology and project requirements.

Test Framework

Property Value
Framework BASH (Bourne Again Shell) >= 4.0
Config file None — inline test functions
Quick run command bash labs/lab-01-iam/tests/quick-test.sh
Full suite command bash labs/lab-01-iam/tests/run-all-tests.sh

Phase Requirements → Test Map

Req ID Behavior Test Type Automated Command File Exists?
LAB-01 Studente può configurare utenti Linux, gruppi e permessi per accesso Docker socket integration bash tests/test-01-user-creation.sh Wave 0
DOCT-01 Lab include Tutorial (guida passo-passo) manual Verify file exists: tutorial/01-create-users.md Wave 0
DOCT-02 Lab include How-to Guides manual Verify files exist: how-to-guides/*.md Wave 0
DOCT-03 Lab include Reference manual Verify file exists: reference/docker-socket-permissions.md Wave 0
DOCT-04 Lab include Explanation (parallelismo Docker ↔ cloud) manual Verify file exists: explanation/docker-iam-parallels.md Wave 0
DOCT-05 Tutorial segue principio "little often" manual Review tutorial for incremental steps Wave 0
TEST-01 Script di test bash pre-implementazione (TDI) unit bash tests/02-docker-access-test.sh Wave 0
TEST-05 Comando di verifica finale ("double check") integration bash tests/99-final-verification.sh Wave 0
INF-01 Nessun container gira come utente root unit bash tests/03-non-root-test.sh Wave 0
PARA-01 Componente Docker mappato a servizio cloud (IAM Users) manual Verify Explanation document includes mapping table Wave 0
PARA-03 Differenze tra locale e cloud documentate manual Verify Explanation includes differences section Wave 0
PARA-04 Comandi Docker equivalenti a comandi cloud mostrati manual Verify Reference includes command comparison Wave 0

Sampling Rate

  • Per task commit: bash labs/lab-01-iam/tests/quick-test.sh (runs in < 30 seconds)
  • Per wave merge: bash labs/lab-01-iam/tests/run-all-tests.sh (full validation)
  • Phase gate: Full suite green + manual verification of all 4 Diátaxis documents + INF-01 verified

Wave 0 Gaps

  • labs/lab-01-iam/tests/01-user-creation-test.sh — tests user/group creation and Docker socket access
  • labs/lab-01-iam/tests/02-non-root-test.sh — verifies INF-01: no container runs as root
  • labs/lab-01-iam/tests/99-final-verification.sh — double check command for students
  • labs/lab-01-iam/tutorial/01-create-users.md — first Diátaxis tutorial
  • labs/lab-01-iam/how-to-guides/ — directory for goal-oriented guides
  • labs/lab-01-iam/reference/ — directory for technical specifications
  • labs/lab-01-iam/explanation/docker-iam-parallels.md — IAM parallelism explanation
  • Test harness setup: None needed — using pure BASH

Success Criteria Validation

Success Criteria 1: Studente può creare utenti Linux con permessi limitati per accesso Docker socket

  • How to verify: Test script creates user, verifies NOT in docker group, confirms docker ps fails, adds to docker group, confirms docker ps succeeds
  • Test command: bash tests/01-user-creation-test.sh
  • Manual check: Student follows Tutorial and demonstrates working Docker access

Success Criteria 2: Studente comprende il parallelismo tra utenti Linux/permessi Docker e IAM Users/Roles in cloud

  • How to verify: Explanation document includes mapping table comparing Linux concepts to AWS IAM
  • Manual check: Review explanation/docker-iam-parallels.md for explicit parallels
  • Test command: None — conceptual understanding verified through documentation quality

Success Criteria 3: Nessun container gira come root (principio minimo privilegio verificato)

  • How to verify: Automated test checks docker exec <container> whoami returns non-root
  • Test command: bash tests/02-non-root-test.sh
  • Manual check: docker inspect shows User field set, docker-compose.yml has user: directive

Success Criteria 4: Lab include Tutorial, How-to Guides, Reference, Explanation (Diátaxis completo)

  • How to verify: File structure check confirms all 4 document types exist
  • Manual check: Review each document for Diátaxis compliance
  • Test command: find labs/lab-01-iam -name "*.md" | grep -E "(tutorial|how-to|reference|explanation)"

Success Criteria 5: Studente può eseguire comando di verifica finale ("double check")

  • How to verify: Final verification script runs all checks and produces PASS/FAIL report
  • Test command: bash tests/99-final-verification.sh
  • Manual check: Student runs script and sees all tests passing

TDI Methodology Verification

RED Phase (Pre-Implementation):

  • Test scripts are written BEFORE docker-compose.yml or Dockerfiles
  • Tests explicitly fail when run against non-existent infrastructure
  • Example: test_01-user-creation-test.sh checks for users that don't exist yet

GREEN Phase (Implementation):

  • Minimum infrastructure created to make tests pass
  • docker-compose.yml includes user: directive for all services
  • Test execution produces all PASS results

REFACTOR Phase (Optimization):

  • Test coverage remains 100% after optimizations
  • Documentation improvements don't break existing tests
  • Security enhancements (e.g., user namespaces) are tested before deployment

INF-01 Verification (No Root Containers)

Automated Verification:

# Test runs for every container defined in docker-compose.yml
for service in $(docker-compose ps --services); do
    container_name=$(docker-compose ps -q $service)
    actual_user=$(docker exec $container_name whoami 2>/dev/null)
    if [ "$actual_user" = "root" ]; then
        echo "FAIL: $service running as root"
        exit 1
    fi
done
echo "PASS: All containers running as non-root"

Manual Verification:

  1. Check docker-compose.yml for user: directive on all services
  2. Run docker-compose ps to get container names
  3. Run docker top <container> and verify USER column != root
  4. Run docker inspect <container> and verify Config.User is set

Continuous Verification:

  • Quick test runs on every commit during development
  • Full test suite runs before merging lab branch to main
  • Phase gate requires 100% PASS rate for all tests

Open Questions

  1. Should we teach rootless Docker in Lab 1?

    • What we know: Rootless Docker is more secure but adds complexity (uidmap, slirp4netns, etc.)
    • What's unclear: Is it too advanced for first lab?
    • Recommendation: Teach standard docker group model in Lab 1, mention rootless as "advanced topic" in Explanation
  2. How to handle the "newgrp" limitation in automated tests?

    • What we know: Group membership requires re-login to take effect
    • What's unclear: Best practice for automated testing without interactive login
    • Recommendation: Test group membership with groups command, not actual Docker access, or use sg docker -c "docker ps"
  3. What UID/GID should we use for non-root containers?

    • What we know: Common practice is 1000:1000, but may conflict with host users
    • What's unclear: Should we use specific UIDs to avoid conflicts?
    • Recommendation: Use 1000:1000 for simplicity, document potential conflicts in troubleshooting guide

Sources

Primary (HIGH confidence)

Secondary (MEDIUM confidence)

  • Docker Compose Documentation - https://docs.docker.com/compose/ - user directive, service configuration
  • Linux user management (useradd, usermod) - Standard POSIX utilities

Tertiary (LOW confidence)

  • None - all findings verified with official documentation

Metadata

Confidence breakdown:

  • Standard stack: HIGH - Docker and Linux utilities are project-wide standards
  • Architecture: HIGH - Based on official Docker security documentation
  • Pitfalls: HIGH - Common issues verified through Docker documentation and best practices

Research date: 2026-03-24 Valid until: 2026-04-23 (30 days - Docker security model is stable)