docker基本安全运行配置

24 / 100 SEO Score

安装docker

docker官方文档中写的很清楚:https://docs.docker.com/engine/install/

根据操作系统自行选择安装方式。

全篇以ubuntu 24.04为例

#卸载自带的冲突包。
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1)

使用apt安装

设置Docker的apt仓库

# 添加docker的官方GPG密钥
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# 添加apt软件源
#从下面开始直到EOF全部一次性复制。
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF

#更新apt缓存
sudo apt update

#安装docker engine
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

docker基本安全配置

基本安全有以下几点:

  • 使用获得了sudo权限的普通用户运行docker。
  • docker容器内进程运行时指定以当前的普通用户执行(注意权限问题)。
  • 配置文件设置只读权限。
  • 端口映射到127.0.0.1。无法直接被外网访问,可通过ufw进行管理。
  • 限制内存使用。

创建一个普通用户

#创建一个名为docrun的普通用户
useradd -m -s /bin/bash docrun
#设置密码
passwd docrun
#加入sudo用户组。
usermod -aG sudo docrun

加入docker用户组(不要进行此操作)

官方文档中对此操作有着明确警告https://docs.docker.com/engine/install/linux-postinstall

#除非你明确了解自己在干什么,否则不要执行此操作
#检查 Docker 用户组是否存在
sudo groupadd docker

#若不存在则创建
sudo groupadd docker

#将用户加入docker用户组
sudo usermod -aG docker docrun


创建或修改 /etc/docker/daemon.json 文件

