关注我们
(本文阅读时间:18分钟)
.NET SDK 的内置容器支持:https://devblogs.microsoft.com/dotnet/announcing-builtin-container-support-for-the-dotnet-sdk/
最小特权
浅识 app
$ docker run --rm mcr.microsoft.com/dotnet/aspnet:8.0-preview cat /etc/passwd | tail -n 1
app:x:64198:64198::/home/app:/bin/sh
"cd && pwd" docker run --rm -u app mcr.microsoft.com/dotnet/aspnet:8.0-preview bash -c
/home/app
$ docker run --rm node cat /etc/passwd | tail -n 1
node:x:1000:1000::/home/node:/bin/bash
$ docker run ubuntu:lunar cat /etc/passwd | tail -n 1
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
$ cat out/layers/ruby/etc/passwd | tail -n 1
nonroot:x:65532:65532:Account created by apko:/home/nonroot:/bin/sh
使用 app
-u
docker run --rm -u app mcr.microsoft.com/dotnet/runtime-deps:8.0-preview whoami
app
USER app
USER 64198
USER $APP_UID
切换到端口8080
$ docker run --rm mcr.microsoft.com/dotnet/aspnet:8.0-preview bash -c "export | grep ASPNETCORE"
declare -x ASPNETCORE_HTTP_PORTS="8080"
$ docker run --rm mcr.microsoft.com/dotnet/aspnet:7.0 bash -c "export | grep ASPNETCORE"
declare -x ASPNETCORE_URLS="http://+:80"
docker run --rm -it -p 8080:8080 aspnetapp
ENV ASPNETCORE_HTTP_PORTS=80
docker run --rm -e ASPNETCORE_HTTP_PORTS=80 -p 8000:80 aspnetapp
>docker run --rm mcr.microsoft.com/dotnet/aspnet:8.0-preview-nanoserver-ltsc2022 cmd /c "set | findstr ASPNETCORE"
ASPNETCORE_HTTP_PORTS=8080
Non-root 运用
pwd
/home/rich/git/dotnet-docker/samples/aspnetapp
cat Dockerfile.alpine-non-root | tail -n 2
USER app
ENTRYPOINT ["./aspnetapp"]
docker build --pull -t aspnetapp -f Dockerfile.alpine-non-root .
$ docker run --rm -d -p 8000:8080 aspnetapp
5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad
$ curl http://localhost:8000/Environment
{"runtimeVersion":".NET 8.0.0-preview.2.23128.3","osVersion":"Linux 5.15.90.1-microsoft-standard-WSL2 #1 SMP Fri Jan 27 02:56:13 UTC 2023","osArchitecture":"X64","user":"app","processorCount":16,"totalAvailableMemoryBytes":67429986304,"memoryLimit":9223372036854771712,"memoryUsage":30220288}
$ docker exec 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad ls -l
total 188
-rw-r--r-- 1 root root 127 Jan 20 17:14 appsettings.Development.json
-rw-r--r-- 1 root root 151 Oct 19 21:59 appsettings.json
-rwxr-xr-x 1 root root 78320 Mar 16 16:51 aspnetapp
-rw-r--r-- 1 root root 463 Mar 16 16:51 aspnetapp.deps.json
-rw-r--r-- 1 root root 51200 Mar 16 16:51 aspnetapp.dll
-rw-r--r-- 1 root root 35316 Mar 16 16:51 aspnetapp.pdb
-rw-r--r-- 1 root root 469 Mar 16 16:51 aspnetapp.runtimeconfig.json
drwxr-xr-x 5 root root 4096 Mar 16 16:51 wwwroot
$ docker exec 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad ps
PID USER TIME COMMAND
1 app 0:00 ./aspnetapp
53 app 0:00 ps
参考 Dockerfile:
所有新的文件和目录都是以 UID 和 GID 为0创建的,除非可选的 -chown 标志指定一个给定的用户名、组名或 UID/GID 组合,以要求对复制的内容拥有特定的所有权。
exec 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad rm aspnetapp.pdb docker
rm: can't remove 'aspnetapp.pdb': Permission denied
exec 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad touch /file docker
touch: /file: Permission denied
exec 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad which dotnet docker
/usr/bin/dotnet
exec 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad rm /usr/bin/dotnet docker
rm: can't remove '/usr/bin/dotnet': Permission denied
exec 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad apk add curl docker
ERROR: Unable to lock database: Permission denied
ERROR: Failed to open apk database: Permission denied
$ docker exec -u root 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad ash -c "rm aspnetapp.pdb && ls aspnetapp.pdb"
ls: aspnetapp.pdb: No such file or directory
$ docker exec -u root 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad ash -c "touch /file && ls /file"
/file
$ docker exec -u root 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad ash -c "rm /usr/bin/dotnet && ls /usr/bin/dotnet"
ls: /usr/bin/dotnet: No such file or directory
$ docker exec -u root 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad apk add curl
fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/community/x86_64/APKINDEX.tar.gz
(1/4) Installing brotli-libs (1.0.9-r9)
(2/4) Installing nghttp2-libs (1.51.0-r0)
(3/4) Installing libcurl (7.87.0-r2)
(4/4) Installing curl (7.87.0-r2)
Executing busybox-1.35.0-r29.trigger
OK: 14 MiB in 28 packages
$ docker exec 5bde77feebdf76ff370815f41a8989a880d51a4037c91e2ac8c6f2c269b759ad sudo
OCI runtime exec failed: exec failed: unable to start container process: exec: "sudo": executable file not found in $PATH: unknown
在 Azure 容器服务中托管
Azure 应用服务要求 WEBSITES_PORT 使用80端口以外的端口。它可以通过 CLI 或在门户中设置。 Azure 容器应用允许在创建资源的过程中更改端口。 Azure 容器实例允许在创建资源的过程中更改端口。
后续步骤
我们 .NET 团队使命的一个关键部分是纵深防御。每个人都需要考虑安全问题,然而,我们的业务是通过单一的变化或功能来关闭整个攻击类别。大约十年前我们刚开始发布容器映像时,就可以做出这种改变。许多年来,我们一直被要求提供 non-root 指导和 non-root 容器映像。老实说,我们并不清楚该如何处理这个问题,很大程度上是因为我们现在使用的模式在我们刚开始的时候并不存在。在安全容器托管方面,没有一个领导者可以让我们学习。正是与 Canonical 在 chiseled 镜像方面的合作经验,使我们发现并形成了这种方法。