Ihar Hancharenka 5dff80e88e first
2023-03-27 16:52:17 +03:00

325 строки
21 KiB
Plaintext

Sabharwal - Docker Hands on Deploy - Administer Docker Platform
Docker server access over https
https://shipyard-project.com/docs/quickstart/
SSL Certificate
cert.pem
SSL Key
key.pem
CA Certificate
ca.pem
http://middlewaresnippets.blogspot.com.by/2015/08/spring-boot-and-docker.html
/opt
/docker
/certs (contains the certificates for client-server communication)
/ca
ca-key.pem # CA pvt signing key
ca.pem
ca.srl
/client
cert.pem
key.pem
/server
server-cert.pem # server
server-key.pem # server pvt rsa key
If we need Docker to be reachable via the network in a safe manner, we can enable TLS by specifying the tlsverify flag
and pointing Docker's tlscacert flag to a trusted CA certificate.
In the daemon mode, it will only allow connections from clients authenticated by a certificate signed by that CA.
In the client mode, it will only connect to servers with a certificate signed by that CA.
By using OpenSSL we can generate the necessary keys and certificates.
To generate the private and public signing keys, we can use
# create the necessary directories
[root@docker ~]# mkdir -p /opt/docker/certs/{ca,client,server}
# generate private and public signing keys
# genrsa - generate an RSA private key
# -aes256: encrypt the private key with the defined cipher
# -out: the output filename
# numbits: the size of the private key to generate in bits. This must be the last option specified.
[root@docker ~]# openssl genrsa -aes256 -out /opt/docker/certs/ca/ca-key.pem 2048
Generating RSA private key, 2048 bit long modulus
...........................+++
...................+++
e is 65537 (0x10001)
Enter pass phrase for /opt/docker/certs/ca/ca-key.pem:
Verifying - Enter pass phrase for /opt/docker/certs/ca/ca-key.pem:
# req - PKCS#10 certificate request and certificate generating utility.
# -new: this option generates a new certificate request. It will prompt the user for the relevant field values.
# -x509: this option outputs a self signed certificate instead of a certificate request.
# -days n: when the -x509 option is being used this specifies the number of days to certify the certificate for.
# -key: specifies the file to read the private key from.
# -[digest]: this specifies the message digest to sign the request with (run 'openssl dgst -h output' to see a list of possible values).
# -out filename: specifies the output filename to write to.
# -subj arg: sets subject name for new request or supersedes the subject name when processing a request. The arg must be formatted as /type0=value0/type1=value1/type2=...
[root@docker ~]# openssl req -new -x509 -days 365 -key /opt/docker/certs/ca/ca-key.pem -sha256 -out /opt/docker/certs/ca/ca.pem -subj '/C=NL/ST=Middleware/L=Snippets/O=Middleware Snippets/OU=Blogging/CN=*.machine.com'
Enter pass phrase for /opt/docker/certs/ca/ca-key.pem:
Note that we have used a wild-card in the common-name (CN=*.machine.com) such that we can use the certificates on all hosts.
To generate the server key and a certificate signing request, we can use
# generate the server key and certificate signing request
# genrsa - generate an RSA private key
# -out: the output filename
# numbits: the size of the private key to generate in bits. This must be the last option specified.
[root@docker ~]# openssl genrsa -out /opt/docker/certs/server/server-key.pem 2048
Generating RSA private key, 2048 bit long modulus
...........................................................................................................................................+++
......................................................................................................................+++
e is 65537 (0x10001)
# req - PKCS#10 certificate request and certificate generating utility.
# -new: this option generates a new certificate request. It will prompt the user for the relevant field values.
# -key: specifies the file to read the private key from.
# -[digest]: this specifies the message digest to sign the request with (run 'openssl dgst -h output' to see a list of possible values).
# -out filename: specifies the output filename to write to.
# -subj arg: sets subject name for new request or supersedes the subject name when processing a request. The arg must be formatted as /type0=value0/type1=value1/type2=...
[root@docker ~]# openssl req -new -key /opt/docker/certs/server/server-key.pem -sha256 -out /opt/docker/certs/server/server.csr -subj '/C=NL/ST=Middleware/L=Snippets/O=Middleware Snippets/OU=Blogging/CN=*.machine.com'
Next, we need to sign the certificate signing request by our CA
# we can also add additional subject identities if needed
# x509 - Certificate display and signing utility
# -req: by default a certificate is expected on input. With this option a certificate request is expected instead
# -days arg: specifies the number of days to make a certificate valid for.
# -[digest]: this specifies the message digest to sign the request with (run 'openssl dgst -h output' to see a list of possible values).
# -in filename: specifies the input filename to read a certificate from .
# -CA filename: specifies the CA certificate to be used for signing. When this option is present x509 behaves like a "mini CA". The input file is signed by this CA using this option: that is its issuer name is set to the subject name of the CA and it is digitally signed using the CAs private key.
# -CAkey filename: sets the CA private key to sign a certificate with. If this option is not specified then it is assumed that the CA private key is present in the CA certificate file.
# -CAcreateserial: with this option the CA serial number file is created if it does not exist: it will contain the serial number "02" and the certificate being signed will have the 1 as its serial number. Normally if the -CA option is specified and the serial number file does not exist it is an error.
# -out filename: specifies the output filename to write to.
# -extfile filename: file containing certificate extensions to use. If not specified then no extensions are added to the certificate.
[root@docker ~]# echo subjectAltName = IP:192.168.101.210,IP:192.168.101.220,IP:192.168.101.230,IP:127.0.0.1 > /opt/docker/certs/server/extfile.cnf
[root@docker ~]# openssl x509 -req -days 365 -sha256 -in /opt/docker/certs/server/server.csr -CA /opt/docker/certs/ca/ca.pem -CAkey /opt/docker/certs/ca/ca-key.pem -CAcreateserial -out /opt/docker/certs/server/server-cert.pem -extfile /opt/docker/certs/server/extfile.cnf
Signature ok
subject=/C=NL/ST=Middleware/L=Snippets/O=Middleware Snippets/OU=Blogging/CN=*.machine.com
Getting CA Private Key
Enter pass phrase for /opt/docker/certs/ca/ca-key.pem:
# sign the public key without additional subject identities
[root@docker ~]# openssl x509 -req -days 365 -sha256 -in /opt/docker/certs/server/server.csr -CA /opt/docker/certs/ca/ca.pem -CAkey /opt/docker/certs/ca/ca-key.pem -CAcreateserial -out /opt/docker/certs/server/server-cert.pem
Signature ok
subject=/C=NL/ST=Middleware/L=Snippets/O=Middleware Snippets/OU=Blogging/CN=*.machine.com
Getting CA Private Key
Enter pass phrase for /opt/docker/certs/ca/ca-key.pem:
Finally, we generate the client key and certificate
# generate client key and certificate signing request
# genrsa - generate an RSA private key
# -out: the output filename
# numbits: the size of the private key to generate in bits. This must be the last option specified.
[root@docker ~]# openssl genrsa -out /opt/docker/certs/client/key.pem 2048
Generating RSA private key, 2048 bit long modulus
..+++
.................+++
e is 65537 (0x10001)
# req - PKCS#10 certificate request and certificate generating utility.
# -new: this option generates a new certificate request. It will prompt the user for the relevant field values.
# -key: specifies the file to read the private key from.
# -out filename: specifies the output filename to write to.
# -subj arg: sets subject name for new request or supersedes the subject name when processing a request. The arg must be formatted as /type0=value0/type1=value1/type2=..
[root@docker ~]# openssl req -new -key /opt/docker/certs/client/key.pem -out /opt/docker/certs/client/client.csr -subj '/CN=client'
# sign the client key
# x509 - Certificate display and signing utility
# -req: by default a certificate is expected on input. With this option a certificate request is expected instead
# -days arg: specifies the number of days to make a certificate valid for.
# -[digest]: this specifies the message digest to sign the request with (run 'openssl dgst -h output' to see a list of possible values).
# -in filename: specifies the input filename to read a certificate from .
# -CA filename: specifies the CA certificate to be used for signing. When this option is present x509 behaves like a "mini CA". The input file is signed by this CA using this option: that is its issuer name is set to the subject name of the CA and it is digitally signed using the CAs private key.
# -CAkey filename: sets the CA private key to sign a certificate with. If this option is not specified then it is assumed that the CA private key is present in the CA certificate file.
# -CAcreateserial: with this option the CA serial number file is created if it does not exist: it will contain the serial number "02" and the certificate being signed will have the 1 as its serial number. Normally if the -CA option is specified and the serial number file does not exist it is an error.
# -out filename: specifies the output filename to write to.
# -extfile filename: file containing certificate extensions to use. If not specified then no extensions are added to the certificate.
[root@docker ~]# echo extendedKeyUsage = clientAuth > /opt/docker/certs/client/extfile.cnf
[root@docker ~]# openssl x509 -req -days 365 -sha256 -in /opt/docker/certs/client/client.csr -CA /opt/docker/certs/ca/ca.pem -CAkey /opt/docker/certs/ca/ca-key.pem -CAcreateserial -out /opt/docker/certs/client/cert.pem -extfile /opt/docker/certs/client/extfile.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for /opt/docker/certs/ca/ca-key.pem:
# change the permissions of the private keys
[root@docker ~]# chmod 0400 /opt/docker/certs/ca/ca-key.pem /opt/docker/certs/client/key.pem /opt/docker/certs/server/server-key.pem
# change the permissions of the public keys
[root@docker ~]# chmod 0444 /opt/docker/certs/ca/ca.pem /opt/docker/certs/client/cert.pem /opt/docker/certs/server/server-cert.pem
# optionally the certificate signing requests and extention files can be removed
[root@docker ~]# rm -f /opt/docker/certs/client/client.csr /opt/docker/certs/client/extfile.cnf /opt/docker/certs/server/server.csr /opt/docker/certs/server/extfile.cnf
# copy the certificates to the other hosts
[root@docker certs]# scp -rp * root@springboot1.machine.com:/opt/docker/certs/
root@springboot1.machine.com's password:
ca-key.pem 100% 1766 1.7KB/s 00:00
ca.pem 100% 1383 1.4KB/s 00:00
ca.srl 100% 17 0.0KB/s 00:00
key.pem 100% 1679 1.6KB/s 00:00
cert.pem 100% 1155 1.1KB/s 00:00
server-key.pem 100% 1675 1.6KB/s 00:00
server-cert.pem 100% 1265 1.2KB/s 00:00
[root@docker certs]# scp -rp * root@springboot2.machine.com:/opt/docker/certs/
root@springboot2.machine.com's password:
ca-key.pem 100% 1766 1.7KB/s 00:00
ca.pem 100% 1383 1.4KB/s 00:00
ca.srl 100% 17 0.0KB/s 00:00
key.pem 100% 1679 1.6KB/s 00:00
cert.pem 100% 1155 1.1KB/s 00:00
server-key.pem 100% 1675 1.6KB/s 00:00
server-cert.pem 100% 1265 1.2KB/s 00:00
To make the Docker daemon only accept connections from clients providing a certificate trusted by our CA, we edit the /usr/lib/systemd/system/docker.service file
[root@springboot2 system]# cat docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target docker.socket
Requires=docker.socket
[Service]
Type=notify
#ExecStart=/usr/bin/dockerd -H fd://
ExecStart=/usr/bin/docker -d --tlsverify --tlscacert=/opt/docker/certs/ca/ca.pem --tlscert=/opt/docker/certs/server/server-cert.pem --tlskey=/opt/docker/certs/server/server-key.pem -H=0.0.0.0:2376
MountFlags=slave
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
[Install]
WantedBy=multi-user.target
# Restart docker
[root@springboot2 system]# systemctl daemon-reload
[root@springboot2 system]# systemctl start docker.service
[root@springboot2 system]# systemctl status docker.service
docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled)
Active: active (running) since Wed 2015-08-19 14:36:56 CEST; 7s ago
Docs: https://docs.docker.com
Main PID: 11021 (docker)
CGroup: /system.slice/docker.service
-- 11021 /usr/bin/docker -d --tlsverify --tlscacert=/opt/docker/certs/ca/ca.pem --tlscert=/opt/docker/certs/server/server-cert.pem --tlskey=/opt/docker/certs/server/server-key.pem ...
To communicate with the Docker daemon we now have to use
[root@docker ~]# docker --tlsverify --tlscacert=/opt/docker/certs/ca/ca.pem --tlscert=/opt/docker/certs/client/cert.pem --tlskey=/opt/docker/certs/client/key.pem -H=springboot2.machine.com:2376 pull docker.machine.com:5000/springbootexample:latest
latest: Pulling from springbootexample
f1b10cd84249: Pull complete
c852f6d61e65: Pull complete
7322fbe74aa5: Pull complete
4cfba0adf483: Pull complete
6a5b64d0925e: Pull complete
e136fb7fd983: Pull complete
f027b1b29898: Pull complete
e8261eb40ec4: Pull complete
20ee6480f62e: Pull complete
369ff136c2b5: Pull complete
c200531e0027: Pull complete
012ae7d5f8b5: Pull complete
c8a563965cf0: Pull complete
Digest: sha256:0b50559aa6d94d3a6919c5efd77b2ce262760c1bc4a9db7cb0b4f539ee854e0e
Status: Downloaded newer image for docker.machine.com:5000/springbootexample:latest
[root@docker ~]# docker --tlsverify --tlscacert=/opt/docker/certs/ca/ca.pem --tlscert=/opt/docker/certs/client/cert.pem --tlskey=/opt/docker/certs/client/key.pem -H=springboot2.machine.com:2376 images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
docker.machine.com:5000/springbootexample latest c8a563965cf0 3 hours ago 528.4 MB
[root@docker ~]# docker --tlsverify --tlscacert=/opt/docker/certs/ca/ca.pem --tlscert=/opt/docker/certs/client/cert.pem --tlskey=/opt/docker/certs/client/key.pem -H=springboot2.machine.com:2376 run -d --name="springbootexample" --net="host" -v /home/temp:/home/temp -p 8080:8080 -p 9090:9090 docker.machine.com:5000/springbootexample
38a2ff01166a7c5c540c4fc6117946a535af9cf915a0c5bb7ae29b573429392e
[root@docker ~]# docker --tlsverify --tlscacert=/opt/docker/certs/ca/ca.pem --tlscert=/opt/docker/certs/client/cert.pem --tlskey=/opt/docker/certs/client/key.pem -H=springboot2.machine.com:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
38a2ff01166a docker.machine.com:5000/springbootexample "java -XX:+UnlockComm" 41 seconds ago Up 39 seconds springbootexample
[root@docker ~]# docker --tlsverify --tlscacert=/opt/docker/certs/ca/ca.pem --tlscert=/opt/docker/certs/client/cert.pem --tlskey=/opt/docker/certs/client/key.pem -H=springboot1.machine.com:2376 start springbootexample
springbootexample
[root@docker ~]# docker --tlsverify --tlscacert=/opt/docker/certs/ca/ca.pem --tlscert=/opt/docker/certs/client/cert.pem --tlskey=/opt/docker/certs/client/key.pem -H=springboot1.machine.com:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7193fa0ef4c8 docker.machine.com:5000/springbootexample "java -XX:+UnlockComm" 3 hours ago Up 19 seconds springbootexample
To secure Docker client connections by default, we can move the client certificate files to the .docker directory in the home directory, and set the DOCKER_HOST and DOCKER_TLS_VERIFY environment variables.
# create the .docker directory
[root@docker ~]# mkdir -p ~/.docker
# copy the certificates
[root@docker ~]# cp /opt/docker/certs/ca/ca.pem ~/.docker
[root@docker ~]# cp /opt/docker/certs/client/cert.pem ~/.docker
[root@docker ~]# cp /opt/docker/certs/client/key.pem ~/.docker
# check
[root@docker .docker]# ll
-r--r--r-- 1 root root 1383 Aug 19 15:02 ca.pem
-r--r--r-- 1 root root 1155 Aug 19 15:02 cert.pem
-r-------- 1 root root 1679 Aug 19 15:07 key.pem
# edit .bashrc
[root@docker ~]# cat .bashrc
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
export DOCKER_HOST=tcp://springboot1.machine.com:2376
export DOCKER_TLS_VERIFY=1
# check
[root@docker ~]# echo $DOCKER_HOST
tcp://springboot1.machine.com:2376
[root@docker ~]# echo $DOCKER_TLS_VERIFY
1
# this communicates only with springboot1.machine.com
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
docker.machine.com:5000/springbootexample latest c8a563965cf0 4 hours ago 528.4 MB
# note that it is better to leave out the $DOCKER_HOST and $DOCKER_TLS_VERIFY environment variables and use
[root@docker ~]# docker --tlsverify -H=springboot1.machine.com:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7193fa0ef4c8 docker.machine.com:5000/springbootexample "java -XX:+UnlockComm" 3 hours ago Up 15 minutes springbootexample
[root@docker ~]# docker --tlsverify -H=springboot2.machine.com:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
38a2ff01166a docker.machine.com:5000/springbootexample "java -XX:+UnlockComm" 23 minutes ago Up 23 minutes springbootexample