Goglides Dev

Goglides Dev is a community of amazing users

We are working on this space so that IT professionals can grow together.

Create account Log in
Balkrishna Pandey
Balkrishna Pandey

Posted on

Openshift: How to pull from secure docker registry which is using self signed certificate

In this blog post, I am going to cover the following stuff,

  1. Create self-signed certificates using the OpenSSL utility
  2. Create a Private Docker registry, use the self-signed certificate created in step 1 and enable basic authentication using htpasswd
  3. Enable Openshift to serve from a private docker registry

What is a Self Signed Certificate?

Before creating certificates, let's understand what a self-signed certificate is. A self-signed certificate is a certificate signed by its creator rather than by an official certificate authority(CA). Browsers or operating systems do not trust self-signed certificates unless you explicitly tell them to trust the certificate.

Why Use Self-Signed Certificates?

There are some use cases where it is okay to use self-signed certificates. For instance, you can use self-signed certificates to set up a test or an internal development environment.

Creating self-signed certificates is very easy and does not require any third-party tools. To create self-signed certificates, you can use the OpenSSL utility pre-installed on most Linux distributions.

Creating self-signed certificates using the OpenSSL utility:

We will use the OpenSSL tool to generate keys and certificates. You can find this tool in most of the Linux distributions by default. If not, install it using your package manager. I am using Fedora here.

sudo dnf install -y openssl
Enter fullscreen mode Exit fullscreen mode

You can also find packages for Windows, MAC, and Linux flavors.

Create Certificate Authority

First, we must create a private key and certificate for the Certificate Authority(CA). The CA is used to sign the server certificate we will generate later.

Run the following command to create a private key and certificate for the CA. You can use any name for the CA. I am using ca here.

Create a directory to store all the keys and certificates. You can make this directory anywhere you want. I am creating this inside my home directory.

mkdir openssl && cd openssl
Enter fullscreen mode Exit fullscreen mode

Now execute the following openssl command to create a rootCA.key private key and rootCA.crt. Replace registry.goglides.dev with your domain name or IP address.

openssl req -x509 \
            -sha256 -days 356 \
            -nodes \
            -newkey rsa:2048 \
            -subj "/CN=registry.goglides.dev/C=US/L=San Fransisco" \
            -keyout rootCA.key -out rootCA.crt 
Enter fullscreen mode Exit fullscreen mode

Create Certificate for registry.goglides.dev

  • Create the Server Private Key
openssl genrsa -out server.key 2048
Enter fullscreen mode Exit fullscreen mode
  • Create the Server CSR (Certificate Signing Request) Configuration
cat > csr.conf <<EOF
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = US
ST = Colorado
L = Denver
O = Goglides
OU = Goglides Dev
CN = registry.goglides.dev

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = registry.goglides.dev
DNS.2 = www.registry.goglides.dev
IP.1 = 192.168.7.88
IP.2 = 192.168.7.203
EOF
Enter fullscreen mode Exit fullscreen mode
  • Generate Certificate Signing Request (CSR) Using Server Private Key
openssl req -new -key server.key -out server.csr -config csr.conf
Enter fullscreen mode Exit fullscreen mode
  • Create an external file
cat > cert.conf <<EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = registry.goglides.dev
EOF
Enter fullscreen mode Exit fullscreen mode
  • Generate an SSL certificate With a self-signed CA
openssl x509 -req \
    -in server.csr \
    -CA rootCA.crt -CAkey rootCA.key \
    -CAcreateserial -out server.crt \
    -days 365 -extensions cert.conf
Enter fullscreen mode Exit fullscreen mode
  • Create htpasswd file for the registry.goglides.dev
htpasswd -bBc htpasswd.goglides.dev goglides-dev SecureSecrets
Enter fullscreen mode Exit fullscreen mode

In above command

  • -b Use the password from the command line rather than prompting it.
  • -B Force bcrypt encryption of the password, Only bcrypt is supported at the moment
  • -c Create a new file htpasswd.goglides.dev with the given username and password

If the htpasswd.goglides.dev file is missing, the file will be created and provisioned with a default user and an automatically generated password. The password will be printed to stdout. You can check container logs using docker logs registry for the password; the default username is docker.

Create docker config

cat <<EOF > config.yml
version: 0.1
http:
  secret: AwesomeSecret123
  host: https://registry.goglides.dev
auth:
  htpasswd:
    realm: basic-realm
    path: /etc/docker/registry/htpasswd.goglides.dev
