在前一篇小编介绍了Ubuntu下安装docker如何进行端口绑定,阐述了直接这样绑定端口容易造成入侵问题,今天我们就来使用认证书来解决这个问题。

 

现在Docker Java API默认的连接方式就是基于签名证书认证的。如果我们的Docker没有签名认证过,Docker Java是无法连接到Docker的,也就是说,要想连Docker,必须做签名认证。

证书的生成详细信息。移步官网

Protect the Docker daemon socket(https://docs.docker.com/engine/security/https/#create-a-ca-server-and-client-keys-with-openssl)。其原理是通过指定tlsverify标志并将Docker的tlscacert标志指向受信任的CA证书来启用TLS。在守护进程模式下,它只允许来自由该CA签名的证书认证的客户端的连接。 在客户端模式下,它将只连接到具有由该CA签名的证书的服务器。

现在我们将认证流程简化一下。

下列一系列的命令,让我们可以生成认证证书。注意:下面这些TLS命令将只在Linux上生成一组有效的证书。 macOS附带的OpenSSL版本与Docker所需的证书不兼容。我没有Mac笔记本,所以没有机会试一试,请大家自行试试吧。

第一步:

 

首先,我们需要选择一个放证书的文件夹,这个文件夹很多文章,包括官网都建议创建一个.docker文件夹,我个人认为,这个文件夹在哪里不重要,只要能保证服务器安全,防火墙有效,就可以了。

我在/home/user/下面创建了一个/certs/文件夹。用$pwd,就可以看到该文件夹是/home/user/certs/。转到该文件夹,

执行如下命令:$ openssl genrsa -aes256 -out ca-key.pem 4096,

生成CA私钥,并设置pass phrase,我设置的就是123456,比较简单,因为是测试环境。但是要记住这个密码,后边命令还会用到。

再输入:$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem,

生成CA公钥,也就是证书。还让你输入国家名,省名啥的,这些都是随便填一个就行,因为密钥算法会把这些信息加密进密钥的。值得一提的是Common Name,说是要你填写,server FQDNyour  name,意味着可以随便写,但是我在这里建议,写Docker所在服务器的IP,这个很重要。这个IP后边还会用到,我这里是192.168.99.101,在生产环境下,用使用你docker宿主机的DNS name替换下面的填入Common name,如api.google.com等,这个IP不难拿到,你用$ifconfig命令就可以拿到。我在这里填CDH是错误的

第二步:

 

生成服务器私钥,命令如下:

$openssl genrsa -out server-key.pem 4096

再用私钥生成服务器公钥请求文件,也就是证书,命令如下:

$openssl req -subj "/CN=192.168.99.101" -sha256 -new -key server-key.pem -out server.csr, 

这里的192.168.99.101同样是Docker所在服务器的IP,你不要照抄,用自己的Docker服务器替换上去。

下面我们可以用CA来签署证书了。这里我们可以填写IP地址或则DNS name,如,我们需要允许10.10.10.20和127.0.0.1连接:

$echo subjectAltName = IP:10.10.10.20, IP:127.0.0.1 > extfile.cnf,

上述命令有点像一个过滤器,如果地址填的不全,远程API就无法访问该Docker,那么我们就把,地址填的全一些,我的命令是这样滴:

$echo subjectAltName = DNS:192.168.99.101, IP: 192.168.99.101, IP: 192.168.1.101, IP:0.0.0.0, IP:127.0.0.1 > extfile.cnf

然后,将上述多个生成信息,写入文件。用如下命令。

$openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf

再看客户端私钥:

$openssl genrsa -out key.pem 4096

下一步再生成客户端证书请求文件:

$openssl req -subj '/CN=client' -new -key key.pem -out client.csr

用CA为客户端签署证书文件:

$openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf

这时候,还需要输入你的密码,我的密码是123456,输上去即可。

第三步:使用证书

 

还是要回到我们上文提到的docker.service文件中,那个文件里需要添加上你为它生成的文件的路径和文件名。如下图红色方框所示:

 

字比较小啊看不清。嗯,我们来把它放大:

ExecStart=/usr/bin/dockerd -D --tlsverify=true --tlscert=/home/user/certs/server-cert.pem --tlskey=/home/user/certs/server-key.pem --tlscacert=/home/user/certs/ca.pem -H tcp://0.0.0.0:2376  -H fd://

注意到没有,我这里把所有的认证文件都加上了准确的路径。用Ctrl+X,按Y保存退出。

再重新装载配置文件

$sudo systemctl daemon-reload,回车

$sudo service docker restart,回车

$sudo service docker status,来查看进程状态。

第四步:客户端签名证书设置

 

在home/user/certs文件夹下下载几个文件,放到我的本地机上d:/data/certs/文件夹下,如下图蓝色方框部分,这样Java客户端就可以通过这些证书来访问Docker服务器了

第五步:使用证书来访问

程序代码段

 

public class DockerJavaClient {

public DockerJavaClient() {

}

public static void main(String[] args) {

DockerCmdExecFactory dockerCmdExecFactory = new JerseyDockerCmdExecFactory().withReadTimeout(1000)
        .withConnectTimeout(1000).withMaxTotalConnections(100).withMaxPerRouteConnections(10);

DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerTlsVerify(true)

.withDockerCertPath("D:/Data/cert/").withDockerHost("tcp://192.168.99.101:2376")

.withDockerConfig("D:/Data/cert/").withApiVersion("1.23").withRegistryUrl("https://index.docker.io/v1/")

.withRegistryUsername("username").withRegistryPassword("password")

.withRegistryEmail("email").build();

//根据自己的情况,按需填写

DockerClient dockerClient = DockerClientBuilder.getInstance(config)

.withDockerCmdExecFactory(dockerCmdExecFactory).build();

CreateContainerResponse container1 = dockerClient.createContainerCmd("tomcat:latest").exec();

dockerClient.startContainerCmd(container1.getId()).exec();

}

至此,我们的Docker访问就配置成功了。

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