vi /etc/docker/daemon.json
#写入以下配置
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "20m",
    "max-file": "3"
  },
  "live-restore": true,
  "userland-proxy": false
}
  • log-driver:指定 Docker 的默认日志驱动程序为 json-file。将容器的 stdout 和 stderr 输出以 JSON 格式输出。(路径/var/lib/docker/containers/container-id/container-id-json.log
  • log-opts:日志设置,max-size 20m 每个容器的日志文件最大为20MB,之后新建日志文件。max-file 3 日志文件最多为3个。超过时循环旧文件。
  • live-restore:值为true时启用 live restore 功能,也就是升级、重启docker。。。。时,正在运行的容器不会停止。
  • userland-proxy:值为false时禁用 Docker 的用户空间代理,性能会稍微好一点。若想使用自定义IPv6网桥时删除这一项。否则IPv6网桥不可用。

保存退出。应用配置。

sudo systemctl daemon-reload
sudo systemctl restart docker

切换用户,退出当前shell。重新用新建的docrun用户登录

运行容器

映射的目录提前由docrun用户创建好,否则可能会出现权限管理混乱。

由于docker会在ufw上打洞,所以端口映射时不要直接映射端口号。而是把容器内的端口号映射到127.0.0.1:xx之后通过安装在宿主机上的nginx反代。如果nginx也要安装在docker中,不要这么操作。

以nginx镜像(非 Root版本)为例。本例只演示镜像运行的用户权限。


sudo docker run -d \
  --name my-nginx \
  --restart unless-stopped \
  --user $(id -u):$(id -g) \
  -p 127.0.0.1:8080:8080 \
  -v $(pwd)/html:/usr/share/nginx/html:ro \
  --memory="100m" \
  nginxinc/nginx-unprivileged:alpine
  • docker run -d :创建并启动一个新容器,-d在后台运行。
  • –name :给容器命名为 my-nginx
  • –restart :容器重启策略,unless-stopped表示主机重启时容器自动启动。可手动关闭容器。
  • –user $(id -u):$(id -g) :以宿主机当前的用户身份运行。$(id -u) ,获取当前用户的用户 ID,$(id -g) ,获取当前用户组 ID。但对容器内强制以root运行的进程无效。不要在nginx这类需要root权限的镜像中添加这类命令,会导致容器无限重启。
  • -p :端口绑定宿主机的127.0.0.1:8080绑定到容器内的80端口。防止docker在ufw上打洞。但这样外网无法直接访问。
  • -v :挂载卷。$(pwd),当前目录。/usr/share/nginx/html,容器内nginx默认网站root目录。:ro,容器只能读取这个目录,不能修改。
  • –memory=”100m” : 限制容器最多使用100MB内存。
  • nginx:alpine:镜像名和标签

查看容器运行状态

#查看容器中镜像运行状态
sudo docker exec my-nginx ps aux

#查看宿主机容器运行状态
sudo docker top my-nginx
#或者
ps aux | grep nginx

可以看到除了nginx的uid,为当前用户的uid。


docker升级版安全配置

配置文件中加入"userns-remap": "default"。别的没有太大差别。

"userns-remap": "default"会把容器内的root用户(UID 0)映射为宿主机的非特权用户(例如UID 100000),但挂载目录时非常麻烦。目录的权限是个坑。有些需要 –privileged 或特殊权限的容器可能无法正常工作。

修改配置文件

vi /etc/docker/daemon.json
#写入以下配置。
#顺便再加入IPv6内网支持和exec-opts
{
    "exec-opts": ["native.cgroupdriver=systemd"], 
    "log-driver": "json-file",
    "log-opts": {
      "max-size": "20m",
      "max-file": "3"
  },
   "live-restore": true,
   "ipv6": true,
   "ip6tables": true,
   "userns-remap": "default"
}
  • exec-opts:统一管理入口为systemd。Ubuntu或debain尽量添加此配置。
  • ipv6: 启动 IPv6。
  • fixed-cidr-v6:配置本地地址
  • ip6tables:开启 IPv6 防火墙规则管理
  • userns-remap:用户命名空间重映射

保存退出。应用配置。

sudo systemctl daemon-reload
sudo systemctl restart docker

#确认基准UID
cat /etc/subuid
cat /etc/subgid

图中新创建的dockremap:100000:65536便是”userns-remap”: “default”模式下docker的UID范围。100000为起始UID。同时也是root的UID。65536为UID数量。

创建ipv6网桥

#创建名为my_ipv6_net的IPv6网桥
sudo docker network create \
  --driver bridge \
  --ipv6 \
  --subnet=fd00:1:2:3::/64 \
  my_ipv6_net

#检查当前的网络状态
sudo docker network ls

可以看到名为my_ipv6_net的网络已经创建成功。

运行容器


#运行容器
sudo docker run -d \
  --name my-nginx \
  --network my_ipv6_net \
  --restart unless-stopped \
  --user 1000:1000 \
  -p 127.0.0.1:80:80 \
  -p 127.0.0.1:443:443 \
  -p [::1]:80:80  \
  -p [::1]:443:443  \
  -v $(pwd)/html:/usr/share/nginx/html:ro \
  --memory="100m" \
  nginx:alpine

之后查看docker容器的PID。

#查看容器本身的UID
sudo ps aux | grep nginx
#查看容器内进程的UID
sudo docker exec my-nginx ps aux

此次并没有映射文件。nginx本身没有需要读取的文件,所以不会报错。若挂载了需要读取的文件,会因为权限问题无法运行。使用ACL解决。

添加挂载文件读取权限

上一步已经明白了docker nginx容器的UID为100101。

准备映射的目录

#目录放在一个名为dockerun用户的家目录中。
#进入目录
cd /home/dockerun/

#创建名为nginx的目录
mkdir nginx
#创建名为conf.d的目录
mkdir nginx/conf.d
#创建名为log的目录
mkdir nginx/log
#创建名为html的目录
mkdir nginx/html

创建nginx配置文件

vi /home/dockerun/nginx/nginx.conf
#写入以下内容

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

#保存退出

#继续创建nginx配置文件
vi /home/dockerun/nginx/conf.d/default.conf
#写入以下内容
server {
    listen       80;
    listen       [::]:80;

    server_name  localhost;

    root   /usr/share/nginx/html;
    index  index.html index.htm;

    location / {
        try_files $uri $uri/ /index.html;
    }
    access_log /var/log/nginx/access.log main;
    error_log  /var/log/nginx/error.log warn;


}
#保存退出

接下来若直接执行sudo docker run…….,日志中会提示权限问题,导致nginx无限重启

#查看日志
sudo docker logs my-nginx

nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied)

