Keep learning, keep living...

0%

在Kubernetes节点上安装我们的流量检测模块之后所有的Pod会断网。经分析是由于流量检测模块的NFQUEUE机制与kube-proxy使用的iptablesmark机制冲突的原因。

在Linux内核中,网络数据包是由sk_buff结构来表示的,一般数据包简写作SKBmarksk_buff结构的一个字段, 如(include/linux/skbuff.h):

1
2
3
4
5
6
7
8
struct sk_buff {
...
union {
__u32 mark;
__u32 reserved_tailroom;
};
...
}

mark并不是网络协议结构的部分,不会存在于任一层协议头中,而是Linux网络子系统用于在主机内部传递状态信息的标记机制。各种网络应用可以根据自身需要使用该字段来实现自身的状态传递。

这个mark机制主要用在netfilter框架中,所以也叫nfmark。除了它之外,内核中还有conntrack模块也有自己的mark机制,一般叫做ctmark

之前的文章<<基于IPTABLES MARK机制实现策略路由>>也介绍过iptablesMARK模块,可以用于修改和匹配数据包的mark值。

NFQUEUE机制可以在内核中将数据通过NFQUEUE通道将数据包送往用户态,在用户态进行安全检测,再将裁决(verdict)结果送回内核。之前的文章<<NFQUEUE和libnetfilter_queue实例分析>>介绍了libnetfilter_queue库的简单用法。我们的流量检测程序会使用libnetfilter_queue库中的nfq_set_verdict2在返回verdict的同时,设置数据包的mark值,以传递更多的信息给内核模块,函数原型如下:

1
2
3
4
5
6
7
int nfq_set_verdict2(struct nfq_q_handle *  qh,
uint32_t id,
uint32_t verdict,
uint32_t mark,
uint32_t data_len,
const unsigned char* buf
)

这就会导致数据包sk_buff结构的mark值被设置。而kube-proxy实现也依赖iptablesmark机制, 会在主机上添加如下iptables规则:

1
2
3
-A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000
...
-A KUBE-FIREWALL -m comment --comment "kubernetes firewall for dropping marked packets" -m mark --mark 0x8000/0x8000 -j DROP

对于不合法的报文,kube-proxy会给相应报文标记0x8000/0x8000, 之后通过KUBE-FIREWALL规则链将数据包丢弃。

如果我们的流量检测程序所设置的mark值设置为kube-proxy所依赖的0x8000位,就会导致数据包被丢弃。

阅读全文 »

在一些服务器安全场景中,需要通过网络连接关联到相关进程。例如,在安全溯源场景中,通过威胁情报可以判断某台主机上存在恶意连接,这时就需要追查这些恶意连接是由哪个进程以及哪个可执行文件来发起的。又或者,在微隔离场景中,我们不仅仅需要知道IP:PortIP:Port之间的访问关系,我们还需要额外增加进程级别的信息,也就是哪个进程通过IP:Port在访问IP:Port的哪个进程。

要解决这种网络连接与进程关联的问题,在用户态的可行办法主要是通过读取/proc/net/tcp以及/proc/[pid]/fd这两种文件来构建相应的映射结构。

通过读取文件/proc/net/tcp可获取系统的TCP连接信息:

1
2
3
4
5
6
[root@centos3 tcpconn]# cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000:006F 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 13841 1 ffff9fc7da7c8000 100 0 0 10 0
1: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 16863 1 ffff9fc7da7c87c0 100 0 0 10 0
2: 0100007F:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 17951 1 ffff9fc7da7c9f00 100 0 0 10 0
3: 0F02000A:0016 0202000A:F3FE 01 00000000:00000000 02:000AF352 00000000 0 0 23961 4 ffff9fc7da7c8f80 20 4 25 10 -1

从其中可获取TCP连接四元组及对应socket的inode号。

而从/proc/[pid]/fd中可以获取进程所有的文件描述符:

