<p>Currently, running a private Docker registry (Artifactory) on an internal network that uses a self signed certificate for authentication.</p>

<p>When Kubernetes starts up a new node, it is unable to auth with the private Docker registry because this new node does not have the self signed certificate. </p>

<p>Any help would be much appreciated. Thanks!</p>

<p>The simplest solution I found after an extensive search is suggested in this guide by CoreOS : <a href="https://github.com/coreos/tectonic-docs/blob/master/Documentation/admin/add-registry-cert.md" rel="noreferrer">https://github.com/coreos/tectonic-docs/blob/master/Documentation/admin/add-registry-cert.md</a></p>
<p>It consists to create a secret that contains your certificate and a DaemonSet to populate it to <code>/etc/docker/certs.d/my-private-insecure-registry.com/ca.crt</code> on all the nodes of your cluster.</p>
<p>I think this answers your question because, when adding a new node, the DaemonSet is automatically executed on it.</p>
<p>I give the detailed solution below but all the credits goes to Kyle Brown (kbrwn) for his very cool guide (cf. link above).</p>
<h1 id="detailed-solution-for-kubernetes-1.16-iqlw">Detailed solution for Kubernetes 1.16+</h1>
<p>Lets suppose that your certificate is a file named <code>ca.crt</code> in your working directory. Create a secret from this file content :</p>
<pre class="lang-sh prettyprint-override"><code>kubectl create secret generic registry-ca --namespace kube-system --from-file=registry-ca=./ca.crt
</code></pre>
<p>Then, use the following DaemonSet that mounts the certificate as the file <code>/home/core/registry-ca</code> and copy it to the desired location : <code>/etc/docker/certs.d/reg.example.com/ca.crt</code>.</p>
<p>Simply replace <code>my-private-insecure-registry.com</code> with the hostname of your container registry.</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: registry-ca
  namespace: kube-system
  labels:
    k8s-app: registry-ca
spec:
  selector:
    matchLabels:
      name: registry-ca
  template:
    metadata:
      labels:
        name: registry-ca
    spec:
      containers:
      - name: registry-ca
        image: busybox
        command: [ 'sh' ]
        args: [ '-c', 'cp /home/core/registry-ca /etc/docker/certs.d/my-private-insecure-registry.com/ca.crt &amp;&amp; exec tail -f /dev/null' ]
        volumeMounts:
        - name: etc-docker
          mountPath: /etc/docker/certs.d/my-private-insecure-registry.com
        - name: ca-cert
          mountPath: /home/core
      terminationGracePeriodSeconds: 30
      volumes:
      - name: etc-docker
        hostPath:
          path: /etc/docker/certs.d/my-private-insecure-registry.com
      - name: ca-cert
        secret:
          secretName: registry-ca
</code></pre>
<p>Save the file as <code>registry-ca-ds.yaml</code> and then create the DaemonSet :</p>
<pre class="lang-sh prettyprint-override"><code>kubectl create -f registry-ca-ds.yaml
</code></pre>
<p>You can now check that your application correctly pulls from your private self-signed registry.</p>
<p>As mentioned, the certificate will be added to new nodes' docker in an automatic fashion by the <code>registry-ca</code> DaemonSet. If you want to avoid this, simply delete the DaemonSet :</p>
<pre class="lang-sh prettyprint-override"><code>kubectl delete ds registry-ca --namespace kube-system
</code></pre>
<p>I think this is more secure than setting the <code>insecure-registries</code> flag of the docker daemon. Also, it is resilient to new nodes.</p>
<h1 id="original-solution-for-kubernetes-prior-to-1.16-4xye">Original solution for Kubernetes prior to 1.16</h1>
<p>As suggested by @MarcusMaxwell, this answer has been edited to take into account the deprecation of the API <code>extensions/v1beta1</code> for Kubernetes 1.16+ clusters. If you still run a Kubernetes cluster with version prior to 1.16, you should adapt this code instead:</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: registry-ca
  namespace: kube-system
  labels:
    k8s-app: registry-ca
spec:
  template:
    metadata:
      labels:
        name: registry-ca
    spec:
      containers:
      - name: registry-ca
        image: busybox
        command: [ 'sh' ]
        args: [ '-c', 'cp /home/core/registry-ca /etc/docker/certs.d/my-private-insecure-registry.com/ca.crt &amp;&amp; exec tail -f /dev/null' ]
        volumeMounts:
        - name: etc-docker
          mountPath: /etc/docker/certs.d/my-private-insecure-registry.com
        - name: ca-cert
          mountPath: /home/core
      terminationGracePeriodSeconds: 30
      volumes:
      - name: etc-docker
        hostPath:
          path: /etc/docker/certs.d/my-private-insecure-registry.com
      - name: ca-cert
        secret:
          secretName: registry-ca
</code></pre>
<h1 id="known-limitations-edit-2021-sfjo">Known limitations (edit 2021)</h1>
<p>According to these Kubernetes answers (<a href="https://github.com/kubernetes/kubernetes/issues/83781#issuecomment-542767227" rel="noreferrer">here</a> and <a href="https://github.com/kubernetes/kubernetes/issues/93479#issuecomment-664656885" rel="noreferrer">here</a>) to related github issues, a Kubernetes volume path cannot contain a colon. Therefore, this solution is not valid for registries that communicate securely with a self-signed certificate on specific ports (for example 5000).</p>
<p>In such case, please see Gary Plattenburg's answer to create the directory in the shell command instead of using Kubernetes to handle it during the mount.</p>