使用ACL赋予nginx目录权限

严格来说,应该以最小权限为原则。但是实在懒的一个一个配置。索性整个目录都配置上权限。

nginx运行时会分别使用root和普通user,所以要把root的100000和普通user的100101都配置上。

#赋予容器内user用户的读写执行权。
sudo setfacl -R -m u:100101:rwx /home/dockerun/nginx
sudo setfacl -R -m d:u:100101:rwx /home/dockerun/nginx
#赋予容器内root用户的读写执行权。
sudo setfacl -R -m u:100000:rwx /home/dockerun/nginx
sudo setfacl -R -m d:u:100000:rwx /home/dockerun/nginx

#检查权限
getfacl /home/dockerun/nginx

可以看到user:100000:rwx user:100101:rwx,表示UID为100000和100101的用户对nginx目录有着读写执行(rwx)的权限。

运行容器

sudo docker run -d \
  --name my-nginx \
  --network my_ipv6_net \
  --restart unless-stopped \
  -p 127.0.0.1:80:80 \
  -p 127.0.0.1:443:443 \
  -p [::1]:80:80 \
  -p [::1]:443:443 \
  -v /home/dockerun/nginx/html:/usr/share/nginx/html:ro \
  -v /home/dockerun/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
  -v /home/dockerun/nginx/conf.d:/etc/nginx/conf.d:ro \
  -v /home/dockerun/nginx/log:/var/log/nginx \
  --memory="100m" \
  nginx:alpine

检查运行状态

#这回不再报错了
sudo docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED         STATUS         PORTS                                                                                NAMES
c6695a1db925   nginx:alpine   "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes   127.0.0.1:80->80/tcp, [::1]:80->80/tcp, 127.0.0.1:443->443/tcp, [::1]:443->443/tcp   my-nginx

#测试IPv4端口映射
#403是因为nginx的网站root目录本身就是空的。
dockerun@Ubuntutest:~$ curl "http://127.0.0.1:80"
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.29.4</center>
</body>
</html>

#测试IPv6端口映射
dockerun@Ubuntutest:~$ curl "http://[::1]:80"
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.29.4</center>
</body>
</html>

配置完成。

另外,设置了”userns-remap”: “default”后会对部分管理docker的容器造成麻烦。此时可用命令(--userns=host)强制对某个容器单独禁用命名空间重映射。

#此处以portainer-ce为例

docker volume create portainer_data

docker run -d \
  -p 8000:8000 \
  -p 9443:9443 \
  --name portainer \
  --restart=always \
  --userns=host \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:lts

rootless模式

先决条件

rootless模式是官方最为推荐的运行模式,完全不需要root权限。但也正因为如此,存在很多限制。例如不能使用低于1024的端口号等。详情参阅官方文档:https://docs.docker.com/engine/security/rootless/以及第三方文档https://rootlesscontaine.rs/getting-started/

已安装docker

首先创建一个新用户,这个用户运行docker时没必要赋予sudo权限。但配置环境时仍然需要sudo。

#创建一个名为rootlesstest的用户,用户名可随意指定
useradd -m -s /bin/bash rootlesstest

#设置密码
passwd rootlesstest

安装必要的依赖。

sudo apt update
sudo apt install uidmap
sudo apt install -y dbus-user-session

确认用户命名空间范围。

切换到新注册的用户。

#切换用户
su - rootlesstest

#查看用户UID。
id -u
#会显示1002。不同用户,UID会不同。
1002

#产看当前用户名。
whoami
#会显示当前的用户名。
rootlesstest

