| 操作系统 | 配置 | 主机名 | IP |
|---|---|---|---|
| CentOS 7.9 | 2C4G | master | 192.168.93.165 |
| CentOS 7.9 | 2C4G | client | 192.168.93.166 |
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config
hostnamectl set-hostname master
hostnamectl set-hostname client
cat >> /etc/hosts << EOF
192.168.93.165 master
192.168.93.166 client
EOF
Docker提供了Docker hub,可以让用户上传创建的镜像,以便其他用户下载,快速搭建环境。但同时也带来了一些安全问题。例如下面三种方式:
(1)、客户上传恶意镜像
(2)、镜像使用有漏洞的软件
(3)中间人攻击篡改镜像
Docker本身的架构与机制就可能产生问题,例如这样一种攻击场景,黑客已经控制了宿主机上的一些容器,或者获得了通过在公有云上建立容器的方式,然后对宿主机或其他容器发起攻击
为容器创建独立分区
仅运行必要的服务
禁止将宿主机上敏感目录映射到容器
对Docker守护进程、相关文件和目录进行审计
设置适当的默认文件描述符数
用户权限为root的Docker相关文件的访问权限应该为644或者更低权限
周期性检查每个主机的容器清单,并清理不必必要的容器
hostnamectl set-hostname master
[root@master ~]# mkdir /tls
[root@master ~]# cd /tls/
[root@master tls]# echo "127.0.0.1 master" >> /etc/hosts
# 使用OpenSSL创建CA、服务器的端口段密钥
[root@master tls]# openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus
...................++
...........................................................................................................................++
e is 65537 (0x10001)
Enter pass phrase for ca-key.pem: # 密码123123
Verifying - Enter pass phrase for ca-key.pem: # 确定密码
[root@master tls]# openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem: # 输入刚刚的密码123123
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:HN
Locality Name (eg, city) [Default City]:ZhengZhou
Organization Name (eg, company) [Default Company Ltd]:kgc
Organizational Unit Name (eg, section) []:kgc
Common Name (eg, your name or your server's hostname) []:master
Email Address []:
[root@master tls]# openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus
......................................................................................................++
..................................................................................................................++
e is 65537 (0x10001)
[root@master tls]# openssl req -subj "/CN=master" -sha256 -new -key server-key.pem -out server.csr
# 由于可以通过IP地址贺DNS名称进行TLS连接,因此IP地址需要在创建证书时指定,例如,允许连接的IP为127.0.0.1、192.168.93.166
[root@master tls]# echo subjectAltName = DNS:master,IP:192.168.93.165,IP:127.0.0.1 >> extfile.cnf
# 将Docker守护程序密钥的扩展用法属性设置为仅用于服务器身份验证
[root@master tls]# echo extendedKeyUsage = serverAuth >> extfile.cnf
# 生成签名证书
[root@master tls]# openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
Signature ok
subject=/CN=master
Getting CA Private Key
Enter pass phrase for ca-key.pem:
[root@master tls]# openssl genrsa -out key.pem 4096
Generating RSA private key, 4096 bit long modulus
.....................................................................................................................................................++
...........................................................................................................................................................................................................................................................................................++
e is 65537 (0x10001)
[root@master tls]# openssl req -subj '/CN=client' -new -key key.pem -out client.csr
[root@master tls]# echo extendedKeyUsage = clientAuth > extfile-client.cnf
# 生成签名证书
[root@master tls]# openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile-client.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for ca-key.pem:
# 生成后,可以安全地删除两个证书签名请求贺扩展配置文件
[root@master tls]# rm -rf client.csr server.csr extfile.cnf extfile-client.cnf
# 为了数据的安全,进行对密钥的权限更改
[root@master tls]# chmod -v 0400 ca-key.pem key.pem server-key.pem
[root@master tls]# chmod -v 0444 ca.pem server-cert.pem cert.pem
# 把密钥上传到client
[root@master tls]# scp ca.pem root@192.168.93.166:/etc/docker/
[root@master tls]# scp cert.pem root@192.168.93.166:/etc/docker/
[root@master tls]# scp key.pem root@192.168.93.166:/etc/docker/
# 重新启动docker开启TLS认证加密
## 方法1:
[root@master tls]# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --tlsverify --tlscacert=/tls/ca.pem --tlscert=/tls
/server-cert.pem --tlskey=/tls/server-key.pem -H tcp://0.0.0.0:2376 -H unix:/
//var/run/docker.sock
#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
[root@master tls]# systemctl daemon-reload
[root@master tls]# systemctl restart docker
## 方法2:
[root@master tls]# systemctl stop docker
[root@master tls]# dockerd --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:2376
hostnamectl set-hostname client
[root@client ~]# vim /etc/hosts
192.168.93.165 master
[root@client ~]# cd /etc/docker/
# 使用密钥连接master并查看master的docker版本
[root@client docker]# docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H=master:2376 version
Client: Docker Engine - Community
Version: 26.1.2
API version: 1.45
Go version: go1.21.10
Git commit: 211e74b
Built: Wed May 8 14:01:02 2024
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 26.1.2
API version: 1.45 (minimum version 1.24)
Go version: go1.21.10
Git commit: ef1912d
Built: Wed May 8 13:59:55 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.31
GitCommit: e377cd56a71523140ca6ae87e30244719194a521
runc:
Version: 1.1.12
GitCommit: v1.1.12-0-g51d5e94
docker-init:
Version: 0.19.0
GitCommit: de40ad0
[root@master ~]# docker exec -it 容器名称 bash
# docker.scok是daemon监听的套接字,容器中的进程可以通过它与docker daemon通信
[root@master ~]# dockerd -H unix:///var/run/docker.sock
或
[root@master ~]# vim /usr/lib/systemd/system/docker.service
# 进行修改即可
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://192.168.93
.165:2375
[root@master ~]# systemctl daemon-reload
[root@master ~]# systemctl restart docker
[root@master ~]# netstat -anpt | grep docker
tcp 0 0 192.168.93.165:2375 0.0.0.0:* LISTEN 13281/dockerd
[root@master ~]# systemctl start firewalld
# 添加防火墙富规则
[root@master ~]# firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.93.166" port protocol="tcp" port="2375" accept"
success
# 刷新防火墙
[root@master ~]# firewall-cmd --reload
success
# 在客户端控制服务端拉去一个nginx镜像
[root@client ~]# docker -H=tcp://192.168.93.165:2375 pull nginx
# 在服务端查看是否有nginx镜像
[root@master ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 4f67c83422ec 3 days ago 188MB
# 拒绝10.0网段的主机与服务器通信
[root@master ~]# firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.10.0/24" reject"
[root@master ~]# yum -y install git
[root@master ~]# git clone https://github.com/docker/docker-bench-security.git
Cloning into 'docker-bench-security'...
remote: Enumerating objects: 2726, done.
remote: Counting objects: 100% (804/804), done.
remote: Compressing objects: 100% (242/242), done.
remote: Total 2726 (delta 611), reused 634 (delta 554), pack-reused 1922
Receiving objects: 100% (2726/2726), 4.46 MiB | 1.50 MiB/s, done.
Resolving deltas: 100% (1889/1889), done.
[root@master ~]# cd docker-bench-security/
[root@master docker-bench-security]# sh docker-bench-security.sh
##################################################################
# --------------------------------------------------------------------------------------------
# Docker Bench for Security v1.6.0
#
# Docker, Inc. (c) 2015-2024
#
# Checks for dozens of common best-practices around deploying Docker containers in production.
# Based on the CIS Docker Benchmark 1.6.0.
# --------------------------------------------------------------------------------------------
Initializing 2024-06-02T06:50:17-04:00
Section A - Check results
[INFO] 1 - Host Configuration
[INFO] 1.1 - Linux Hosts Specific Configuration
[DEPRECATION NOTICE]: API is accessible on http://192.168.93.165:2375 without encryption.
Access to the remote API is equivalent to root access on the host. Refer
to the 'Docker daemon attack surface' section in the documentation for
more information: https://docs.docker.com/go/attack-surface/
In future versions this will be a hard failure preventing the daemon from starting! Learn more at: https://docs.docker.com/go/api-security/
[WARN] 1.1.1 - Ensure a separate partition for containers has been created (Automated)
[INFO] 1.1.2 - Ensure only trusted users are allowed to control Docker daemon (Automated)
[INFO] * Users:
[WARN] 1.1.3 - Ensure auditing is configured for the Docker daemon (Automated)
Section C - Score
[INFO] Checks: 86
[INFO] Score: -2
# 部分内容省略
##################################################################
# 输出结果中,带有不同的级别,说明问题的严重程度,最后会给出整体检查结果和评分
1、标红[WARN]是需要调整
2、标绿[PASS]表示通过检测
3、[INFO]可根据实际需要确定是否进行调整
# 一般要尽量避免出现WARN或以上的问题
root@master ~]# docker pull centos:7
[root@master ~]# mkdir /root/stress
[root@master ~]# cat /root/stress/Dockerfile
FROM centos:7
MAINTAINER Wzh
RUN yum -y install wget
RUN wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum -y install stress
[root@master ~]# cd /root/stress/
[root@master stress]# docker build -t centos:stress .
[root@master stress]# docker run -itd --cpu-shares 100 centos:stress
# stress -c 10向容器中开启10个进程用于测试
[root@master stress]# docker run -itd --name cpu512 --cpu-shares 512 centos:stress stress -c 10
# 进入容器使用top查看资源咱占用情况
[root@master ~]# docker exec -it cpu512 bash
[root@5a30bc38e2d9 /]# top
top - 11:26:33 up 10 min, 0 users, load average: 7.89, 2.69, 0.98
Tasks: 13 total, 11 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s): 98.8 us, 1.2 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0
KiB Mem : 3861260 total, 2380572 free, 312972 used, 1167716 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3302036 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9 root 20 0 7312 96 0 R 20.3 0.0 0:17.46 stress
12 root 20 0 7312 96 0 R 20.3 0.0 0:17.62 stress
13 root 20 0 7312 96 0 R 20.3 0.0 0:18.17 stress
6 root 20 0 7312 96 0 R 19.9 0.0 0:17.96 stress
7 root 20 0 7312 96 0 R 19.9 0.0 0:17.58 stress
8 root 20 0 7312 96 0 R 19.9 0.0 0:17.66 stress
15 root 20 0 7312 96 0 R 19.9 0.0 0:17.59 stress
10 root 20 0 7312 96 0 R 19.6 0.0 0:17.47 stress
11 root 20 0 7312 96 0 R 19.6 0.0 0:17.58 stress
14 root 20 0 7312 96 0 R 19.6 0.0 0:18.16 stress
1 root 20 0 7312 624 528 S 0.0 0.0 0:00.01 stress
16 root 20 0 11828 1896 1492 S 0.0 0.0 0:00.01 bash
30 root 20 0 56192 2012 1444 R 0.0 0.1 0:00.00 top
[root@master ~]# docker run -itd --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10
[root@master ~]# docker exec -it cpu1024 bash
[root@dc64e7513c1f /]# top
top - 11:28:19 up 12 min, 0 users, load average: 13.22, 5.74, 2.24
Tasks: 13 total, 11 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0
KiB Mem : 3861260 total, 2369580 free, 323532 used, 1168148 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3291300 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7 root 20 0 7312 92 0 R 14.2 0.0 0:03.71 stress
13 root 20 0 7312 92 0 R 14.2 0.0 0:03.68 stress
15 root 20 0 7312 92 0 R 14.2 0.0 0:03.50 stress
14 root 20 0 7312 92 0 R 13.9 0.0 0:03.51 stress
9 root 20 0 7312 92 0 R 12.9 0.0 0:03.32 stress
10 root 20 0 7312 92 0 R 12.6 0.0 0:03.32 stress
12 root 20 0 7312 92 0 R 12.6 0.0 0:03.29 stress
11 root 20 0 7312 92 0 R 12.3 0.0 0:03.31 stress
16 root 20 0 7312 92 0 R 12.3 0.0 0:03.33 stress
8 root 20 0 7312 92 0 R 11.9 0.0 0:03.31 stress
1 root 20 0 7312 620 528 S 0.0 0.0 0:00.01 stress
17 root 20 0 11828 1904 1496 S 0.0 0.0 0:00.01 bash
31 root 20 0 56192 2012 1444 R 0.0 0.1 0:00.00 top
# 可以看容器512CPU占用率要比1024高
Docker提供了–cpu-period、–cpu-quota两个参数控制容器可以分配到CPU时钟周期
–cpu-period:是用来指定容器对CPU的使用要在多长事件内做一次重新分配
–cpu-quota:是用来指定在这个周期内,最多可以有多少时间跑这个容器。与–cpu-shares不同的是,这种配置是指定一个绝对值,容器对CPU资源的使用绝对不会超过配置的值
cpu-period和cpu-quota的单位为微秒(us)。cpu-period的最小值为1000微妙,最大值为1秒。默认值为0.1秒。cpu-quota的值默认为-1,表示不做控制。cpu-period和cpu-quota参数一般联合使用
# 例如:容器进程需要每1秒使用单个CPU的0.2秒时间,可以将cpu-period设置为1000000(即1秒),cpu-quota设置为200000(0.2秒)
[root@master ~]# docker run -itd --cpu-period 1000000 --cpu-quota 200000 centos:stress
[root@master ~]# docker exec -it condescending_spence bash
[root@3d0f9e29cc61 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
1000000
[root@3d0f9e29cc61 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
200000
# 只允许这个容器使用0、1两个内核
[root@master ~]# docker run -itd --name cpu1 --cpuset-cpus 0-1 centos:stress
[root@master ~]# docker exec -it cpu1 bash
[root@ea4cd6c80f5e /]# cat /sys/fs/cgroup/cpuset/cpuset.cpus
0-1
[root@master ~]# docker run -itd --name cpu3 --cpuset-cpus 1 --cpu-shares 512 centos:stress stress -c 1
[root@master ~]# docker exec -it cpu3 bash
[root@3a197567bf58 /]# top
top - 11:52:58 up 37 min, 0 users, load average: 20.67, 20.14, 16.51
Tasks: 4 total, 2 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0
KiB Mem : 3861260 total, 2333408 free, 357196 used, 1170656 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3256448 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7 root 20 0 7312 96 0 R 54.8 0.0 0:32.37 stress
1 root 20 0 7312 424 344 S 0.0 0.0 0:00.00 stress
8 root 20 0 11828 1900 1496 S 0.0 0.0 0:00.01 bash
22 root 20 0 56192 2000 1444 R 0.0 0.1 0:00.00 top
[root@master ~]# docker run -itd --name cpu4 --cpuset-cpus 1 --cpu-shares 1024 centos:stress stress -c 1
[root@master ~]# docker exec -it cpu4 bash
[root@080ee5432922 /]# top
top - 11:56:33 up 40 min, 0 users, load average: 21.80, 20.81, 17.52
Tasks: 4 total, 2 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0
KiB Mem : 3861260 total, 2325228 free, 364704 used, 1171328 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3248516 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7 root 20 0 7312 96 0 R 66.7 0.0 0:16.50 stress
1 root 20 0 7312 424 344 S 0.0 0.0 0:00.01 stress
8 root 20 0 11828 1896 1496 S 0.0 0.0 0:00.01 bash
22 root 20 0 56192 1964 1428 R 0.0 0.1 0:00.00 top
# 上面的centos:stress镜像安装了stress工具,用来测试CPU和内存的负载。通过在两个容器上分别执行stress -c 1命令,将会给系统一个随机负载,产生1个进程,这个进程都反复不停的计算有rand()产生随机数的平方根,知道资源耗尽
与操作系统类似,容器可使用的内存包括两部分:物理内存和Swap。Docker通过下面两组参数来控制容器内存的使用量
# 执行如下命令允许该容器最多使用200M的内存和不能超过300的swap(swap100内存)
[root@master ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
--vm 1:启动1个内存工作线程
--vm-bytes 280M:每个线程分配280内存
# 默认情况下,容器可以使用主机上的所有空闲内存。与CPU的cgroups配置类似,Docker会自动为容器在目录/sys/fs/cgroup/memory/docker<容器的完整长度 ID>中创建相应cgroup配置文件
# 因为280M在可分配的范围(300M)内,所以工作线程能够正常工作,其工作过程是
分配280M内存
释放280M内存
再分配280M内存
再释放280M内存
一直循环
# 如果让工作线程分配的内存超过300M,分配的内存超过限制,stress线程报错,容器退出
[root@master ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 325058560 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: FAIL: [1] (416) <-- worker 7 got signal 9
stress: WARN: [1] (418) now reaping child worker processes
stress: FAIL: [1] (422) kill error: No such process
stress: FAIL: [1] (452) failed run completed in 0s
[root@master ~]# docker run -it --name IO_A --blkio-weight 600 centos:stress [root@c3d24510ba18 /]# cat /sys/fs/cgroup/blkio/blkio.weight
600
[root@master ~]# docker run -it --name IO_B --blkio-weight 300 centos:stress
[root@5f98b4ad5a2a /]# cat /sys/fs/cgroup/blkio/blkio.weight
300
--device-read-bps:限制读某个设备的bps
--device-write-bsp:限制写某个设备的bps
--device-read-iops:限制某个设备的iops
--device-write-iops:限制写某个设备的iops
# 下面的示例是显示容器写/dev/sda的速率为5MB/s
[root@master ~]# docker run -it --device-write-bps /dev/sda:5MB centos:stress
# 输出完时间为20秒左右
[root@4775b55a6f0b /]# dd if=/dev/zero of=test bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 20.0017 s, 5.2 MB/s
# 不限速,不限速时间还没1秒就输出完毕了
[root@master ~]# docker run -it centos:stress
[root@ee280332da35 /]# dd if=/dev/zero of=test bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 0.0775017 s, 1.4 GB/s
# 通过dd命令测试在容器中写磁盘的速度。因为容器的文件系统是在host/dev/sda上的,在容器中写文件相当于对host/dev/sda进行写操作。另外,oflag=direct指定用direct IO方式写文件,这样--device-weite-bps才能生效