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
Recommended Project Structure
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
--privilegedflag: 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
--privilegedflag: 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 accesslabs/lab-01-iam/tests/02-non-root-test.sh— verifies INF-01: no container runs as rootlabs/lab-01-iam/tests/99-final-verification.sh— double check command for studentslabs/lab-01-iam/tutorial/01-create-users.md— first Diátaxis tutoriallabs/lab-01-iam/how-to-guides/— directory for goal-oriented guideslabs/lab-01-iam/reference/— directory for technical specificationslabs/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 psfails, adds to docker group, confirmsdocker pssucceeds - 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.mdfor 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> whoamireturns non-root - Test command:
bash tests/02-non-root-test.sh - Manual check:
docker inspectshows User field set, docker-compose.yml hasuser: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.shchecks 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:
- Check docker-compose.yml for
user:directive on all services - Run
docker-compose psto get container names - Run
docker top <container>and verify USER column != root - 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
-
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
-
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
groupscommand, not actual Docker access, or usesg docker -c "docker ps"
-
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)
- Docker Engine Security Documentation - https://docs.docker.com/engine/security/ - Namespaces, control groups, daemon attack surface, capabilities
- Rootless Docker Documentation - https://docs.docker.com/engine/security/rootless/ - Installation, user namespaces, limitations
- AWS IAM Introduction - https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html - Identities, policies, authentication vs authorization
Secondary (MEDIUM confidence)
- Docker Compose Documentation - https://docs.docker.com/compose/ -
userdirective, 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)