dotnet-docker
dotnet-docker copied to clipboard
Include documentation and samples that demonstrate USER best practices
The Dockerfile best practices suggest services should be run with a non-root user. The current documentation and samples do not discuss or show the Dockerfile best practices around USER. They should be updated to illustrate the best practices.
My PR #3139 about changing defaults to Dockerfiles didn't reached consensus so I'm sharing examples how to handle this with different container orchestration tools.
These examples do show how to run ASP.NET Sample App with as tight security hardening as possible without breaking the application which means that:
- they are compliant with Pod Security Standard == Restricted
- they use read only root file system in containers like suggested on NSA: Kubernetes Hardening Guide
- because of that there is also additional 100M tmpfs mouted to /tmp as ASP.NET need to be able to write to that path.
- ASP.NET is configured to use listen port 8080 instead of 80 because not all environments allow <=1024 to listened by non-root.
Examples
Local Docker
docker run \
--user 65534:65534 \
--cap-drop ALL \
--read-only \
--env ASPNETCORE_URLS=http://+:8080 \
--publish 8080:8080 \
--mount type=tmpfs,tmpfs-size=100M,destination=/tmp \
mcr.microsoft.com/dotnet/samples:aspnetapp
Docker Swarm
version: "3.8"
services:
aspnetapp:
image: mcr.microsoft.com/dotnet/samples:aspnetapp
user: "65534:65534"
cap_drop:
- ALL
read_only: true
environment:
- ASPNETCORE_URLS=http://+:8080
ports:
- target: 8080
published: 8080
volumes:
- type: tmpfs
target: /tmp
tmpfs:
size: 104857600
Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: aspnetapp
spec:
selector:
matchLabels:
app.kubernetes.io/name: aspnetapp
template:
metadata:
labels:
app.kubernetes.io/name: aspnetapp
spec:
automountServiceAccountToken: false
securityContext:
fsGroup: 65534
runAsGroup: 65534
runAsNonRoot: true
runAsUser: 65534
containers:
- name: aspnetapp
image: mcr.microsoft.com/dotnet/samples:aspnetapp
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsGroup: 65534
runAsNonRoot: true
runAsUser: 65534
seccompProfile:
type: RuntimeDefault
env:
- name: ASPNETCORE_URLS
value: http://+:8080
ports:
- containerPort: 8080
protocol: TCP
volumeMounts:
- name: tmpfs
mountPath: /tmp
volumes:
- name: tmpfs
emptyDir:
sizeLimit: 100Mi
Nomad
job "aspnetapp" {
datacenters = ["dc1"]
type = "service"
group "web" {
network {
port "http" {
to = 8080
}
}
task "aspnetapp" {
driver = "docker"
user = "nobody"
env {
ASPNETCORE_URLS = "http://+:8080"
}
config {
image = "mcr.microsoft.com/dotnet/samples:aspnetapp"
cap_drop = ["ALL"]
readonly_rootfs = true
ports = ["http"]
mount {
type = "tmpfs"
target = "/tmp"
readonly = false
tmpfs_options {
size = 104857600
}
}
}
}
}
}
Feel free to copy those to other documentations.
In additionally one nice way to handle this would be include those with proper comments to those examples which developers can generate with Visual Studio. Then it shouldn't be too hard for them also loosen up those where ever needed.
https://github.com/dotnet/dotnet-docker/issues/3988 goes into more depth of the implications of running as non-root, particularly around the port usage.
We do have this existing blog post which describes the best practice: https://devblogs.microsoft.com/dotnet/securing-containers-with-rootless/
It's great to have the images to be able to run rootless and the examples in the Blogpost hel a lot. It would be great to also include examples of how to enable https in rootless containers though. I'm running into issues where the app user isn't allowed to access the certificate and similar issues.
[Triage] I would consider this issue as complete since we have non-root users as default in .NET 8 images, with documentation about using non-root users in our distroless documentation. There's also lots of great information in @richlander's blog post, Secure your .NET cloud apps with rootless Linux Containers.
Any other problems encountered with non-root users should be filed as separate issues (@Addisco).