1
2
3
4
5
6
7
[root@centos3 tcpconn]# ls -l /proc/823/fd
total 0
lr-x------. 1 root root 64 Jul 24 15:06 0 -> /dev/null
lrwx------. 1 root root 64 Jul 24 15:06 1 -> socket:[16389]
lrwx------. 1 root root 64 Jul 24 15:06 2 -> socket:[16389]
lrwx------. 1 root root 64 Jul 24 15:06 3 -> socket:[16863]
lrwx------. 1 root root 64 Jul 24 15:06 4 -> socket:[16939]

其中也可以获取相应的inode号.

这样,我们就可以从/proc/net/tcp建立起网络连接五元组->inode的映射, 再从/proc/pid/fd建立起连接inode->进程的映射。从而实现网络连接关联到相应进程。

但这种方式整个映射关系的建立依赖周期性读取两种proc文件,缺乏实时性,对于瞬时连接相应的数据可以无法实时获取到,从而无法关联到进程。

阅读全文 »

CNI: Container Network Interface是配置Linux容器网络接口的一种规范。它将容器运行时和容器网络实现解耦,使容器网络实现成为可插拔的插件。在不同的容器运行时环境中,容器网络实现可以复用。而在不同的网络环境中,也可以灵活的插拔不同的网络实现。

CNI规范主要涉及容器运行时CNI插件两个角色,规范约定了二者的交互方式。容器运行时在容器实例创建时调用CNI插件的ADD接口以创建容器络连接所需的资源网络连接,当容器删除时调用CNIDEL接口移除所创建的相应资源完成资源释放。不同的CNI插件按照规范所统一定义的接口、参数、响应实现不同的网络方案。

官方提供了开发库libcni容器运行时可以使用该库来集成CNI能力,并且还提供了一系列的CNI插件参考实现

目前CNI规范的最新版本为0.4.0

从具体实现上看,容器运行时会先创建好相应的network namespace, 然后CNI插件负责将网络接口插入到容器实例的network namespace、在宿主机上做必要的网络操作(如绑定IP到接口、建立路由等)以实现容器网络连通。

一般设计中,主体模块与插件之间的交互会采用RPC、二进制兼容的动态库加载等手段。CNI规范则指定CNI插件实现为可执行程序,相应接口参数通过环境变量与标准输入流传给CNI插件,类似于早年WEB领域的CGI模式。

阅读全文 »

之前的文章<<NSX分布式逻辑路由器介绍>>简要介绍了NSX-V(NSX for vSphere)中的分布式逻辑路由器。NSX-V只支持vSphere平台,对VMware vCenter强依赖。NSX-T是针对异构虚拟化平台以及多Hypervisor环境来设计的,不仅支持vSphere平台,还支持KVM、Docker、Kubernetes等平台。当前来看,NSX-T更像是VMware未来的主要投入方向。这篇文章很透彻地介绍了NSX-VNSX-T的差别,但文章中的内容是基于NSX-T2.3版本,当前已经是3.0, 有些内容已经不太适用。

NSX-T的路由实现与NSX-V有较大不同,本文来简要介绍NSX-T平台下逻辑路由器的概念。

NSX-T中,逻辑路由器分为Tier-0网关和Tier-1网关。Tire-0网关用于连接NSX-T虚拟网络与外部网络,主要处理南北向路由。Tier-1网关用于处理不同分段: Segment(以前版本叫做逻辑交换机: Logical Switch, 虚拟二层网络)之间的东西向路由。从概念上来看,Tire-1网关对应NSX-V中的LDR: Logical Distributed Router, Tire-0对应NSX-V中的ESG: Edge Service Gateway

典型的部署结构如下图, 图片来自VMware官方博客:

阅读全文 »

