vSphere with Tanzu: Harbor

Changing the certificates in Harbor

Introduction

VMware Cloud Foundation (VCF) is a multi-cloud platform that provides a full-stack hyper-converged infrastructure (HCI) that is made for modernising data centers and deploying modern container-based applications.

VMware Avi load balancer (Avi) is a 100% software-defined multi-cloud application services platform with Software Load Balancers, Intelligent WAF (iWAF), and Container Ingress.

All modern applications use load balancing nowadays. Load balancing is the process of distributing network traffic across multiple servers.

Normally i would blog about Avi. I wanted to use Harbor that comes with vSphere with Tanzu for my ako/amko deployment.
Update: While writing the blog, i took the time to re-install vSphere with Tanzu. Now I am using Avi

The goal of this blog

The goal of this blog is to explain how to install Habor Service on the Supervisor cluster and replace Harbor certificates.
I will not go over the installation of VCF 5.2 itself. You might already have DRI (Developer Ready Infrastructure) configured. Harbor is then already installed as part of that.

My lab setup

For my setup, I am using the following:
VCF 5.2.1
vCenter 8.0u3b
NSX 4.2.1.0
ESX 8.0.3
Avi 22.1.7

Lab setup diagram

Preparation

Please refer to installing service and installing Contour
It is important to have Contour running before you continue.
This blog does require you to have vSphere with Tanzu running.
You can also configure DRI (Developer Ready Infrastructure). See validated solution

Optional: If you want to use Avi, you need to onboard Avi to NSX before you install DRI.
A friend of mine wrote a good blog about how to do this. You can find it here.
Once onboarded, Tanzu and Avi will take care of the rest.

Installation

1. Install Harbor service.


Select Add New Service

Follow the link to GitHub. Here you will find configuration files for various services.

Download both Harbor v2.9.1 and values for v2.9.1

Press Upload and then finish.

Go to Action->Manage Service

Select the Supervisor and press Next

