Introduction
Container images are fundamental building blocks of modern application deployment, but they can introduce significant security risks if not properly configured and secured. This guide explores 10 common vulnerabilities in container image building and deployment, along with practical solutions and examples.
1. Running Containers as Root
Vulnerability
Running containers with root privileges gives excessive permissions that could be exploited if the container is compromised.
Example
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Solution
Create a non-root user and switch to it:
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y nginx
# Create non-root user
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
RUN chown -R appuser:appgroup /var/www/html /var/log/nginx
USER appuser
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
2. Using Latest Tags
Vulnerability
Using the :latest
tag can lead to unexpected behavior and security issues as the base image could change without notice.
Example
FROM node:latest
COPY . /app
Solution
Use specific version tags:
FROM node:16.14.2-slim
COPY . /app
3. Sensitive Data in Build Context
Vulnerability
Including sensitive files in the build context can expose them in the image layers.
Example
COPY . /app
RUN npm install
Solution
Use .dockerignore
to exclude sensitive files:
.env
*.key
*.pem
node_modules
.git
4. Outdated Base Images
Vulnerability
Using outdated base images with known vulnerabilities.
Example
FROM debian:stretch
RUN apt-get update && apt-get install -y python
Solution
Use up-to-date base images and implement regular scanning:
FROM debian:bullseye-slim
RUN apt-get update && apt-get upgrade -y && \
apt-get install -y python3
5. Unnecessary Packages
Vulnerability
Including unnecessary packages increases the attack surface.
Example
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y \
build-essential \
python3 \
vim \
curl \
wget
Solution
Use minimal base images and only install required packages:
FROM python:3.9-slim
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
6. Insecure Package Sources
Vulnerability
Using untrusted or insecure package sources can introduce malicious code.
Example
RUN curl -k https://untrusted-source.com/package.sh | bash
Solution
Verify package signatures and use secure sources:
# Add GPG key and verify package
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
RUN echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu focal stable" > /etc/apt/sources.list.d/docker.list
7. Exposed Secrets in Environment Variables
Vulnerability
Hardcoding secrets in Dockerfile ENV instructions exposes them in image history.
Example
ENV AWS_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE
ENV AWS_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Solution
Use build arguments or runtime environment variables:
ARG AWS_ACCESS_KEY
ARG AWS_SECRET_KEY
RUN aws configure set aws_access_key_id $AWS_ACCESS_KEY && \
aws configure set aws_secret_access_key $AWS_SECRET_KEY
8. Insecure File Permissions
Vulnerability
Incorrect file permissions can allow unauthorized access to sensitive data.
Example
COPY app.config /etc/app/
RUN chmod 777 /etc/app/app.config
Solution
Set appropriate permissions:
COPY app.config /etc/app/
RUN chown appuser:appgroup /etc/app/app.config && \
chmod 600 /etc/app/app.config
9. Missing Health Checks
Vulnerability
Without health checks, unhealthy containers might continue running.
Example
FROM nginx:alpine
EXPOSE 80
Solution
Implement health checks:
FROM nginx:alpine
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost/ || exit 1
10. Unencrypted Communications
Vulnerability
Using unencrypted protocols for sensitive communications.
Example
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Solution
Configure SSL/TLS:
COPY ssl/cert.pem /etc/nginx/ssl/
COPY ssl/key.pem /etc/nginx/ssl/
COPY nginx-ssl.conf /etc/nginx/conf.d/default.conf
EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]
Best Practices for Deployment
- Always scan images before deployment:
# Using Trivy scanner
trivy image your-image:tag
- Implement runtime security policies:
# Example SecurityContext in Kubernetes
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
containers:
- name: app
image: your-secure-image:tag
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
- Use multi-stage builds to reduce final image size:
# Build stage
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Production stage
FROM node:16-slim
COPY --from=builder /app/dist /app
USER node
CMD ["node", "app/server.js"]
Conclusion
Securing container images requires attention to detail and following security best practices throughout the build and deployment process. Regular scanning, updates, and security audits are essential to maintain a strong security posture.
Remember to:
- Regularly update base images and dependencies
- Implement least privilege principles
- Use multi-stage builds
- Scan images for vulnerabilities
- Implement runtime security controls
- Monitor containers in production
Top comments (0)