Custom DNS record and SSL certificate in docker container - ssl

I am facing a issue with self signed certificate and DNS record in hosts file inside docker container. We have multiple Linux servers with docker swarm running. There was a docker service where I need to copy the self signed certificate and create a DNS record manually with docker exec all the time when ever service is restarting. There was a mapped volume for the docker service. How can I map container DNS file(/etc/hosts) and /usr/local/share/ca-certificates to have these in mapped place so that there will be no issues if the container re-start.

Use docker configs.
Something like :-
docker config create my_public-certificate-v1 public.crt.
docker service create --config src=my_public-certificate-v1,target=/usr/local/share/ca-certificates/example.com.crt ...

Related

How to retrieve client IP within a Docker container running Apache on AWS Elastic Container Service?

I have a Docker server running Apache 2.4.25 (Debian) PHP 7.3.5.
This container is "hosted" within an Amazon Elastic Container Service.
The default AWS EC2s are sat behind an AWS application load balancer.
I want to be able to obtain, in PHP, the users/clients IP address.
My presumption based on my limited knowledge is that this IP address will need to be handed from the ALB, to the EC2, then to the Docker container, and finally for Apache to pick up.
I have tried to shorten the stack by attempting to obtain the IP within a Docker container running on my local machine, however still I wasn't able to find a way for Docker to fetch and pass through my IP to Apache.
I know typically you'd have the X-Forwarded header from the ALB, but I have not been able to work out how Docker can take this and pass it through to Apache.
I expected to have the client IP in $_SERVER['REMOTE_ADDR'] or $_SERVER['X_FORWARDED'].
Within the AWS hosted Docker containers
$_SERVER['REMOTE_ADDR'] contains an IP within the VPC subnet
$_SERVER['X_FORWARDED'] does not exist

Which ca.crt does docker.sock use for docker pull?

When I do docker pull from inside a container that uses /var/run/docker.sock to run docker (docker inside docker), I got this error:
FATA[0000] Error response from daemon: v1 ping attempt failed with error: Get https://registry.com:5000/v1/_ping: x509: certificate has expired or is not yet valid. If this private registry supports only HTTP or HTTPS with an unknown CA certificate, please add `--insecure-registry registry.com:5000` to the daemon's arguments. In the case of HTTPS, if you have access to the registry's CA certificate, no need for the flag; simply place the CA certificate at /etc/docker/certs.d/registry.com:5000/ca.crt
So I followed the instruction and added the ca.crt inside that directory and also added the insecure option to /etc/default/docker, but the error didn't go away.
I wonder where /var/run/docker.sock command look for the cert when I pull from inside the container. Especially when pulling works from outside (host) with the same config (ca.crt in the right folder and the insecure option is also added).
/var/run/docker.sock is not the thing that is looking for a cert. That is simply the socket that you use to communicate with dockerd. When you do a pull, you are asking the docker daemon to go talk to a registry.
Where did you get the ca.crt file? Is that really the signing certificate for your registry.com:5000 server's certificate? Did you put that in /et c/default/docker/registry.com:5000/ca.crt on the host where dockerd is running, or inside the container?
That ca.crt file belongs where the daemon is running. Double check that you have that correct file in the correct place on the host, and that should fix the issue.
Got it to work now, the solution is to restart the docker daemon inside the container. I actually tried it before but the docker service kept going down after restart, that made me think it was the docker service from the host.
The reason I could not restart docker service is /var/run/docker.pid existed which prevent docker from starting again. So I deleted that pid and docker restarted successfully.

Issue with docker push on local registry https access to ressource denied