storage:
  filesystem:
    rootdirectory: /var/lib/registry
    maxthreads: 100
EOF
Enter fullscreen mode Exit fullscreen mode

Create a docker registry

mkdir certs
cp server.crt certs/server.crt
cp server.key certs/server.key
Enter fullscreen mode Exit fullscreen mode

And run the registry as follows,

docker run -d \
  --restart=always \
  --name registry \
  -v "$(pwd)"/htpasswd.goglides.dev:/etc/docker/registry/htpasswd.goglides.dev \
  -v "$(pwd)"/config.yml:/etc/docker/registry/config.yml \
  -v "$(pwd)"/certs:/certs \
  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/server.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/server.key \
  -p 443:443 \
  registry:2
Enter fullscreen mode Exit fullscreen mode

Verification

Now verify docker login, add 127.0.0.1 registry.goglides.dev to /etc/hosts, and run following command

docker login registry.goglides.dev -u goglides-dev -p SecureSecrets
Enter fullscreen mode Exit fullscreen mode

Output:

WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Login Succeeded
Enter fullscreen mode Exit fullscreen mode

Create Kubernetes secrets

  • Create Kubernetes as follows so that you can pass this secret to imagePullSecrets later on
oc create secret docker-registry docker-pull-secret --docker-server=https://registry.goglides.dev/ --docker-username=goglides-dev --docker-password='SecureSecrets'
Enter fullscreen mode Exit fullscreen mode

If you do not want to pass imagePullSecrets and your application is using a default service account, you can link this secret to default service account as follows,

oc secrets link default docker-pull-secret --for=pull
Enter fullscreen mode Exit fullscreen mode

Allow the docker registry to be used by the OpenShift container platform

  • Create a configMap with server.crt as follows,
oc create configmap external-registry-config -n openshift-config --from-file=registry.goglides.dev=certs/server.crt
Enter fullscreen mode Exit fullscreen mode

Now patch the image.config.openshift.io/cluster object,

oc patch image.config.openshift.io/cluster --patch '{"spec":{"additionalTrustedCA":{"name":"external-registry-config"}}}' --type=merge
Enter fullscreen mode Exit fullscreen mode

You can verify the object using the following command,

oc get image.config.openshift.io/cluster -o json | jq .spec.additionalTrustedCA
Enter fullscreen mode Exit fullscreen mode

Output:

{
 "name": "external-registry-config"
}
Enter fullscreen mode Exit fullscreen mode

Verify that imagePullSecrets are there in the service account

  • oc get sa default -o json | jq '.imagePullSecrets[]' Output:
{
 "name": "default-dockercfg-stgqk"
}
{
 "name": "docker-pull-secret"
}
Enter fullscreen mode Exit fullscreen mode

Verification

Let's verify whether OpenShift can pull the image from this registry or not. First, publish an image to this docker registry.

docker pull nginx
docker tag nginx registry.goglides.dev/nginx
Enter fullscreen mode Exit fullscreen mode

And push this image to registry

docker push registry.goglides.dev/nginx
Enter fullscreen mode Exit fullscreen mode

Output:

Using default tag: latest
The push refers to repository [registry.goglides.dev/nginx]
de100bd247e0: Pushed 
1d561d938628: Pushed 
c03189a5ef70: Pushed 
305b0db3a210: Pushed 
1c99a7efe9d9: Pushed 
43b3c4e3001c: Pushed 
latest: digest: sha256:33cef86aae4e8487ff23a6ca16012fac28ff9e7a5e9759d291a7da06e36ac958 size: 1570
Enter fullscreen mode Exit fullscreen mode

You can validate the image is present or not as follows,

curl --cacert server.crt -u 'goglides-dev:SecureSecrets' https://registry.goglides.dev/v2/_catalog
Enter fullscreen mode Exit fullscreen mode

Output:

{"repositories":["nginx"]}
Enter fullscreen mode Exit fullscreen mode

Now create a pod to pull from this registry,

oc run nginx --image registry.goglides.dev/nginx
Enter fullscreen mode Exit fullscreen mode

Output:

pod/nginx created
Enter fullscreen mode Exit fullscreen mode

The nginx pod should be up and running.

oc get pods
Enter fullscreen mode Exit fullscreen mode

Output:

nginx   1/1   Running      0     41s
Enter fullscreen mode Exit fullscreen mode

Discussion (0)