dotnet-docker icon indicating copy to clipboard operation
dotnet-docker copied to clipboard

Include documentation and samples that demonstrate USER best practices

Open MichaelSimons opened this issue 4 years ago • 4 comments

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.

MichaelSimons avatar Mar 26 '20 15:03 MichaelSimons

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.

olljanat avatar Jul 27 '22 09:07 olljanat

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.

mthalman avatar Oct 19 '22 18:10 mthalman

We do have this existing blog post which describes the best practice: https://devblogs.microsoft.com/dotnet/securing-containers-with-rootless/

mthalman avatar Aug 16 '23 18:08 mthalman

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.

Addisco avatar Jun 22 '24 05:06 Addisco

[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).

lbussell avatar Jul 29 '24 18:07 lbussell