NSX是VMware公司在vSphere平台上的网络虚拟化解决方案。从架构上分为四层, 如图:

  • 消费平面: 云管平台CMP(Cloud Management Platform)不是NSX的组件,NSX提供了丰富的REST API, 可根据需要集成NSX。
  • 管理平面: NSX Manager是NSX的集中管理器,主要功能包括管理NSX Controller集群,管理EDGE节点,为上层消费平台提供管理和配置接口。NSX Manager自身实现了vSphere vCenter插件,可注册在vCenter中,通过GUI进行管理。
  • 控制平面: 控制平台主要包括NSX Controller集群,Controller负责维护所有ESXi主机、逻辑交换机(Logical Switch)和分布式逻辑路由器(DLR: Distributed Logical Router)的信息。实际上,控制平面还包括DLR的Control VM, 上图中没有体现。上图来自官方6.4版本的文档。后文会再介绍它的作用。
  • 数据平面: 数据平面主要包括NSX Virtual Switch, DLR, 和ESG: Edge Service Gateway。按图中表示,NSX Virtual Switch是基于vSphere的分布式交换机并在内核中实现VXLAN、防火墙过滤、分布式路由等功能的逻辑交换机。我个人更倾向将NSX Virtual Switch理解为VDS+VXLAN实现,将DLR看成独立组件。VDS可以理解为基于VLAN隔离的虚拟交换机,NSX Virtual Switch是基于VXLAN隔离的虚拟交换机。NSX界面上,NSX Virtual Switch叫做逻辑交换机: Logical SwitchDLRESG都是路由器,DLR负责虚拟数据中心中东西向流量路由,ESG负责虚拟数据中心边缘的南北向流量路由。其他数据面组件都在ESXi主机内核中实现,而ESG是独立的虚拟机。 NSX的一个典型逻辑网络架构如下图:
阅读全文 »

很多业务场景都需要在后台定期执行任务,如数据ETL(Extract-Transform-Load)操作。简单处理可通过crontab来管理。当任务需要在多台机器上执行,或者任务之间有依赖关系时,crontab便不太能满足需求。这种场景下需要分布式任务调度系统来组织任务编排,管理任务依赖,调度任务工作流和监视任务执行状态。

比较优秀的开源解决方案有:

Azkaban和Oozie都更聚集在大数据处理平台上的任务调度,Airflow的应用场景更为通用。本文简单介绍Airflow。

Airflow使用Python开发,它通过DAGs(Directed Acyclic Graph, 有向无环图)来表达一个工作流中所要执行的任务,以及任务之间的关系和依赖。比如,如下的工作流中,任务T1执行完成,T2T3才能开始执行,T2T3都执行完成,T4才能开始执行。

阅读全文 »

互联网服务为了保证高可用和可扩展性,在流量入口一般都需要部署负载均衡设备。负载均衡设备可分为4层(传输层)和7层(应用层)。L4负载均衡设备之前较为流行的方案是LVS,后来各大厂商又基于DPDKXDP/eBPF等技术实现了性能更高的一些方案, 如:

无论以上哪种实现,流量分发的部署方案都类似, 都是由LB集群中多个服务器通过BGP或者OSPF协议向网络设备宣告相同的IP地址(VIP),网络设备通过ECMP路由将流量分散到这些服务器中。当其中某些LB服务器异常宕机或者维护下线时,网络设备会通过OSPF或者BGP协议的路由收敛机制检测到LB服务器下线,迅速将流量切走, 实现服务高可用。

本文来实验基于ECMPOSPF的负载均衡。Cumulus是一个基于Linux的网络操作系统(NOS:Network Operation System), 运行于白牌交换机上。Cumulus VX是Cumulus的免费虚拟设备,可以以虚拟机形式运行。本文就使用Vagrant, VirtualBox, Ubuntu, Cumulus VX来构建我们的实验拓扑。结构如图:

阅读全文 »

VXLAN现在主要有以下几种类型的控制面:

  • 基于集中的SDN控制器
  • 基于IP多播实现洪泛与学习
  • 基于单播的HER(Head-End Replication)洪泛与学习,即在入口VTEP处实现包复制,通过单播发送给需要洪泛的所有VTEP
  • 基于BGP EVPN(Ethernet Virtual Private Network)