Paste in the values config (change setting where needed.
Add tlsCertificateSecretName: harbor-cert (This is the tls-secret you are going to use.)
Press finish. Harbor will now install.

The installation will fail because the harbor-cert secret does not exist yet.

2. Creating the certificates

I am using Microsoft AD as CA. I have chosen MS CA, because sddc mananager can use MS CA as certificate manager.

Create CSR

Create a CSR. Important note here, you should use SAN
I am using OpenSSL to create the CSR.

My OpenSSL config file

[ req ]
default_bits       = 2048
distinguished_name = req_distinguished_name
req_extensions     = req_ext
[ req_distinguished_name ]
countryName                = Country Name (NL)
stateOrProvinceName        = State or Province Name (ZH)
localityName               = Locality Name (FQ)
organizationName           = Organization Name (FQDN)
commonName                 = Common Name (e.g. server FQDN)
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
DNS.1   = harbor.sfo.rainpole.io

Run the following command. Openssl will create the file CSR.csr and the key file tls.key

openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout tls.key -config config
<snip>
-----
Country Name (NL) []:NL
State or Province Name (ZH) []:ZH
Locality Name (FQ) []:FQ
Organization Name (FQDN) []:FQDN
Common Name (e.g. server FQDN) []:harbor.sfo.rainpole.io

Request the certificate

Go to the URL of your certsrv
In my setup it is https://rpl-ad01.rainpole.io/certsrv

Paste the CSR you have created and select Web Server. Press Submit

Select Base64 encoded.
Press Download certificate chain. This will download the file certnew.p7b

Extract the certificate and CA cert.

openssl pkcs7 -inform PEM -outform PEM -in certnew.p7b -print_certs > certificate_bundle


Then copy the certificate from the file certificate_bundle to tls.crt and ca.crt (only between —–BEGIN CERTIFICATE—– and —–END CERTIFICATE—–)

You should now have 3 files:
ca.crt
tls.crt
tls.key

#Change to the harbor context
kubectl config use-context svc-harbor-domain-c9

#Create the harbor-cert secret
kubectl create secret generic harbor-cert --from-file=ca.crt=ca.crt --from-file=tls.crt=tls.crt --from-file=tls.key=tls.key  --dry-run=client -o yaml | kubectl apply -f -
secret/harbor-cert created

Now you need to go back to the Service configuration. You do not need to change anything.
Click next and then Finish.

Now Harbor will configure correctly. (If not. Retry the Service configuration again.)

The to test if Harbor is working.
You can find the IP address here. (Add this to the DNS. In my case, it is harbor.sfo.rainpole.io A 192.168.21.3.) The IP address in the browser will not work because of how Contour is configured.
You can find the correct ip here:

Or get the IP from Avi if you are using that:

Go to the Url.
As you can see, I do not have a certificate warning.
Please note: You might have to add your CA to the trust on the machine you are using your browser on.
See at the end of this blog under Additional: trust certificates

3. Add CA certificate to Tanzu workload cluster

Now for the next step.
You might notice you will get an error when pulling from Harbor.
The solution is adding the CA certificate to the Tanzu cluster.
Link to the documentation: here

  Warning  Failed              10s              kubelet                  Failed to pull image "harbor.sfo.rainpole.io:443/ako/ako-gateway-api:1.12.1": failed to pull and unpack image "harbor.sfo.rainpole.io:443/ako/ako-gateway-api:1.12.1": failed to resolve reference "harbor.sfo.rainpole.io:443/ako/ako-gateway-api:1.12.1": failed to do request: Head "https://harbor.sfo.rainpole.io:443/v2/ako/ako-gateway-api/manifests/1.12.1": tls: failed to verify certificate: x509: certificate signed by unknown authority

Te following needs to be added to your cluster config file.

- name: trust
  value:
    additionalTrustedCAs:
    - name: additional-ca-1

Here is my cluster config file as an example. Clustername tkgs-cluster01 in namespace chris

tkgs-cluster01.yaml
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  name: tkgs-cluster01
  namespace: chris
spec:
  clusterNetwork:
    services:
      cidrBlocks: ["10.6.64.0/22"]
    pods:
      cidrBlocks: ["10.6.68.0/22"]
    serviceDomain: "cluster.local"
  topology:
    class: tanzukubernetescluster
    version: v1.30.1---vmware.1-fips-tkg.5
    controlPlane:
      replicas: 1
      metadata:
        annotations:
          run.tanzu.vmware.com/resolve-os-image: os-name=ubuntu
    workers:
      machineDeployments:
        - class: node-pool
          name: node-pool-01
          replicas: 1
          metadata:
            annotations:
              run.tanzu.vmware.com/resolve-os-image: os-name=ubuntu
    variables:
      - name: vmClass
        value: best-effort-small
      - name: storageClass
        value: vsan-default-storage-policy
      - name: trust
        value:
          additionalTrustedCAs:
          - name: additional-ca-1

We need to create the following secret in the chris namespace.

tkgs-cluster01-user-trusted-ca-secret.yaml
apiVersion: v1
data:
  additional-ca-1: TFMwdEx.....
kind: Secret
metadata:
  name: tkgs-cluster01-user-trusted-ca-secret
  namespace: chris
type: Opaque

The value of the secret’s data map is a user-defined string which is the name for the CA certificate (additional-ca-1 in this example) whose value is the CA certificate in PEM format that is double base64-encoded.
In the metadata section, the secret must be named CLUSTER-NAME-user-trusted-ca-secret, where CLUSTER-NAME is the name of the Cluster. This secret must be created in the same vSphere Namespace as the Cluster.

To double base64-encode the contents of your CA certificate, go to the directory where you created the CSR earlier. The output from the following command needs to be added in the additional-ca-1 field.

base64 -w 0 ca.crt | base64 -w 0
TFMwdEx...

#change to the correct context
kubectl config use-context chris
kubectl apply -f tkgs-cluster01-user-trusted-ca-secret.yaml

#create the cluster
kubectl apply -f tkgs-cluster01.yaml

Warning: If you add additionalTrustedCAs to an already running cluster, Tanzu will create new master and worker nodes and delete the old ones. Please keep that in mind!

When we look back now to the pulling of the images for the pods, you can see it has no errors anymore.

  Normal  Pulled              2m31s                  kubelet                              Successfully pulled image "projects.registry.vmware.com/ako/ako:1.12.1" in 16.551s (31.568s including waiting). Image size: 61150904 bytes.
  Normal  ValidatedUserInput  2m27s (x2 over 2m28s)  avi-kubernetes-operator              User input validation completed.
  Normal  Pulled              2m11s                  kubelet                              Successfully pulled image "harbor.sfo.rainpole.io:443/ako/ako-gateway-api:1.12.1" in 5.689s (20.088s including waiting). Image size: 61592133 bytes.

Additional: trust certificates

To trust the certificates, you might need to ad the CA cert to the trust of your OS.

Windows:
1. Launch MMC (mmc.exe).
2. Choose File > Add/Remove Snap-ins.
3. Choose Certificates, then choose Add.
4. Choose My user account.
If you want the cert to be available for all users, choose local computer
5. Import the ca.crt file.

If you want the cert to be available for all users

Ubuntu:

sudo apt-get install -y ca-certificates
sudo cp ca.crt /usr/local/share/ca-certificates/rainpole.crt
sudo update-ca-certificates

Final words

It would be great if rotation of the certificates in Harbor could be done from the SDDC manager.
Maybe it is possible with cert-manager. I have briefly looked at it, but i am struggling with cert-manager using MS CA.

I you have any question or comment or ideas, let me know.

Leave Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.