ipsec_vpn&docker

Docker环境下IPsec配置实验

选用Docker的原因

实验要求一台主机和四台虚拟机,硬件条件不允许,只好选用docker来代替。

Docker

第一次接触Docker,之前只知道Docker是一种容器化技术

Docker 和虚拟机的区别

同为虚拟技术,区别如下:

  • 容器和宿主机共享kernel,即宿主机的kernel就是容器的kernel
  • 虚拟机有独立的文件、进程、内存系统,而容器只是做了隔离,Docker是进程之间的隔离,而虚拟机可以实现系统级别的隔离
  • 容器管理和虚拟机管理在速度上有很明显的差距,虚拟机可以做到10台/min,而Docker容器的创建是秒级别的

docker_vm

Docker Engine

Docker Engine属于Docker的运行层。这是一套轻量化运行时及工具组合,负责管理容器、镜像、构建 等等。它以原生方式运行在Linux系统之上,并由以下元素构成:

  • Docker Daemon,运行在主机之上的程序
  • Docker Client,负责与Docker Daemon通信以执行命令,Docker采用的是CS模式
  • REST API,用于同Dockers Daemon远程交互

    Docker 核心概念

Image 镜像

image 就类似虚拟机的镜像文件,可以用于创建容器

Container 容器

容器就是运行的单位,从镜像启动。Docker 会在镜像的最上一层创建一个可写层,镜像本身是只读的,保持不变

Repository 仓库

仓库是用来存放一类镜像的地方

docker_vm

Docker 四种网络模式(部分转载)

实现原理:

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0,对应连接网卡是eth0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信(可以理解为一个公共网段,每个容器的eth0网卡都在网段上)。

Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。

四类网络模式
Docker网络模式 配置 说明
host模式 –net=host 容器和宿主机共享Network namespace。
container模式 –net=container:NAME_or_ID 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。
none模式 –net=none 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。
bridge模式 –net=bridge (默认为该模式)
host

如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。

container

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

none

使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。

这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过–network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

bridge

当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。

从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。

bridge模式是docker的默认网络模式,不写–net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。

Dockerfile

一个用来构建镜像的文本文件,一般分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动时执行指令,前三部分对应三个指令:FROM ;MAINTAINER; RUN。

注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

1
2
3
4
FROM centos
RUN yum install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz

以上执行会创建 3 层镜像。可简化为以下格式:

1
2
3
4
FROM centos
RUN yum install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz

如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。

构建好后,由新构建的镜像启动容器即可。

容器抓包

基本的ipsec配置过程不再赘述,搭建好网络拓扑,配置好网关,按照 这上面 的配置文件(修改下right和left的IP、掩码)就🆗,然后是抓包分析协议。

抓包时遇到了一个问题,在容器内部,用tcpdump抓包时,遇到了这样的问题:

1
Couldn't change ownership of savefile

应该是容器内部访问文件的问题,网上有关于apache中使用tcpdump出现同样问题的情况,采取同样措施(关闭宿主机的SELinux)仍然无法解决时,采取了第二种方案:在宿主机抓包。

因为Docker技术主要是依赖Linux Namespace 技术来实现,可以在宿主机中切换到对应容器的网络命名空间来抓包。

步骤:
  • 首先由容器ID获取容器进程pid:
1
docker ps | grep xxx
  • 使用nsenter切换网络命名空间
1
nsenter -n -t container_id/name

直接抓包即可,最后确实抓取到了ipsec的流量:

IKEv1:

ikev1

IKEv2:

ikev2