一、生成tls脚本
#!/usr/bin/env bash
# -------------------------------------------------------------
# 自动创建 Docker TLS 证书
# -------------------------------------------------------------
:<<!
author: lanwp
date: 2019/4/17
des: docker tls数字证书创建。
subjectAltName 不设置服务器端subjectAltName不设置(不校验 serverIP,所有服务器均可用)
subjectAltName 设置多个 subjectAltName = DNS:docker166,IP:192.168.72.166,IP:127.0.0.1
自动创建 Docker TLS 证书
服务器证书
ca.pem
server-cert.pem
server-key.pem
客户端使用
cert.pem
ca.pem
key.pem
!
PASSWORD="123456" #私钥密码
DAYS=36500
#IP=""
COUNTRY="CN"
STATE="省" # 省 可选
CITY="市" # 市 可选
ORGANIZATION="公司名称" # 组织 可选
ORGANIZATIONAL_UNIT="Dev" # 组织-单位可选
COMMON_NAME="test" # 域名或者IP,必须填写
EMAIL="test@163.com" # 可选 test@163.com
function noCode() {
#---
# 创建ca-key.pem 和 ca.pem
#openssl genrsa -out ca-key.pem 4096
openssl genrsa -aes256 -passout "pass:${PASSWORD}" -out ca-key.pem 4096 # -passout "pass:$PASSWORD" 不用输入私钥privateKey
openssl req -new -x509 -days ${DAYS} -key "ca-key.pem" -sha256 -out "ca.pem" -passin "pass:${PASSWORD}" -subj "/C=${COUNTRY}/ST=${STATE}/L=${CITY}/O=${ORGANIZATION}/OU=${ORGANIZATIONAL_UNIT}/CN=${COMMON_NAME}/emailAddress=${EMAIL}"
#---
# Generate Server key
openssl genrsa -out "server-key.pem" 4096
# Generate Server Certs.
openssl req -subj "/CN=$COMMON_NAME" -sha256 -new -key "server-key.pem" -out server.csr
# echo subjectAltName = DNS:docker166,IP:192.168.72.166,IP:127.0.0.1 >> extfile.cnf
# echo "subjectAltName = IP:$IP,IP:127.0.0.1" >> extfile.cnf
echo "extendedKeyUsage = serverAuth" >> extfile.cnf
# Generate server-cert.pem
openssl x509 -req -days ${DAYS} -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf -passin "pass:${PASSWORD}"
rm -f extfile.cnf
#---
# Generate Cient
openssl genrsa -out "key.pem" 4096
openssl req -subj '/CN=client' -new -key "key.pem" -out client.csr
echo extendedKeyUsage = clientAuth >> extfile.cnf
openssl x509 -req -days 365 -sha256 -in client.csr -passin "pass:${PASSWORD}" -CA "ca.pem" -CAkey "ca-key.pem" -CAcreateserial -out "cert.pem" -extfile extfile.cnf
rm -vf client.csr server.csr extfile.cnf
chmod -v 0400 ca-key.pem key.pem server-key.pem
chmod -v 0444 ca.pem server-cert.pem cert.pem
}
# 保存目录
setSaveCaDir() {
# 运行脚本的路径 当前运行脚本文件名basename和目录dirname
local BASE_PATH = $PWD
if [ -d "$BASE_PATH/ssl" ];then
echo "文件夹存在"
else
echo "文件夹不存在"
mkdir $PWD/ssl
fi
cd $PWD/ssl
}
setSaveCaDir
noCode
二、证书放到目标docker
docker 服务端证书配置
docker 1.12.6
系统
容器 | 版本 |
---|---|
docker | 1.12.6 |
系统版本 | CentOS Linux release 7.2.1511 (Core) |
-----这里配置 -H fd://
也可以-----
centos推荐配置 unix://
修改文件 /usr/lib/systemd/system/docker.service,添加ExecStart添加-H fd://
[root@docker227 ~]# cat /usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target docker.socket
Requires=docker.socket
[Service]
EnvironmentFile=-/etc/sysconfig/docker
EnvironmentFile=-/etc/sysconfig/docker-storage
EnvironmentFile=-/etc/sysconfig/docker-network
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// $DOCKER_OPTIONS $DOCKER_STORAGE_OPTIONS $DOCKER_NETWORK_OPTIONS
修改文件中/etc/sysconfig/docker-network
DOCKER_NETWORK_OPTIONS="--tlsverify --tlscacert=/root/.docker/ca.pem --tlscert=/root/.docker/server-cert.pem --tlskey=/root/.docker/server-key.pem -H=0.0.0.0:2376 -H=0.0.0.0:2375"
docker -H使用
tcp监听配置同时监听2375和 2376
# 默认为对应主机的2375端口
docker -H 192.168.72.166 ps
# 指定端口
docker -H 192.168.72.166:2376 ps
例子
[root@localhost ~]# docker -H localhost:2375 ps
Get http://localhost:2375/v1.26/containers/json: net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x15\x03\x01\x00\x02\x02".
* Are you trying to connect to a TLS-enabled daemon without TLS?
[root@localhost ~]# docker -H localhost ps
Get http://localhost:2375/v1.26/containers/json: net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x15\x03\x01\x00\x02\x02".
* Are you trying to connect to a TLS-enabled daemon without TLS?
[root@localhost ~]# docker -H localhost:2376 ps
Cannot connect to the Docker daemon at tcp://localhost:2376. Is the docker daemon running?
docker 1.3.1和 docker-ce 1.18.09
docker.service文件配置
方法一:自己添加一个文件/etc/sysconfig/docker-network
EnvironmentFile=-/etc/sysconfig/docker-network
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:// $DOCKER_NETWORK_OPTIONS
[root@docker111 ~]# cat /etc/sysconfig/docker-network
DOCKER_NETWORK_OPTIONS=" --tlsverify --tlscacert=/root/.docker/ca.pem --tlscert=/root/.docker/server-cert.pem --tlskey=/root/.docker/server-key.pem -H=0.0.0.0:2376"
方法二:
/usr/lib/systemd/system/docker.service文件中直接添加所有
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:// $DOCKER_NETWORK_OPTIONS --tlsverify --tlscacert=/root/.docker/ca.pem --tlscert=/root/.docker/server-cert.pem --tlskey=/root/.docker/server-key.pem -H 0.0.0.0:2376
-H 0.0.0.0:2376 效果等同于 -H=0.0.0.0:2376
官网配置参考 https://docs.docker.com/engine/reference/commandline/dockerd/
docker 1.13版本以上使用 unix:// 本机使用docker命令不需要使用证书
1.12.x fd://
官网摘抄片段
On Systemd based systems, you can communicate with the daemon via Systemd socket activation, use dockerd -H fd://. Using fd:// will work perfectly for most setups but you can also specify individual sockets: dockerd -H fd://3. If the specified socket activated files aren’t found, then Docker will exit. You can find examples of using Systemd socket activation with Docker and Systemd in the Docker source tree.
You can configure the Docker daemon to listen to multiple sockets at the same time using multiple -H options:
# listen using the default unix socket, and on 2 specific IP addresses on this host.
$ sudo dockerd -H unix:///var/run/docker.sock -H tcp://192.168.59.106 -H tcp://10.10.10.2
仅供参考有人说ubuntu 还是用 fd:// centos使用 unix://
本地测试证书
增加 -H fd://
后容器本地客户端访问本机可以不需要指定证书
[root@docker227 ~]# docker version
Client:
Version: 1.12.6
API version: 1.24
Go version: go1.6.4
Git commit: 78d1802
Built: Wed Jan 11 00:23:16 2017
OS/Arch: linux/amd64
Server:
Version: 1.12.6
API version: 1.24
Go version: go1.6.4
Git commit: 78d1802
Built: Wed Jan 11 00:23:16 2017
OS/Arch: linux/amd64
本机上使用外部IP测试
[root@docker227 ~]# docker -H 192.168.14.227 version
Client:
Version: 1.12.6
API version: 1.24
Go version: go1.6.4
Git commit: 78d1802
Built: Wed Jan 11 00:23:16 2017
OS/Arch: linux/amd64
Get http://192.168.14.227:2375/v1.24/version: malformed HTTP response "\x15\x03\x01\x00\x02\x02".
* Are you trying to connect to a TLS-enabled daemon without TLS?
否则需要证书如下
[root@docker110 ~]# docker version
Client:
Version: 1.13.1
API version: 1.26
Package version:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
本地按局域网模拟远程访问
[root@docker110 ~]# docker -H 192.168.72.110 version
Client:
Version: 1.13.1
API version: 1.26
Package version:
Get http://192.168.72.110:2375/v1.26/version: net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x15\x03\x01\x00\x02\x02".
* Are you trying to connect to a TLS-enabled daemon without TLS?
[root@docker110 ~]# docker --tls -H 192.168.72.110 version
Client:
Version: 1.13.1
API version: 1.26
Package version: docker-1.13.1-94.gitb2f74b2.el7.centos.x86_64
Go version: go1.10.3
Git commit: b2f74b2/1.13.1
Built: Tue Mar 12 10:27:24 2019
OS/Arch: linux/amd64
Server:
Version: 1.13.1
API version: 1.26 (minimum version 1.12)
Package version: docker-1.13.1-94.gitb2f74b2.el7.centos.x86_64
Go version: go1.10.3
Git commit: b2f74b2/1.13.1
Built: Tue Mar 12 10:27:24 2019
OS/Arch: linux/amd64
Experimental: false
–tls 表示不校验服务端主机IP
–tlsverify 校验主机IP
-
docker服务器主机IP无效,说明可能不是真是服务器或没有设置服务器有效IP
[root@docker110 ~]# docker --tlsverify -H 192.168.72.110 version Client: Version: 1.13.1 API version: 1.26 Package version: error during connect: Get https://192.168.72.110:2375/v1.26/version: x509: cannot validate certificate for 192.168.72.110 because it doesn't contain any IP SANs
curl测试 docker https
Connecting to the secure Docker port using curl
To use curl to make test API requests, you need to use three extra command line flags:
$ curl https://$HOST:2376/images/json \
--cert ~/.docker/cert.pem \
--key ~/.docker/key.pem \
--cacert ~/.docker/ca.pem
验证服务端证书
[root@docker110 ~]# curl https://192.168.72.111:2376/images/json --cert ~/.docker/cert.pem --key ~/.docker/key.pem --cacert ~/.docker/ca.pem
curl: (51) Unable to communicate securely with peer: requested domain name does not match the server's certificate.
增加 -k 不验证服务端证书
curl https://192.168.72.111:2376/version --cert ~/.docker/cert.pem --key ~/.docker/key.pem --cacert
[root@docker110 ~]# curl https://192.168.72.111:2376/version --cert ~/.docker/cert.pem --key ~/.docker/key.pem --cacert ~/.docker/ca.pem -k
{"Platform":{"Name":"Docker Engine - Community"},"Components":[{"Name":"Engine","Version":"18.09.0","Details":{"ApiVersion":"1.39","Arch":"amd64","BuildTime":"2018-11-07T00:19:08.000000000+00:00","Experimental":"false","GitCommit":"4d60db4","GoVersion":"go1.10.4","KernelVersion":"3.10.0-957.1.3.el7.x86_64","MinAPIVersion":"1.12","Os":"linux"}}],"Version":"18.09.0","ApiVersion":"1.39","MinAPIVersion":"1.12","GitCommit":"4d60db4","GoVersion":"go1.10.4","Os":"linux","Arch":"amd64","KernelVersion":"3.10.0-957.1.3.el7.x86_64","BuildTime":"2018-11-07T00:19:08.000000000+00:00"}
httpClient和dockerClient
dockerClient基于httpclient请求dockerApi
使用docker pem证书生成httpClient
DockerCertificatesStore dockerCertificatesStore = null;
try {
dockerCertificatesStore = new DockerCertificates(Paths.get(getDockerCaDir()));
} catch (DockerCertificateException e) {
e.printStackTrace();
}
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLContext(dockerCertificatesStore.sslContext()).setSSLHostnameVerifier(new NoopHostnameVerifier())
.build();
使用docker.keystore
根据docker的证书转化为keystore,https方式请求dockerApi
private static SSLConnectionSocketFactory getSSLConnectionSocketFactory() throws Exception {
String curClassPath = DockerApi.class.getClassLoader().getResource("").getPath();
String keyStorePath = new File(curClassPath + "/dockertls/certificate/docker.keystore").getPath();
// docker使用证书将对应的pem证书转为jks证书
InputStream in = new FileInputStream(new File(keyStorePath));
KeyStore keyStore = KeyStore.getInstance("jks");
String password = dockerKeyStorePass; // 证书密码,生成证书时指定
try {
keyStore.load(in, password.toCharArray());
} catch (Exception e) {
e.printStackTrace();
} finally{
in.close();
}
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, (password).toCharArray())
.loadTrustMaterial(new TrustSelfSignedStrategy())
.build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext, new String[] { "TLSv1" }, null,
new NoopHostnameVerifier()); // 不验证server服务器
return sslsf;
}
public CloseableHttpClient getHttpclientSsl(){
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sSLConnectionSocketFactory)
.build();
return httpclient;
}
生成keystore脚本