#查看当前用户的UID,GID起始编号和范围。
#确保用户至少有65536个ID。
grep ^$(whoami): /etc/subuid
rootless:231072:65536

grep ^$(whoami): /etc/subgid
rootless:231072:65536

如果原版docker已经运行,可以考虑禁用它

sudo systemctl disable --now docker.service docker.socket
sudo rm /var/run/docker.sock

安装docker rootless

因为已经用apt安装了docker。docker中本身包含了安装脚本。直接运行脚本即可。

无systemctl模式

注意!如果使用su切换到rootlesstest用户运行脚本,会导致安装后没有systemctl。此时可用手动配置环境即可。


#运行此脚本
dockerd-rootless-setuptool.sh install

#如果脚本不存在,需要手动安装
sudo apt-get install -y docker-ce-rootless-extras

#之后脚本会提示
rootlesstest@Ubuntutest:~$ dockerd-rootless-setuptool.sh install
[INFO] systemd not detected, dockerd-rootless.sh needs to be started manually:

PATH=/usr/bin:/sbin:/usr/sbin:$PATH dockerd-rootless.sh

[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Using CLI context "rootless"
Current context is now "rootless"

[INFO] Make sure the following environment variable(s) are set (or add them to ~/.bashrc):
# WARNING: systemd not found. You have to remove XDG_RUNTIME_DIR manually on every logout.
export XDG_RUNTIME_DIR=/home/rootlesstest/.docker/run
export PATH=/usr/bin:$PATH

[INFO] Some applications may require the following environment variable too:
export DOCKER_HOST=unix:///home/rootlesstest/.docker/run/docker.sock

由于rootlesstest是用su切换的用户,没有systemctl,所以根据提示,添加环境变量,启动docker。由于是手动配置环境变量,重启,或重新登录后仍然需要配置,所以还要进行持久化配置。

首先测试docker rootless模式运行。

设置环境变量

export XDG_RUNTIME_DIR=/home/rootlesstest/.docker/run
export PATH=/usr/bin:$PATH
export DOCKER_HOST=unix:///home/rootlesstest/.docker/run/docker.sock

测试docker

#直接启动,启动后各种日志信息会显示在终端。
PATH=/usr/bin:/sbin:/usr/sbin:$PATH dockerd-rootless.sh

#在后台启动
PATH=/usr/bin:/sbin:/usr/sbin:$PATH dockerd-rootless.sh > /dev/null 2>&1 &

#之后测试是否启动成功
docker ps

配置持久化

在rootlesstest的家目录中执行以下命令,编辑.bashrc文件

vi ~/.bashrc

#最下方添加以下配置

export XDG_RUNTIME_DIR=/home/rootlesstest/.docker/run
export PATH=/usr/bin:$PATH
export DOCKER_HOST=unix:///home/rootlesstest/.docker/run/docker.sock

#保存退出

#应用配置
source ~/.bashrc

#启动和之前一样还是用以下命令
PATH=/usr/bin:/sbin:/usr/sbin:$PATH dockerd-rootless.sh > /dev/null 2>&1 &

#关闭docker
pkill dockerd

systemctl模式

安装方法和上面一样,唯一的不同是要用su -切换用户,新开个ssh终端,用rootlesstest用户重新登陆。

#若之前安装并配置了持久化,先删除之前的配置
vi ~/.bashrc
#删除之前添加的内容
export XDG_RUNTIME_DIR=/home/rootlesstest/.docker/run
export PATH=/usr/bin:$PATH
export DOCKER_HOST=unix:///home/rootlesstest/.docker/run/docker.sock
#刷新配置
source ~/.bashrc


#执行安装脚本
dockerd-rootless-setuptool.sh install

#安装成功会有类似提示
[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger rootlesstest`

[INFO] CLI context "rootless" already exists
[INFO] Using CLI context "rootless"
Current context is now "rootless"

[INFO] Make sure the following environment variable(s) are set (or add them to ~/.bashrc):
export PATH=/usr/bin:$PATH

[INFO] Some applications may require the following environment variable too:
export DOCKER_HOST=unix:///run/user/1002/docker.sock

安装成功,配置环境变量。

同样编辑~/.bashrc文件

vi ~/.bashrc

#把安装的提示信息写入文件
export PATH=/usr/bin:$PATH
export DOCKER_HOST=unix:///run/user/1002/docker.sock
#保存退出

#应用配置
source ~/.bashrc

未安装docker

以新用户dockerun安装。

未安装docker时,可用脚本安装。Ubuntu 24.04 及更高版本需要先配置AppArmor。官方给的脚本在ubuntu24.04中一般用户执行可能会提示“权限不足”。给出了修改后的脚本,此脚本需要sudo权限。

#官方脚本
filename=$(echo $HOME/bin/rootlesskit | sed -e 's@^/@@' -e 's@/@.@g')
[ ! -z "${filename}" ] && sudo cat <<EOF > /etc/apparmor.d/${filename}
abi <abi/4.0>,
include <tunables/global>

"$HOME/bin/rootlesskit" flags=(unconfined) {
  userns,

  include if exists <local/${filename}>
}
EOF

修改后的脚本



filename=$(echo $HOME/bin/rootlesskit | sed -e 's@^/@@' -e 's@/@.@g')
[ ! -z "${filename}" ] && cat <<EOF | sudo tee /etc/apparmor.d/${filename}
abi <abi/4.0>,
include <tunables/global>

"$HOME/bin/rootlesskit" flags=(unconfined) {
  userns,

  include if exists <local/${filename}>
}
EOF

之后重启apparmor.service服务

sudo systemctl restart apparmor.service

安装docker rootless

#使用脚本安装
curl -fsSL https://get.docker.com/rootless | sh

#安装成功
+ systemctl --user enable docker.service
Created symlink /home/dockerun/.config/systemd/user/default.target.wants/docker.service → /home/dockerun/.config/systemd/user/docker.service.
[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger dockerun`

[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Using CLI context "rootless"
Current context is now "rootless"

[INFO] Make sure the following environment variable(s) are set (or add them to ~/.bashrc):
export PATH=/home/dockerun/bin:$PATH

[INFO] Some applications may require the following environment variable too:
export DOCKER_HOST=unix:///run/user/1001/docker.sock

设置环境变量

注意,要根据安装成功的提示设置对应的变量,不要照抄。


#编辑bashrc文件
vi ~/.bashrc

#最下方添加以下内容
export PATH=/home/dockerun/bin:$PATH
export DOCKER_HOST=unix:///run/user/1001/docker.sock
#保存退出

#应用配置
source ~/.bashrc
#之后便可以正常使用docker了

运行docker rootless

查看docker信息,一般用户使用,无需sudo权限。

docker info

rootless模式systemctl操作

  • 启动docker:systemctl --user start docker
  • 关闭docker:systemctl --user stop docker
  • 查看docker状态:systemctl --user status docker
  • 重启docker:systemctl --user restart docker
  • 设置登录启动(登录rootlesstest用户后自动启动):systemctl --user enable docker
  • 设置开机启动(开机,而无需登录便启动,需要sudo):sudo loginctl enable-linger $(whoami)

如果不想给rootlesstest用户sudo权限,可以让有sudo权限的用户设置sudo loginctl enable-linger rootlesstest

配置文件位置

docker rootless的配置文件不在/etc/docker/daemon.json中。位置是~/.config/docker/daemon.json。若没有,需要自己创建。

修改后重启docker服务即可systemctl --user restart docker

测试镜像

#下载nginx镜像进行测试
docker run -d -p 8080:80 nginx

#浏览器打开8080端口能看到nginx默认主页,或者用curl命令
curl 127.0.0.1:8080
#将会看到
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>


暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