Lab: Secure container defaults
Short hands-on defaults: small bases, non-root, capability drop, and secrets handling. CVE scanning and SBOM workflows live in Image Audit and Supply Chain.
Lab objective
- Compare Alpine and Ubuntu image sizes on disk.
- Contrast a container running as root versus non-root in the image.
- Try
--cap-drop=ALLand see that many privileged actions stop working. - Prefer runtime secret delivery over baking credentials into the image.
Hands on Lab
Compare base image sizes
docker pull ubuntu:latest
docker images ubuntu:latest
## ====##
docker pull alpine:latest
docker images alpine:latest
Smaller bases reduce install surface. You still patch, scan, and track what is inside.
Run as root (baseline)
cat > Dockerfile.root-baseline <<'EOF'
FROM alpine:latest
CMD ["sh"]
EOF
docker build -f Dockerfile.root-baseline -t peachycloudsecurity-userdemo:root .
docker run --rm peachycloudsecurity-userdemo:root id
Expect uid=0. Long-lived services should not rely on this.
Run as non-root in the image
cat > Dockerfile.nonroot <<'EOF'
FROM alpine:latest
RUN adduser -D peachycloudsecurity-user
USER peachycloudsecurity-user
CMD ["sh"]
EOF
docker build -f Dockerfile.nonroot -t peachycloudsecurity-userdemo:nonroot .
docker run --rm peachycloudsecurity-userdemo:nonroot id
Expect a non-zero uid.
Drop all capabilities
docker run --rm -it --cap-drop=ALL alpine sh
- Run this script inside container.
cat <<'EOF' > raw_test.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip_icmp.h>
int main() {
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sock < 0) {
perror("socket");
return 1;
}
printf("Raw socket created\n");
return 0;
}
EOF
apk add --no-cache gcc musl-dev >/dev/null
gcc raw_test.c -o raw_test
./raw_test
For secrets dont use hardcoded secret as it can be extracted via image layers.
Clean up
docker rmi peachycloudsecurity-userdemo:root peachycloudsecurity-userdemo:nonroot 2>/dev/null || true
rm -f Dockerfile.root-baseline Dockerfile.nonroot
Summary
- Prefer small, maintained bases and still patch and scan them (Lab: Trivy image scan).
- Run as non-root in the image when the application allows it.
- Start from
--cap-drop=ALLand add capabilities only when required. - Keep secrets out of image layers and build-time environment for real deployments.
- For SBOM generation and scanning that SBOM, see Lab: SBOM with Syft and Grype.