I have a problem with my registry docker. My "server" VM is on kali-linux. I created the registry docker in HTTP and use a centOS VM as a client. I declared the registry insecure in the client VM and it worked perfectly.
Now I try to put it in HTTPS. In order to do that, I use nginx as a proxy. I followed this tutorial : Step 5 — Setting Up SSL except for Part 8 to make it a service (I don't know why but i can't do it).
Because I don't have a domain name, I used a fake one. In order to be recognized, I added my IP (192.168.X.X) and the domain name I used (myregistryexemple) to the /etc/hosts file on both VM.
As asked by the tutorial, I generated the certificat on my "server" VM (the kali one), and send it by scp to my client VM. I make the centOS vm trust the certificate thanks to this commands :
yum install ca-certificates
update-ca-trust force-enable
cp cert.crt /etc/pki/ca-trust/source/anchors/
update-ca-trust extract
I restart the service docker on the client VM. And launch the docker registry and the nginx proxy with "docker-compose up" on my kali VM.
I tag and try to push an ubuntu on the registry :
docker tag ubuntu myregistryexemple/ubuntu
docker push myregistryexemple/ubuntu
But I get this error :
The push refers to a repository [docker.io/myregistryexemple/ubuntu]
56827159aa8b: Preparing
440e02c3dcde: Preparing
29660d0e5bb2: Preparing
85782553e37a: Preparing
745f5be9952c: Preparing
denied: requested access to the resource is denied
Then I try to push to localhost directly :
docker tag ubuntu localhost:5000/ubuntu & docker push localhost:5000/ubuntu
then I docker login on the domain from the client VM, it worked, but when i tried to pull from my domain registry on the client VM, docker cannot find on the registry the docker images i tried to push.
Do someone has any idea why and knows how to help me ?
Ok so i found a way to make it work.
It is quite simple : Juste follow the complete tutorial I quote on the question ( https://www.digitalocean.com/community/tutorials/how-to-set-up-a-private-docker-registry-on-ubuntu-14-04#step-5-%E2%80%94-setting-up-ssl )
After you created the repository, and before you push/pull a docker image.
You need to go, in both client and server VM, on /etc/hosts .
Add the line : domainChosen serverVmIp
Save and quit it.
Now we need the client to trust the certificate generated. In order to do that, you can use this tutorial : http://kb.kerio.com/product/kerio-connect/server-configuration/ssl-certificates/adding-trusted-root-certificates-to-the-server-1605.html .
Then restart your registry and your docker deamon. And you normaly can use your domain name to push/pull in your registry in https.

how docker-machine uses docker api to copy certificates

My question is, as I understand docker-machine uses docker remote API to do whatever it does, for example to regenerate certificates. I have checked docker API but couldn't find how it's possible to send certificates to that machine using only docker api, can someone help please?
The TLS files are hosted locally on the Docker client. For this reason you should protect the files as if they were a root password.
This page will walk you through generating the files needed to negotiate a connection over TLS. Note that the remote daemon must be running TLS.
https://docs.docker.com/engine/security/https/
docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H=$HOST:2376 version
Note: Docker over TLS should run on TCP port 2376.
Warning: As shown in the example above, you don’t have to run the
docker client with sudo or the docker group when you use certificate
authentication. That means anyone with the keys can give any
instructions to your Docker daemon, giving them root access to the
machine hosting the daemon. Guard these keys as you would a root
password!

Setup secured Jenkins master with docker

I would like to set up a secured Jenkins master server on ec2 with docker.
I'm using standard jenkins docker file from here: https://registry.hub.docker.com/_/jenkins/
By default it opens an unsecured 8080 http port. However I want it to use a standard 443 port with https (at first I want to use self-signed ssl certificate).
I researched in this topic a little bit and found several possible solution. I'm not really experienced with docker so I still couldn't find a simple one I can use or implement. Here are some options I found:
Use standard jenkins docker on 8080 but configure a secured apache or nginx server on my ec2 instance that will redirect the trafic. I don't like this because the server will be outside the docker so I can not keep it in the version control
Somehow modify the jenkins docker file to start jenkins with a https configured according to https://wiki.jenkins-ci.org/display/JENKINS/Starting+and+Accessing+Jenkins. I'm not sure how to do that though. Do I need to create my own docker container?
use docker file with secured nginx like this one https://registry.hub.docker.com/u/marvambass/nginx-ssl-secure/ and somehow combine two docker containers or make them communicate? Not sure how to that either.
Could someone experienced please recommend me the best solution?
P.S. I'm not sure how much troubles ec2 is going to give me but I assume its just about opening 443 in a security group.
After passing few tutorials on Docker I found that the easiest option to follow is number 2. Jenkins docker image declares the entry point in a way that you can easily pass arguments to the jenkins.
Lets say you have your keystore (e.g. self-signed in this example) as jenkins_keystore.jks in the home folder of ubuntu ec2 instance. Here is the example how to generate one:
keytool -genkey -keyalg RSA -alias selfsigned -keystore jenkins_keystore.jks -storepass mypassword -keysize 2048
Now you can easily configure jenkins to run on https only without creating your own docker image:
docker run -v /home/ubuntu:/var/jenkins_home -p 443:8443 jenkins --httpPort=-1 --httpsPort=8443 --httpsKeyStore=/var/jenkins_home/jenkins_keystore.jks --httpsKeyStorePassword=mypassword
-v /home/ubuntu:/var/jenkins_home exposes the host home folder to the jenkins docker container
-p 443:8443 maps 8443 jenkins port in the container to the 443 port of the host
--httpPort=-1 --httpsPort=8443 blocks jenkins http and exposes it with https on port 8443 inside the container
--httpsKeyStore=/var/jenkins_home/jenkins_keystore.jks --httpsKeyStorePassword=mypassword provides your keystore that has been mapped from the host home folder to the container /var/jenkins_home/ folder.
Like otognan, I would also recommend doing #2, but it seems that his answer is outdated.
First of all, use the jenkins/jenkins:lts image, as the jenkins image is deprecated (see https://hub.docker.com/_/jenkins/ )
Now, lets set it up. You'll need to stop your current jenkins container to free up the ports.
First, you'll need a certificate keystore. If you don't have one, you could create a self-signed one with
keytool -genkey -keyalg RSA -alias selfsigned -keystore jenkins_keystore.jks -storepass mypassword -keysize 4096
Next, let's pass the SSL arguments into the jenkins container. This is the script I use to do so:
read -s -p "Keystore Password:" password
echo
sudo cp jenkins_keystore.jks /var/lib/docker/volumes/jenkins_home/_data
docker run -d -v jenkins_home:/var/jenkins_home -v $(which docker):/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock -p 443:8443 -p 50000:50000 jenkins/jenkins:lts --httpPort=-1 --httpsPort=8443 --httpsKeyStore=/var/jenkins_home/jenkins_keystore.jks --httpsKeyStorePassword=$password
this script prompts the user for the keystore password
-v jenkins_home:/var/jenkins_home creates a named volume called jenkins_home, which happens to exist at /var/lib/docker/volumes/jenkins_home/_data by convention.
if the directory at /var/lib/docker/volumes/jenkins_home/_data does not exist yet, you will need to create the named volume using docker volume before copying the keystore.
-p 443:8443 maps 8443 jenkins port in the container to the 443 port of the host
--httpPort=-1 --httpsPort=8443 blocks http and exposes https on port 8443 inside the container (port 443 outside the container).
--httpsKeyStore=/var/jenkins_home/jenkins_keystore.jks --httpsKeyStorePassword=$password provides your keystore, which exists at /var/jenkins_home/jenkins_keystore.jks inside the container ( /var/lib/docker/volumes/jenkins_home/_data/jenkins_keystore.jks outside the container).
-v /var/run/docker.sock:/var/run/docker.sock is optional, but is the recommended way to allow your jenkins instance to spin up other docker containers.
WARNING: By giving the container access to /var/run/docker.sock, it is easy to break out of the containment provided by the container, and gain access to the host machine. This is obviously a potential security risk.
-v $(which docker):/usr/bin/docker is also optional, but allows your jenkins container to be able to run the docker binary.
Be aware that, because docker is now dynamically linked, it no longer comes with dependencies, so you may be required to install dependencies in the container.
The alternative is to omit -v $(which docker):/usr/bin/docker and install docker within the jenkins container. You'll need to ensure that the inner container docker and the outer host docker are the same version, so that communication over /var/run/docker.sock is supported.
In either case, you may want to use a Dockerfile to create a new Jenkins docker image.
Another alternative is to include -v $(which docker):/usr/bin/docker, but install a statically-linked binary of docker on the host machine.
You should now be able to access the jenkins webportal via https with no port specifier (since port 443 is default for https)
Thanks to otognan for getting me part of the way here.
I know this is a very old topic but I wanted to share a blog post which covers reverse proxy option in detail: https://itnext.io/setting-up-https-for-jenkins-with-nginx-everything-in-docker-4a118dc29127
Jenkins suggests to setup reverse proxy in documents. It may seem like an extra effort in the first place but it is a general solution for other services related with CI/CD environment as well (i.e. SonarQube).
I would use nginx together with jenkins in the same container, and use supervisord to manage both processes. Securing different services with builtin tools is a pain; nginx works the same for all services, and is easy to configure. It is possible, and nicer in some ways, to use docker-compose (was fig) to create two different containers and hook them up with the pretty internal networking that docker provides with links. The problem is that running pairs of jobs together is still not well supported in cluster managers like marathon. It's far easier to tell most services to run a single container, rather than to run two containers, but make sure they're on the same host.
Install Self-Signed SSL Certification to Jenkins Container
I have setup my jenkins in AWS EC2 instance with docker using official jenkins container. I have used docker-compose to build and run jenkins container and here is my docker-compose.yml file
First, you will need certificate keystore. If you already have a certificate keystorke, no need to run below code. So to generate certificate keystroke run
keytool -genkey -keyalg RSA -alias selfsigned -keystore jenkins.jks -storepass password -keysize 4096
please be careful with volume mapping because i have places my jenkins.jks file in /opt/cert folder and my jenkins directory is in /jenkins foler and inside that jenkins foler i have my docker-compose.yml file and jenkins_home directory
version: '3.7'
services:
jenkins:
image: jenkins/jenkins
container_name: jenkins-docker
restart: always
privileged: true
user: root
ports:
- 443:8443
- 50000:50000
volumes:
- ./jenkins_home:/var/jenkins_home
- ../opt/cert/jenkins.jks:/var/lib/jenkins/jenkins.jks
environment:
JAVA_OPTS: -Duser.timezone=CET
JENKINS_OPTS: --httpPort=-1 --httpsPort=443 --httpsKeyStore=/var/lib/jenkins/jenkins.jks --httpsKeyStorePassword=password
after the all these steps , check your jenkins container is up and running. If so , then you can access your jenkins with browser with simply typing https://public-ip:443