对于Linux服务器而言,常用netfilter/iptables数据包过滤系统。Centos 8采用了firewalld取代了iptables。firewalld和iptables其实都不是真正的防火墙,只是定义策略的防火墙工具而已。
SELinux全称为“Security-Enhanced Linux”,是安全增强型Linux系统,一个Linux内核模块,也是Linux的一个安全子系统。开启后会关闭系统中不安全的功能。主要作用是最大限度地减小系统中服务进程可访问的资源。SELinux有Enforcing、Permissive、Disabled三种模式:
Enforcing(强制模式):违反SELinux规则的行为将被阻止并记录到日志中。
Permissive(宽容模式):违反SELinux规则的行为只会记录到日志中。一般为调试用。
Disabled(关闭模式):SELinux并没有实际运行。
在 CentOS 8 系统中,有三套策略:
targeted:对大部分网络服务进程进行管制。这是系统默认使用的政策。
minimum:以 targeted 为基础,仅对选定的网络服务进程进行管制。一般不用。
mls:多级安全保护。对所有的进程进行管制。这是最严格的政策,配置难度非常大。一般不用,除非对安全性有极高的要求。
查看安全策略
[root@localhost ~]# cat /etc/selinux/config SELINUX=enforcing SELINUXTYPE=targeted //如果想要修改模式和策略,更改这个文件里面的内容即可。 |
2.1 SELinux基本操作
1)模式切换
查看状态
[root@wuzz ~]# getenforce Permissive |
或
[root@wuzz ~]# sestatus -v SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: permissive Mode from config file: enforcing Policy MLS status: enabled Policy deny_unknown status: allowed Memory protection checking: actual (secure) Max kernel policy version: 33 Process contexts: Current context: unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 Init context: system_u:system_r:init_t:s0 /usr/sbin/sshd system_u:system_r:sshd_t:s0-s0:c0.c1023 File contexts: Controlling terminal: unconfined_u:object_r:user_devpts_t:s0 /etc/passwd system_u:object_r:passwd_file_t:s0 /etc/shadow system_u:object_r:shadow_t:s0 /bin/bash system_u:object_r:shell_exec_t:s0 /bin/login system_u:object_r:login_exec_t:s0 /bin/sh system_u:object_r:bin_t:s0 -> system_u:object_r:shell_exec_t:s0 /sbin/agetty system_u:object_r:getty_exec_t:s0 /sbin/init system_u:object_r:bin_t:s0 -> system_u:object_r:init_exec_t:s0 /usr/sbin/sshd system_u:object_r:sshd_exec_t:s0 |
//如果第一行的SELinux status参数为enabled即为开启状态
关闭SELinux
临时关闭(不用重启)
[root@localhost ~]# setenforce 0 //设置SELinux 为permissive模式 //setenforce 1|0 设置SELinux 为Enforcing|Premission模式 //临时关闭的适用范围只能在够在Enforcing和Permissive两种模式之间进行切换 |
永久关闭
[root@localhost ~]# vim /etc/selinux/config SELINUX=disabled [root@localhost ~]# reboot |
2)SELinux安全上下文
传统Linux,一切接文件,由用户,组,权限控制访问; 在SELinux中,一切皆对象,由存放在inode的扩展属性域的安全元素所控制其访问。所有文件、端口资源和进程都具备安全标签:安全上下文。安全上下文是SELinux的核心。
查看文件或目录的安全上下文
[root@wuzz ~]# ls -Z /var/log/messages system_u:object_r:var_log_t:s0 /var/log/messages [root@wuzz ~]# ll -Z /var/log/messages -rw-------. 1 root root system_u:object_r:var_log_t:s0 2121223 9月 19 21:13 /var/log/messages |
查看进程的安全上下文
[root@localhost ~]# ps auxZ | grep -v grep | grep <进程名> |
修改文件或目录的安全上下文为default_t
[root@localhost ~]# chcon -t default_t /var/log/messages |
// -R 递归处理所有的文件及子目录
-v 为处理的所有文件显示诊断信息
-r 修改安全上下文角色的配置
-t 修改安全上下文类型的配置
把文件或目录的安全上下文恢复到默认值
[[root@wuzz ~]# restorecon -Rv /var/log/messages Relabeled /var/log/messages from system_u:object_r:default_t:s0 to system_u:object_r:var_log_t:s0 |
添加目录的默认安全上下文
semanage fcontext -a -t httpd_sys_content_t '/newdir(/.*)?' //目录或文件的默认安全上下文可以通过 semanage fcontext -l 命令配合 grep过滤查看 |
添加某类进程允许访问的端口
[root@localhost ~]# semanage port -a -t http_port_t -p tcp 82 |
//各种服务类型所允许的端口号可以通过 semanage port -l 命令配合 grep 过滤查看
3) SEbool
系统中通常有大量的文件和进程,为了节省时间和开销,通常我们只是选择性地对某些进程进行管制。而进程需要管制的类型由政策决定的。一套政策里面有多个布尔型规则。部分布尔型规则可以按照需求启用或禁用。布尔型规则是 SELinux 对服务功能能添加的开关。
查看功能开关
[root@wuzz ~]# getsebool -a | grep httpd httpd_anon_write --> off httpd_builtin_scripting --> on httpd_can_check_spam --> off httpd_can_connect_ftp --> off httpd_can_connect_ldap --> off …… |
//由于该命令要么查询所有规则,要么只查询一个规则,所以一般都是先查询所有规则然后用 grep 筛选。
开关一个布尔型规则
[root@localhost ~]# setsebool -P httpd_anon_write on [root@localhost ~]# setsebool -P httpd_anon_write off |
或
[root@localhost ~]# setsebool -P httpd_anon_write=1 [root@localhost ~]# setsebool -P httpd_anon_write=0 |
//-P 重启仍然生效
2.2 firewalld的配置与管理
firewalld(动态防火墙管理器)自身和iptables一样,并不具备防火墙的功能,而是需要通过内核的 netfilter来实现,也就是说firewalld和iptables的作用都是用于维护规则,而真正使用规则的是内核的netfilter。只不过firewalld和iptables的结构以及使用方法不一样。firewalld跟iptables比起来,firewalld可以动态修改单条规则,不需要像iptables那样,修改了规则后必须全部刷新才可以生效。缺点是每个服务都需要去设置才能放行,因为默认是拒绝,而iptables里默认是每个服务是允许,需要拒绝的才去限制。普遍应用于Rhel7、CentOS7及之后。且最小化安装的Linux系统不会安装firewalld。firewalld只能做和IP/Port相关的限制,web相关的限制无法实现。
通过将网络划分成不同的区域,制定出不同区域间的访问控制策略来控制不同程序区域间传送的数据流。一个网卡仅能绑定一个区域,但一个区域可以绑定多个网卡。如表2-1所示的几种不同的预定义区域。
表2-1 预定义区域名称及配置
区域名称 | 默认配置 |
trusted | 允许所有数据包传入和数据包流出,lo接口被分配为此区域 |
home | 拒绝任何数据包流入,但允许数据包流出和预定义服务(ssh、mdns、ipp-client、sbmclient、dhcpv6-client)的数据包可以流入 |
work | 拒绝任何数据包流入,但允许数据包流出和预定义服务(ssh、ipp-client、dhcpv6-client)的数据包可以流入 |
public | 拒绝任何数据包流入,但允许数据包流出和预定义服务(ssh、dhcpv6-client)的数据包可以流入。新添加的网卡默认绑定到该区 |
dmz | 隔离区域也称为非军事区域。拒绝任何数据包流入,但允许数据包流出和预定义服务(ssh)的数据包可以流入 |
block | 阻止所有传入的数据包 |
drop | 拒绝所有传入的数据包 |
internal | 拒绝任何数据包流入,但允许数据包流出和预定义服务(ssh)的数据包可以流入 |
external | 拒绝任何数据包流入,但允许数据包流出和预定义服务(ssh、dhcpv6-client)的数据包可以流入 |
相应地,firewalld提供了九个区域的配置文件,分别是trusted.xml、home.xml、work.xml 、public.xml、dmz.xml、block.xml、drop.xml、internal.xml、external.xml,他们都保存在“/usr/lib/firewalld/zones/”目录下。
注:默认区域是public,默认区域可以修改。
通过预定义服务,可以很方便的允许特定网络的流量通过防火墙,如表2-2所示。
表2-2 预定义服务节选
服务名称 | 配置 |
ssh | 本地SSH服务器。到22/tcp的流量。 |
dhcpv6-client | 本地DHCPv6客户端。到fe80::/64 IPv6网络中546/udp的流量。 |
ipp-client | 本地IPP打印。到631/udp的流量。 |
samba-client | 本地Windows文件和打印共享客户端。到137/udp和138/udp的流量。 |
mdns | 多播DNS(mDNS)本地链路名称解析。到5353/udp指向224.0.0.251(IPv4)或ff02::fb(IPv6)多播地址的流量。 |
2) firewalld 配置方法
firewalld的配置方法主要有三种:firewall-config、firewall-cmd和直接编辑xml文件。其中 firewall-config是图形化工具,firewall-cmd是命令行工具。
①安装firewalld
[root@localhost ~]# yum install firewalld firewall-config //firewall-config为图形工具 |
②启动/关闭/重启firewalld
[root@localhost ~]# systemctl start firewalld [root@localhost ~]# systemctl stop firewalld [root@localhost ~]#systemctl restart firewalld |
③屏蔽服务
[root@localhost ~]# systemctl mask iptables [root@localhost ~]# systemctl mask ip6tables [root@localhost ~]# systemctl mask ebtables |
//由于iptables、ip6tables、ebtables这三个服务与filrewalld冲突,为防止意外启动,需要屏蔽这三个服务。
④ 配置文件所在位置
[root@localhost ~]# cd /lib/firewalld/{services,zones} |
//系统配置文件,尽量不要修改
⑤ 查看状态
[root@wuzz services]# systemctl status firewalld ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2024-09-15 21:35:54 EDT; 4 days ago Docs: man:firewalld(1) Main PID: 1011 (firewalld) Tasks: 2 (limit: 36801) Memory: 38.7M CGroup: /system.slice/firewalld.service └─1011 /usr/libexec/platform-python -s /usr/sbin/firewalld --nofork --nopid 9月 15 21:35:56 wuzz firewalld[1011]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -t nat -F DOCKER' failed: iptables:> …… 9月 15 21:35:56 wuzz firewalld[1011]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -t filter -X DOCKER-ISOLATION' fail> [root@wuzz services]# firewall-cmd --state running |
⑥配置 firewalld
[root@localhost ~]# firewall-cmd [选项··· ] [root@localhost ~]# firewall-cmd --reload [root@wuzz services]# firewall-cmd --query-port=3306/tcp //查看防火墙对某个端口是否开放 [root@wuzz services]# firewall-cmd --zone=public --add-port=3306/tcp --permanent Success //注意:开放端口后要重启防火墙生效 [root@wuzz services]# firewall-cmd --zone=public --add-port=40000-45000/tcp --permanent success //注意:开放端口后要重启防火墙生效 [root@wuzz services]# firewall-cmd --remove-port=3306/tcp --permanent Success [root@wuzz services]# netstat -lnp|grep 3306 //检查端口被哪个进程占用 [root@wuzz services]# netstat -lntp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1031/sshd tcp6 0 0 :::22 :::* LISTEN 1031/sshd |
默认情况下是修改运行时配置(马上临时生效),如果要修改永久配置,添--permanent选项,但一定要重启才能生效。
zone区域相关命令,如表2-1所示。
表2-1 zone区域命令及作用说明
参数 | 作用 |
–get-default-zone | 查询当前默认区域 |
–set-default-zone= | 设置默认区域,使其永久生效 |
–get-active-zones | 列出当前正在使用的所有区域(具有关联的接口或源)及其接口和源信息。 |
–get-zones | 列出所有可用区域 |
–new-zone= | 新增区域 |
服务相关命令,如表2-2所示。
表2-2 services服务命令及作用说明
参数 | 作用 |
–get-services | 列出所有预定义服务 |
–add-service= [–zone=] | 允许到的流量。如果未提–zone=选项,则将使用默认区域 |
–remove-service= [–zone=] | 移除到的流量。如果未提–zone=选项,则将使用默认区域 |
port端口相关命令,如表2-3所示。
表2-3 port端口命令及作用说明
参数 | 作用 |
–add-port=<PORT/PROTOCOL> [–zone=] | 允许到<PORT/PROTOCOL>端口的流量。如果未提–zone=选项,则将使用默认区域 |
–remove-port=<PORT/PROTOCOL> [–zone=] | 移除到<PORT/PROTOCOL>端口的流量。如果未提–zone=选项,则将使用默认区域 |
interface接口相关命令,如表2-4所示:
表2-4 interface接口命令及作用说明
参数 | 作用 |
–add-interface= [–zone=] | 将来自的所有流量路由到指定区域,如果未提–zone=选项,则将使用默认区域 |
–remove-interface= [–zone=] | 将来自的所有流量路由取消到指定区域,如果未提–zone=选项,则将使用默认区域 |
source源相关命令,如表2-5所示:
表2-5 source源命令及作用说明
参数 | 作用 |
–add-source= [–zone=] | 将来自IP地址或网络/子网掩码的所有流量路由到指定区域。如果未提–zone=选项,则将使用默认区域 |
–remove-source= [–zone=] | 将来自IP地址或网络/子网掩码的所有流量路由取消到指定区域。如果未提–zone=选项,则将使用默认区域 |
其他相关命令,如表2-6所示:
表2-6 其他命令及作用说明
参数 | 作用 |
–list-all [–zone=] | 列出的所有已配置接口、源、服务和端口。如果未提–zone=选项,则将使用默认区域。 |
–reload | 更新防火墙规则 |
–version | 查看版本 |
⑦ 重启firewalld服务
[root@wuzz services]# firewall-cmd --reload success |
或
[root@localhost ~]# systemctl restart firewalld |
3)配置firewalld的富规则
firewalld 中的富规则表示更复杂的防火墙策略配置,它可以针对系统服务、端口号、原地址和目标地址等诸多信息进行更有针对性的策略配置,优先级在所有的防火墙策略中也是最高的。
[root@localhost ~]# man firewalld.richlanguage rule [source] [destination] service|port|protocol|icmp-block|icmp-type|masquerade|forward-port|source-port [log] [audit] [accept|reject|drop|mark] Rule rule [family="ipv4|ipv6"] Source source [not] address="address[/mask]"|mac="mac-address"|ipset="ipset" Destination destination [not] address="address[/mask]" Service service name="service name" Port port port="port value" protocol="tcp|udp" Protocol protocol value="protocol value" Forward-port forward-port port="port value" protocol="tcp|udp" to-port="port value" to-addr="address" Source-port source-port port="port value" protocol="tcp|udp" [ accept | reject | drop | mark ] |
firewall-cmd 有四个选项用于处理富规则,这些选项都能加上--permanent,--zone=<ZONE>组合使用,如表2-7所示:
表2-7 富规则命令及作用说明
参数 | 作用 |
–add-rich-rule=‘’ | 在指定的区域添加一条富规则。如果未指定区域,则向默认区域中添加 |
–remove-rich-rule=‘’ | 在指定的区域删除一条富规则。如果未指定区域,则向默认区域中添加 |
–query-rich-rule=‘’ | 查询富规则是否已添加到指定区域,如果未指定区域,则为默认区域。找到规则返回0,找不到返回1。 |
–list-rich-rules | 列出指定区域的所有富规则 |
在work区域中拒绝172.25.0.11的所有流量
[root@localhost ~]# firewall-cmd --zone=work --add-rich-rule='rule family=ipv4 source address=172.25.0.11 reject' |
允许172.25.0.0网段的主机能够访问http服务
[root@localhost ~]# firewall-cmd --add-rich-rule='rule family=ipv4 source address=172.25.0.0/24 service name=http accept' |
默认public区域对外开放,但拒绝172.16.0.0/24网段通过ssh连接
[root@localhost ~]# firewall-cmd --add-rich-rule='rule family=ipv4 source address=172.25.0.0/24 service name=ssh drop' |
网站禁止ping服务
[root@localhost ~]# firewall-cmd --add-rich-rule='rule family=ipv4 protocol value=icmp drop' //drop和reject区别 reject直接拒绝,返回拒绝 drop是丢弃,直到超时 |
2.3 iptables的配置与管理
iptables 其实不是真正的防火墙,它只是一个命令行工具,位于用户空间,可以把它理解成一个客户端代理。用户通过iptables这个代理,将用户的安全设定执行到对应的“安全框架”中,这个“安全框架”才是真正的防火墙,名字叫netfilter,位于内核空间,以实现网络数据包的过滤管理(查看、记录、修改、丢弃、拒绝)。普遍应用于Rhel6、CentOS6及之前。netfilter/iptables组成Linux平台下的包过滤防火墙。在多数Linux版本内,firewalld、iptables、ebtables是共存的,默认是使用firewalld来管理netfilter子系统,不过底层调用的命令仍然是iptables等。
1)基本命令说明
①设置基本的规则匹配
输入顺序
[root@localhost ~]# iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> |
-p 协议名 <-s 源IP/源子网> --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作
//规则的次序非常关键,谁的规则越严格,应该放的越靠前
表名(如果不指定此选项,默认是 filter 表)包括(区分大小写):
raw:高级功能,如:网址过滤。
mangle:数据包修改(QOS),用于实现服务质量。
nat:地址转换,用于网关路由器。
filter:包过滤,用于防火墙规则。
filter一般只能做在3个链上:INPUT ,FORWARD ,OUTPUT
nat一般只能做在3个链上:PREROUTING ,OUTPUT ,POSTROUTING
mangle则5个链都可以做:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
规则链包括(区分大小写):
INPUT链:处理输入数据包。
• OUTPUT链:处理输出数据包。
• FORWARD链:处理转发数据包。
• PREROUTING链:用于目标地址转换(DNAT)。
• POSTOUTING链:用于源地址转换(SNAT)。
参数选择
规则管理命令,如表2-8所示:
表2-8 规则管理参数及作用
选项 | 说明 |
-A | 在指定链的末尾插入指新规则 |
-I | 在链的指定位置插入一条或多条规则,如果指定的规则号是1,则在链的头部插入。默认是1。 |
-D | 在指定链中删除一个或多个指定规则。 |
-R | 替换/修改第几条规则 |
源地址目标地址的匹配,如表2-9所示:
表2-10 地址匹配参数及作用
选项 | 说明 |
-p | 匹配的数据包协议类型,如tcp,udp,icmp,all。也能在协议前加上“!”。 |
-s | 匹配来源地址IP/MASK,加叹号“!”表示除这个IP外。当后面没有 mask 时,address 是一个地址。iptables仅支持ipv4。 |
-d | 地址格式同上,匹配目标地址。 |
-i | 匹配从这块网卡流入的数据,比如最常见的 eth0 。 |
-o | 匹配从这块网卡流出的数据 |
链管理命令,如表2-10所示:
表2-10 链管理参数及作用
选项 | 说明 |
-P | 为指定的链设置默认策略 |
-F | 清空指定链上面的所有规则。如果没有指定链,清空该表上所有链的所有规则。 |
-X | 清除表中使用者自定的空链中的规则 |
-Z | 把指定链,或者表中的所有链上的所有计数器清零。 |
-N | 用指定的名字创建一个新的链 |
-j | 满足某条件时该执行什么样的动作 |
–dport num | 匹配目标端口号 |
–sport num | 匹配来源端口号 |
默认策略一般只有两种:
[root@localhost ~]# iptables -P INPUT ( DROP | ACCEPT ) |
//默认是关的/开的
[root@localhost ~]# iptables -P INPUT DROP |
//拒绝默认规则。且并且没有定义什么动作,所以关于外界连接的所有规则,包括远程连接都被拒绝了。
动作包括:
ACCEPT:接收数据包。
DROP:丢弃数据包。
REJRCT: 拒绝通过,必要时会给出提示
SNAT:源地址转换。
DNAT:目标地址转换。
LOG:记录日志,然后传给下一条规则
查看管理命令,如表2-11所示:
表2-11 查看管理参数及作用
选项 | 说明 |
-L | 列出链上面的所有规则。如果没有指定链,默认只列出表filter上所有链的所有规则。 |
-n | 以数字形式显示地址、端口等信息 |
–line-numbers | 查看规则时,显示规则的行号。 |
注:如果没有找到匹配条件,则执行防火墙默认规则
2)设置扩展的规则匹配
①多端口匹配
匹配多个源端口:
[root@localhost ~]# iptables -A INPUT -p tcp -m multiport --sport 22,23,53,80 -j ACCEPT |
匹配多个目的端口:
[root@localhost ~]# iptables -A INPUT -p tcp -m multiport --dport 22,23,53,80 -j ACCEPT |
匹配多端口(无论是源端口还是目的端口):
[root@localhost ~]# iptables -A INPUT -p tcp -m multiport --port 22,23,53,80 -j ACCEPT |
匹配连续端口
[root@localhost ~]# iptables -A INPUT -p tcp --sport 20:80 -j ACCEPT |
②指定 TCP 匹配
使用 –tcp-flags 选项可以根据tcp包的标志位进行过滤
[root@localhost ~]# iptables -A INPUT -p tcp --tcp-flags SYN,FIN,ACK SYN -j ACCEPT |
//表示SYN、ACK、FIN的标志都检查,但是只有SYN匹配。
③ 速率匹配
指定单位时间内允许通过的数据包个数,单位时间可以是/second、/minute、/hour、/day
[root@localhost ~]# iptables -A INPUT -m limit --limit 300/hour -j ACCEPT |
指定触发事件的阀值
[root@localhost ~]# iptables -A INPUT -m limit --limit-burst 10 -j ACCEPT |
# 一次同时涌入的封包超过10个将直接丢弃
④ 基于状态的扩展匹配
NEW: 该包想要开始一个新的连接(重新连接或连接重定向)。
RELATED: 该包是属于某个已经建立的连接所建立的新连接。
ESTABLISHED:该包属于某个已经建立的连接。
INVALID: 该包不匹配于任何连接,通常这些包被DROP。
在INPUT链添加一条规则,匹配已经建立的连接或由已经建立的连接所建立的新连接。
[root@localhost ~]# iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
在INPUT链链添加一条规则,匹配所有从非eth0接口来的连接请求包。
[root@localhost ~]# iptables -A INPUT -m state --state NEW -i !eth0 -j ACCEPT |
3)实验步骤
①安装iptables服务 yum install firewalld
[root@localhost ~]# yum install -y iptables-services |
②关闭firewalld服务
[root@localhost ~]# systemctl stop firewalld [root@localhost ~]# systemctl disable firewalld |
③启动iptables服务
[root@localhost ~]# systemctl start iptables |
④备份iptables文件
[root@localhost ~]# cp -a /etc/sysconfig/iptables /etc/sysconfig/iptables.bak |
⑤设置 INPUT 方向拒绝所有的请求
[root@localhost ~]# iptables -P INPUT DROP |
⑥开放所需端口
[root@localhost ~]# iptables -I INPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT |
⑦保存规则
[root@localhost ~]# iptables-save > /etc/sysconfig/iptables |
#如果不保存,重启服务器还是会恢复原来没有设置的状态。
⑧设置为开机自启并重启服务
[root@localhost ~]# service iptables enabled [root@localhost ~]# service iptables restart |
2.4 Docker容器NAT配置
1)Docker网络模式简介
基于对Network Namespace的控制,docker可以为在容器创建隔离的网络环境,在隔离的网络环境下,容器具有完全独立的网络栈,与宿主机隔离,也可以使容器共享主机或者其他容器的网络命名空间,基本可以满足开发者在各种场景下的需要。按docker官方的说法,docker容器的网络有五种模式:
网络模式 | 简介 |
Bridge(默认模式) | 此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。 |
Host | 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。 |
Container | 创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。 |
None | 该模式关闭了容器的网络功能,与宿主机、与其他容器都不连通的. |
2)默认网络
当你安装Docker时,它会自动创建三个网络(bridge、host、none)。你可以使用以下docker network ls命令列出这些网络:
[root@wuzz services]# docker network ls NETWORK ID NAME DRIVER SCOPE 5da77476c8f6 bridge bridge local b2da7db32740 host host local 7e8f0a766a4f nei macvlan local 2825bee1e7b8 net01 bridge local cf031282e138 net02 bridge local b5fb0af0aee1 none null local e71d75b6041c wuzzphy macvlan local |
我们在使用docker run创建Docker容器时,可以用 –net 选项指定容器的网络模式,Docker可以有以下5种网络模式:
bridge模式:使用 --net=bridge 指定,默认设置。
host模式:使用 --net=host 指定。
none模式:使用 --net=none 指定。
container模式:使用 --net=container:NAME_or_ID 指定。
macvlan
3)Bridge模式(默认方式)
当Docker server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
当创建一个 Docker 容器的时候,同时会创建了一对 veth pair接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0;另一端在本地并被挂载到docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。
图 2
示例:
# --net=bridge可以省略,默认模式 $ docker run --name=nginx_bridge --net=bridge -p 8080:80 -td nginx # 查看容器详情 $ docker inspect nginx_bridge # 筛选出容器IP $ docker inspect --format='{{.NetworkSettings.IPAddress}}' nginx_bridge |
图 3
对比一下宿主机/etc/hosts,不一样
$ docker exec nginx_bridge cat /etc/hosts $ cat /etc/hosts |
图 4
4)Host模式
相当于Vmware中的NAT模式,与宿主机在同一个网络中,但没有独立IP地址。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。可以通过 --net=host 指定使用 host 网络。
图 5
示例:
$ docker run --name=nginx_host --net=host -p 8081:80 -td nginx $ docker inspect nginx_host |
图 6
对比一下宿主机/etc/hosts,一模一样
$ docker exec nginx_host cat /etc/hosts $ cat /etc/hosts |
图 7
5)Container模式
Docker网络container模式是指定其和已经存在的某个容器共享一个 Network Namespace,此时这两个容器共同使用同一网卡、主机名、IP 地址,容器间通讯可直接通过本地回环 lo 接口通讯。但这两个容器在其他的资源上,如文件系统、进程列表等还是隔离的。
图 8
示例:
# 创建容器 $ docker run --name=busybox_container --net=container:nginx_bridge -td busybox $ 查看绑定容器的IP $ docker inspect --format='{{.NetworkSettings.IPAddress}}' nginx_bridge # 查看新创建容器的IP,上面这种方式查不出来 $ docker inspect --format='{{.NetworkSettings.IPAddress}}' busybox_container # 通过ifconfig查询ip $ docker exec busybox_container ifconfig |
图 9
六、None模式
容器有自己的网络命名空间,但不做任何配置,它与宿主机、与其他容器都不连通的。我们新建一个 none 模式的 busybox 镜像 b0:
示例:
$ docker run -dt --net=none --name busybox_none busybox # 查看它的网络状态, 验证它仅有 lo 接口,不能与容器外通信 $ docker exec busybox_none ip a |
图 10
6)Docker NAT iptables实现内外网络通信原理
默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器
【注意】如果容器的宿主机上的ip_forward未打开,那么该宿主机上的容器则不能被其他宿主机访问
【打开转发配置】
# 临时修改 $ echo 1 > /proc/sys/net/ipv4/ip_forward # 永久修改 $ echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf $ sysctl -p |
容器访问外部实现
容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址(即docker0地址)。这是使用 iptables 的源地址伪装操作实现的。
查看主机的 NAT 规则
$ iptables -t nat -vnL |
图 11
其中,上述规则将所有源地址在 172.17.0.0/16网段的包(也就是从Docker容器产生的包),并且不是从docker0网卡发出的,进行源地址转换(SNAT),转换成主机网卡的地址。
【科普】MASQUERADE:IP伪装,自动获取当前ip地址来做NAT
上面这么说可能不太好理解,举一个例子说明一下
当前主机有一块网卡为bond0,IP地址为192.168.182.152/24,网关为192.168.182.2。从主机上一个IP为172.17.0.10/16的容器中ping百度(180.76.3.151)。IP包首先从容器发往自己的默认网关docker0,包到达docker0后,也就到达了主机上。然后会查询主机的路由表,发现包应该从主机的bond0发往主机的网关192.168.182.2/24。接着包会转发给bond0,并从bond0发出去(主机的ip_forward转发应该已经打开)。这时候,上面的Iptable规则就会起作用,通过MASQUERADE IP伪装,自动获取bond0 ip地址来对包做SNAT转换,将源地址换为bond0的地址。这样,在外界看来,这个包就是从192.168.182.152上发出来的,Docker容器对外是不可见的。
查看路由表,可以看到是走默认路由
$ route -n # 或者 $ ip route |
图 12
容器访问外部流程图:
图 13
外部访问容器实现
容器允许外部访问,可以在 docker run 时候通过 -p 或 -P 参数来启用,不管用那种办法,其实也是在本地的 iptable 的 nat 表中添加相应的规则。
使用-P 时(使用 -P 标记时,Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口。):
$ docker run -d -P nginx $ docker run -d -p 8880:80 nginx $ iptables -t nat -nvL |
图 14
上面圈中的就是刚刚创建两个容器的端口转发规则,其中,上述的规则映射了 0.0.0.0,意味着将接受主机来自所有接口的包,并且不是从docker0网卡导入的,进行目的地址转换(DNAT),转换成容器网卡的地址。
外部访问容器流程图:
图 15
2.5 NAT(SNAT和DNAT)企业实战备案
1)目标
掌握iptables防火墙的配置
掌握firewalld防火墙的配置
掌握服务的访问控制列表
掌握利用iptables实现NAT
2)背景
假如某公司需要Internet接入,由ISP分配IP地址202.112.113.1。采用iptables作为NAT服务器接入网络,内部采用100.100.100.0/24地址,外部采用202.112.113.1地址。为确保安全需要配置防火墙功能,要求内部仅能够访问intrasvr、natsvr及intersvr台服务器;内部intersvr服务器100.100.100.221通过端口映射方式对外提供服务。网络拓扑如下图所示。
表6.1 IP规划
主 机 名 称 | 操作系统 | IP地址 |
内网服务器intrasvr | Centos 8 | 100.100.100.221(VMnet1) |
natsvr | Centos 8 | IP1: 100.100.100.220(VMnet1) IP2:202.112.113.1(VMnet4) |
intersvr | Centos 8 | 202.112.113.113(VMnet4) |
3)要求
1. 配置SNAT保证内网用户能够正常访问公网IP。
2. 配置DNAT保证外网用户能够正常访问内网的SSH服务器。
3. 配置iptables防火墙
4)步骤:
注意:请保证物理机连上互联网的情况下,在intrasvr、natsvr两台服务器上安装iptables和iptables-servies两个软件包,以便后续使用。
i准备工作
主机上安装两张Microsoft KM-TEST虚拟网卡(网段设置为202.112.113.0/24)作为充当外网,命名为wai,其配置如图6.17所示;
按表6.1规划容器的网络连接
规划容器连接网络
192.168.0.0/24模拟内网,202.112.113.0/24模拟外网
表6.2 对应的容器网络规划
网络/容器 | Ip | 连接特性 | 端口 | 安装包 |
Nei | 100.100.100.0/24 | Macvlan/ens37 | ||
Wai网卡 | 202.112.113.0/24 | macvlan/ens38 | ||
Intra-svr容器 | 100.100.100.221/24 | Gateway:192.168.0.24 firewalld、iptables和iptables-servies | ||
Nat-svr容器 | 100.100.100.220/24 202.112.113.1/24 | firewalld、iptables和iptables-servies | ||
Inter-svr容器 | 202.112.113.113/24 |
图 17
先在centos8主机上配置vmnet1、vmnet4网段设置,做好本地yum源部署,并测试和外网连通性。
图 18
创建两个macvlan网卡:nei、wai
|
|
docker network create -d macvlan --subnet=192.168.0.0/24 --ip-range=192.168.0.0/24 -o macvlan_mode=bridge -o parent=ens32 macvlan |
Docker network create –d macvlan 创建的网络类型为macvlan,-d为指定驱动 |
--subnet=192.168.0.0/24 --ip-range=192.168.0.0/24 指定子网和ip范围 |
macvlan_mode=bridge |
-o parent=ens32 给容器分配ip的母卡 |
macvlan 命名 |
查看网络
[root@wuzz ~]# docker network ls c6181cd64876 bridge bridge local b2da7db32740 host host local ae132c7e699e mywifi macvlan local 5445b73edf3f nat macvlan local 7e8f0a766a4f nei macvlan local b5fb0af0aee1 none null local d0c49adde8b4 wai macvlan local |
可以看见网卡创建成功了。
5)创建intrasvr、natsvr、intersvr三个容器
docker run -itd -e “container=docker” --privileged=true -v /sys/fs/cgroup:/sys/fs/cgroup -v /wutool:/wutool -v /mnt:/mnt -v /etc/yum.repos.d:/etc/yum.repos.d --net nei --ip 100.100.100.221 --name intrasvr centos /usr/sbin/init docker run -itd -e “container=docker” --privileged=true -v /sys/fs/cgroup:/sys/fs/cgroup -v /wutool:/wutool -v /mnt:/mnt -v /etc/yum.repos.d:/etc/yum.repos.d --net nei --ip 100.100.100.220 --name natsvr centos /usr/sbin/init docker run -itd -e “container=docker” --privileged=true -v /sys/fs/cgroup:/sys/fs/cgroup -v /wutool:/wutool -v /mnt:/mnt -v /etc/yum.repos.d:/etc/yum.repos.d --net wai --ip 202.112.113.113 --name intersvr centos /usr/sbin/init |
查看容器
图 19
启动三个容器
[root@wuzz ~]# docker start intrasvr intersvr natsvr intrasvr intersvr natsvr |
复制3个ssh登录窗口,2、3、4,然后在三个窗口中分别登录容器
图 20
docker exec -it intrasvr /bin/bash |
查看ip,更新yum源
图 21
失败了!看错误好像要到ali网站的docker中心去报到,而我们的容器都是虚拟网模拟的,无法连外网。
图 22
宿主机是可以连外网的,网络有个nat网络是连接外网的,我们在centos主机上给三个容器连外网:
[root@wuzz ~]# docker network connect nat intrasvr |
图 23
更新
[root@8753cfda310e /]# yum clean all Failed to set locale, defaulting to C.UTF-8 0 files removed [root@8753cfda310e /]# yum makecache Failed to set locale, defaulting to C.UTF-8 Docker CE Stable - x86_64 235 kB/s | 66 kB 00:00 LocalRepo_BaseOS 60 MB/s | 2.6 MB 00:00 LocalRepository_AppStream 68 MB/s | 7.5 MB 00:00 Metadata cache created. |
安装必要工具(最好所有的容器上都安)
[root@8753cfda310e /]# yum install -y net-tools NetworkManager firewalld iptables-services openssh-clients |
给容器intrasvr增加网关100.100.100.220
route add default gw 100.100.100.220 |
此时可以断掉intrasvr和natsvr的nat网络
docker network disconnect wai natsvr |
将natsvr连接wai网,该服务器从外网获得了dhcp分配的ip(目前还不知道怎么更改☹)
图 24
在intrasvr上可以ping natsvr的两个ip但是无法ping通外网intersvr,即
[root@intrasvr~]# ping 100.100.100.220 //通 [root@ intrasvr~]# ping 202.112.113.1 //通 [root@ intrasvr~]# ping 202.112.113.113 //不通 |
图 25
(1)配置SNAT
在intrasvr和natsvr上关闭firewalld,启动iptables
[root@ nat-server ~]# systemctl stop firewalld [root@ nat-server ~]# systemctl start iptables |
在natsvr上配置配置防火墙SNAT
[root@862b11cc5d84 /]# cat /proc/sys/net/ipv4/ip_forward |
确认开启路由存储转发,其值为1。如果为0,则执行:
[root@862b11cc5d84 /]# echo 1 > /proc/sys/net/ipv4/ip_forward |
清空filter表,查看filter表和nat 表:
[root@862b11cc5d84 /]# iptables -F [root@862b11cc5d84 /]# iptables -L [root@862b11cc5d84 /]# iptables -t nat -L |
配置SNAT转换
[root@862b11cc5d84 /]# iptables -t nat -A POSTROUTING -s 100.100.100.0/24 -j SNAT --to-source 202.112.113.1 [root@862b11cc5d84 /]# iptables -t nat -L Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain INPUT (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination DOCKER_POSTROUTING all -- anywhere 127.0.0.11 SNAT all -- 100.100.100.0/24 anywhere to:202.112.113.1 Chain OUTPUT (policy ACCEPT) target prot opt source destination DOCKER_OUTPUT all -- anywhere 127.0.0.11 Chain DOCKER_OUTPUT (1 references) target prot opt source destination DNAT tcp -- anywhere 127.0.0.11 tcp dpt:domain to:127.0.0.11:46007 DNAT udp -- anywhere 127.0.0.11 udp dpt:domain to:127.0.0.11:54050 Chain DOCKER_POSTROUTING (1 references) target prot opt source destination SNAT tcp -- 127.0.0.11 anywhere tcp spt:46007 to::53 SNAT udp -- 127.0.0.11 anywhere udp spt:54050 to::53 |
图 26
在内网intrasvr上测试SNAT配置是否成功
图 27
测试内网ping公网
[root@8753cfda310e /]# ping www.baidu.com -c 2 PING www.a.shifen.com (183.2.172.42) 56(84) bytes of data. 64 bytes from 183.2.172.42 (183.2.172.42): icmp_seq=2 ttl=127 time=30.3 ms --- www.a.shifen.com ping statistics --- 2 packets transmitted, 1 received, 50% packet loss, time 1062ms rtt min/avg/max/mdev = 30.323/30.323/30.323/0.000 ms |
转了几次后,时延有点大。
route add default gw 100.100.100.220 docker network connect wai natsvr |
(2)配置DNAT
情景描述:如果外网要登录natsvr的话,自动转换目的地址202.112.113.1到100.100.100.221的SSH服务上。
由于docker安装的容器不支持SSH登录,需要做ssh服务器架设:
[root@8753cfda310e /]# yum install passwd openssl openssh-server initscripts -y |
编辑/etc/ssh/sshd_config,注意红色部分,没有的就自行添加
…… Port 22 AddressFamily any ListenAddress 0.0.0.0 #ListenAddress :: HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_ecdsa_key HostKey /etc/ssh/ssh_host_ed25519_key # Ciphers and keying #RekeyLimit default none # This system is following system-wide crypto policy. The changes to # crypto properties (Ciphers, MACs, ...) will not have any effect here. # They will be overridden by command-line options passed to the server # on command line. # Please, check manual pages for update-crypto-policies(8) and sshd_config(5). # Logging #SyslogFacility AUTH SyslogFacility AUTHPRIV #LogLevel INFO # Authentication: #LoginGraceTime 2m PermitRootLogin yes PermitEmptyPasswords yes #StrictModes yes #MaxAuthTries 6 #MaxSessions 10 PubkeyAuthentication yes |
#重启ssh
[root@8753cfda310e /]# service sshd restart Redirecting to /bin/systemctl restart sshd.service [root@8753cfda310e /]# systemctl start sshd.service [root@8753cfda310e /]# systemctl enable sshd.service [root@8753cfda310e /]# passwd root Changing password for user root. New password: BAD PASSWORD: The password is shorter than 8 characters Retype new password: passwd: all authentication tokens updated successfully. |
查看intrasvr上ssh是否正常启动,并禁用firewalld
[root@8753cfda310e /]# systemctl status sshd ● sshd.service - OpenSSH server daemon Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2024-09-25 02:56:40 UTC; 10min ago Docs: man:sshd(8) man:sshd_config(5) Main PID: 378 (sshd) Tasks: 1 (limit: 36801) Memory: 1.1M CGroup: /docker/8753cfda310eddda30a4972171c0d81866aa81acf9eaf82911359fce815bc912/system.slice/sshd.service └─378 /usr/sbin/sshd -D -oCiphers=aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@o> Sep 25 02:56:40 8753cfda310e systemd[1]: Starting OpenSSH server daemon... Sep 25 02:56:40 8753cfda310e sshd[378]: Server listening on 0.0.0.0 port 22. Sep 25 02:56:40 8753cfda310e systemd[1]: Started OpenSSH server daemon. [root@8753cfda310e /]# systemctl stop firewalld |
开启iptables防火墙,并清空filter表,并查看filter表
[root@8753cfda310e /]# systemctl start iptables [root@8753cfda310e /]# iptables -F [root@8753cfda310e /]# iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination |
在filter表INPUT链中添加规则
[root@8753cfda310e /]# iptables -A INPUT -p tcp --dport 22 -j ACCEPT |
在防火墙nat-server上配置DNAT
iptables -t nat -A PREROUTING -d 202.112.113.1 -p tcp --dport 22 -j DNAT --to-destination 100.100.100.221:22 |
在intersvr上远程登录docker容器查看配置是否生效:
[root@31266148573b /]# ssh 202.112.113.1 The authenticity of host '202.112.113.1 (202.112.113.1)' can't be established. ECDSA key fingerprint is SHA256:znFk2vrW6z+IVAOkcLksG7/MBONE7ra1OQtTjEjKEEA. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '202.112.113.1' (ECDSA) to the list of known hosts. root@202.112.113.1's password: [root@8753cfda310e ~]# |
图 28
至此,完成了基于docker容器的防火墙基本配置和NAT部署