VMware NSX方案是基于SDN控制器。而之前的两篇关于VXLAN的文章<<动态维护FDB表项实现VXLAN通信>>和<<VXLAN原理介绍与实例分析>>中, 我们实验的方式是基于多播和单播的方案。本文我们来介绍基于BGP EVPN的VXLAN控制面。

BGP EVPN是一个标准的控制面协议,由RFC7432定义。它支持三种数据面: MPLS、PBB、NVO(Network Virtualization Overlay)。VXLAN是NVO方案中的一种,它的EVPN应用由RFC8365定义。BGP EVPN依赖BGP协议MP-BGP扩展。BGP是支撑互联网的主要协议,用于在网络设备之间同步路由信息。MP-BGP扩展能够将BGP所同步信息扩展到多种协议,如IPv4, IPv6, L3VPN和EVPN等。EVPN地址族用来传递MAC地址以及这些MAC地址所挂接的设备IP。

阅读全文 »

之前的文章<<VXLAN原理介绍与实例分析>>简要介绍了VXLAN的基本概念和基于组播的通信过程实例。其中控制面是混合在数据面中的,由洪泛(flood)和源地址学习实现。本文通过实例将控制面从数据面中分离,手动维护FDBARP表项实现通信过程。

对于大规模的VXLAN网络中,最核心的问题一般有两个:

  1. 如何发现网络中其他VTEP
  2. 如何降低BUM(Broadcast, Unknown unicast, Multicast)流量

在对于问题一来说,之前的文章中的解决方法是洪泛,对于问题二,则通过源地址学习来确定MAC地址的归属。VXLAN的转发过程主要依赖FDB(Forwarding Database)实现。二层网桥的FDB表项格式可表达为:

1
<MAC> <VLAN> <DEV PORT>

VXLAN设备的表项与之类似,可以表达为:

1
<MAC> <VNI> <REMOTE IP>

VXLAN设备根据MAC地址来查找相应的VTEP IP地址,继而将二层数据帧封装发送至相应VTEP。

如果我们能够从集中的Controller或者存储中获取VTEP信息以及MAC地址与VTEP的对应信息,则问题一和问题二都可以通过根据相应信息动态更新FDB表项来解决,OpenStack的Neutron, VMware的NSX,Docker Overlay都有类似的思路。

下面我们通过实例来手动更新FDB表来实现VXLAN通信。我们的实验环境如下图, VTEP本地使用Linux bridge来挂载连接到network namespace中的veth pair虚拟网卡,我们要实现3.3.3.3二层访问3.3.3.4

阅读全文 »

应用服务常常需要存取各种各样的机密信息,比如,数据库的访问凭证,依赖的外部服务的TokenKey,服务之间的通信凭证等等。在每个这样的应用中都重复实现机密信息的存取、更新与吊销等管理操作相当繁重,而且容易出问题。HashiCorp公司的开源项目Vault就将这部分工作以独立服务方式来实现,需要机密信息操作的应用可以与Vault服务交互完成相应的操作。

Vault的应用场景非常广泛,如:

  • 机密信息存取
  • 凭证的动态生成,比如数据库凭证、PKI证书、公有云服务的凭证等等
  • 加密即服务

Vault架构非常清晰,如下图所示,主要分为三部分:

  • HTTP/S API: Vault服务对外提供HTTP API接口
  • Storage Backend: 负责加密数据的持久化存储, Vault支持多种存储机制。
  • Barrier: 负责各种机密信息相关的处理逻辑,最核心的组件是Secrets EngineAuth MethodSecrets Engine负责实际机密信息处理功能的实现,各种不同的Secrets Engine有着不同的功能服务,Auth Method提供各种不同的身份校验方法。这两个组件都依赖Plugin机制实现,如果官方提供的功能不满足需求,还可以自己写相应Plugin实现特有功能或身份校验方法。
阅读全文 »