【问题标题】:Why is a shell within a docker container showing dmesg content from the host?为什么 docker 容器中的 shell 显示来自主机的 dmesg 内容?
【发布时间】:2017-05-01 11:31:28
【问题描述】:

我有一个在 Ubuntu yakkety 上运行 Debian jessie 的 docker 容器。

在 docker 内(例如通过 ssh 连接)时,我与主机隔离(这是预期的)。然而,我意识到dmesg 向我显示了主机而不是容器的消息。 它如何获得宿主的信息?

docker容器的配置并不特殊(除了它使用特定的网桥,不同于docker0),特别是它不运行在任何特权模式下("Privileged": false下面):

root@srv ~# docker inspect minecraft-1-8
[
    {
        "Id": "748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e",
        "Created": "2016-12-01T15:35:05.287672787Z",
        "Path": "/usr/bin/supervisord",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 28650,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2016-12-15T18:37:08.409564695Z",
            "FinishedAt": "2016-12-15T18:37:07.457274028Z"
        },
        "Image": "sha256:78a2f88d47e29523503c2196ed2faaa3d1039d948d73987edc03b2abd338595d",
        "ResolvConfPath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/hostname",
        "HostsPath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/hosts",
        "LogPath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e-json.log",
        "Name": "/minecraft-1-8",
        "RestartCount": 0,
        "Driver": "overlay",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "docker",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": null,
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DiskQuota": 0,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": -1,
            "OomKillDisable": false,
            "PidsLimit": 0,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0
        },
        "GraphDriver": {
            "Name": "overlay",
            "Data": {
                "LowerDir": "/var/lib/docker/overlay/e78ce9dbcedd6974429a4aada8f38913b7d35da41f586f203dd99a568f38b6c3/root",
                "MergedDir": "/var/lib/docker/overlay/e8422e4707d95db8ea747af2367626cc8bf16e95f8eb05dfad9a63461c9ade86/merged",
                "UpperDir": "/var/lib/docker/overlay/e8422e4707d95db8ea747af2367626cc8bf16e95f8eb05dfad9a63461c9ade86/upper",
                "WorkDir": "/var/lib/docker/overlay/e8422e4707d95db8ea747af2367626cc8bf16e95f8eb05dfad9a63461c9ade86/work"
            }
        },
        "Mounts": [],
        "Config": {
            "Hostname": "minecraft-1-8",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": true,
            "AttachStderr": true,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/usr/bin/supervisord"
            ],
            "Image": "minecraft",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "cf411634babad31138ab4572b9cd7306f74a54dd1baf4cd8d7706d7e7020c594",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/cf411634baba",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "",
            "Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "",
            "IPPrefixLen": 0,
            "IPv6Gateway": "",
            "MacAddress": "",
            "Networks": {
                "docker": {
                    "IPAMConfig": {
                        "IPv4Address": "10.200.0.100"
                    },
                    "Links": null,
                    "Aliases": [
                        "748cfdfbf3fb"
                    ],
                    "NetworkID": "7b20560b36032d36ffe6c0ebece6b4408355d207f4e203a2957b0434ee0afdc1",
                    "EndpointID": "9fa4fc914dfe76022ce0db02e48a7e7c85c57bc2a15b0b3e5d81b1f24d95f376",
                    "Gateway": "10.200.0.1",
                    "IPAddress": "10.200.0.100",
                    "IPPrefixLen": 24,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:0a:c8:00:64"
                }
            }
        }
    }
]

【问题讨论】:

  • 显示您的docker run 命令
  • @user2915097:我start 是使用docker create --network docker --ip 10.200.0.100 --name=minecraft-1-8 -h minecraft-1-8 base 创建的现有容器,其中base 是debian yakkety 映像。

标签: docker containers privileges elevated-privileges


【解决方案1】:

在大多数发行版中,dmesg 不是特权命令。任何用户都可以使用klogctl 接口来读取内核环形缓冲区。

$ id
uid=1001(matt) gid=1001(matt) groups=1001(matt)
$ dmesg | head -1
[    0.000000] Initializing cgroup subsys cpuset

但是除了阅读之外什么也做不了

$ dmesg -C
dmesg: klogctl failed: Operation not permitted

延伸到 Docker

$ sudo docker run debian dmesg | head -1
[    0.000000] Initializing cgroup subsys cpuset
$ sudo docker run debian dmesg -C
dmesg: klogctl failed: Operation not permitted

限制访问

您可以通过/proc/sys/kernel/dmesg_restrict 将读取权限限制为root 用户以及具有CAP_SYSLOG 或CAP_SYS_ADMIN capabilities 的用户。

$ echo 1 > /proc/sys/kernel/dmesg_restrict

那么您应该会收到一条权限被拒绝消息:

$ docker run ubuntu:yakkety dmesg
dmesg: read kernel buffer failed: Operation not permitted

在特权模式下运行容器将重新获得对主机内核环形缓冲区的访问权

$ docker run --privileged ubuntu:yakkety dmesg
[146902.131915] br-fa26f1dc96a1: port 3(veth80d3d5d) entered disabled state
...

如果您永久需要,请使用 sysctl 配置 kernel.dmesg_restrict=1

命名空间

至于为什么内核日志没有像其他内核区域那样的名称间距,我认为答案是“很难”。在此 2012 Stepping closer to practical containers: "syslog" namespaces LWN 帖子中,您想知道的细节比您想知道的要多。除了提议的补丁之外,我看不到任何对它的引用:https://lwn.net/Articles/562389/https://lwn.net/Articles/561271/。正如您在recent netfilter patch 中看到的那样,他们有一种变通方法,允许容器名称空间中的规则使用全局日志。

【讨论】:

  • 谢谢马特。我担心的是您回答的第三点 - 我不关心谁可以在容器中看到(并做什么)容器数据。查看主机日志的能力非常烦人,因为这些日志可能包含不打算用于(隔离和非特权)docker 实例的信息。
  • @WoJ 是的,最好禁用非特权访问。
  • 我的印象是已经是这样了? (查看inspect 输出)
  • ...通过kernel.dmesg_restrict=1klogctl 读取函数
  • 想知道为什么dmesg_restrict 默认设置为0?人们认为它不敏感吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-28
  • 1970-01-01
  • 2020-04-28
  • 2016-01-23
  • 2017-09-14
  • 2020-08-14
相关资源
最近更新 更多