Commit 3d8f8dc3 authored by Nikos Psaromanolakis's avatar Nikos Psaromanolakis
Browse files

Edit README.md

parent c5024e91
Loading
Loading
Loading
Loading
+225 −192
Original line number Diff line number Diff line
# ocm-managed
# ocm-hub

Helm chart for registering a Kubernetes cluster as an **Open Cluster Management (OCM) managed cluster** with integrated **OpenZiti tunneling**.
Helm chart for deploying and configuring an **Open Cluster Management (OCM) hub** with integrated **OpenZiti tunneling**.

## Features

* Retrieves OCM registration information from the hub.
* Executes `clusteradm join`.
* Installs the OCM Klusterlet agents.
* Creates and enrolls an OpenZiti identity for the managed cluster.
* Initializes the OCM hub with `clusteradm init`.
* Pre-creates configured `ManagedCluster` resources.
* Automatically accepts managed-cluster registration CSRs.
* Creates and enrolls the OpenZiti hub identity.
* Deploys the OpenZiti `ziti-edge-tunnel`.
* Checks direct connectivity to the hub Kubernetes API.
* Creates a cluster-specific OpenZiti Dial policy when direct hub connectivity is unavailable.
* Creates the OpenZiti `ocm-hub-api` service used to expose the hub Kubernetes API.
* Reconciles the configured managed-cluster list on Helm upgrades.
* Cleans up OCM and OpenZiti resources during Helm uninstall.

## Registration Flow
## Deployment Flow

```text
Helm install ocm-managed
Helm install ocm-hub
        |
        v
OpenZiti bootstrap
        |
        +--> Create cluster1-ziti identity
        +--> Create hub-ziti identity
        +--> Retrieve enrollment JWT
        +--> Enroll identity
        +--> Create Kubernetes identity Secret
@@ -30,43 +30,47 @@ OpenZiti bootstrap
Start ziti-edge-tunnel
        |
        v
Read hub API endpoint from supplied hub kubeconfig
Create OpenZiti hub API service
        |
        v
Check direct hub connectivity
        |
        +-----------------------------+
        |                             |
     reachable                    unreachable
        |                             |
        |                             v
        |                    Authenticate to OpenZiti
        |                             |
        |                             v
        |                    Create Dial policy
        |                             |
        +-------------+---------------+
        +--> Create intercept.v1
        +--> Create host.v1
        +--> Create Bind policy
        |
        v
              clusteradm get token
Initialize OCM hub
clusteradm init --wait
        |
        v
          Create local managed kubeconfig
OCM Hub Control Plane
        |
        v
                clusteradm join
Create configured ManagedCluster resources
        |
        v
               Install Klusterlet
Managed cluster sends registration CSR
        |
        v
             Registration CSR -> Hub
Automatic CSR acceptance
        |
        v
              Registration accepted
Managed cluster becomes
JOINED=True / AVAILABLE=True
```

The chart combines two responsibilities:

```text
OCM
 |
                      v
              Managed cluster ready
 +--> cluster registration
 +--> lifecycle management
 +--> ManagedCluster reconciliation

OpenZiti
 |
 +--> secure overlay connectivity
 +--> hub identity management
 +--> hub API service exposure
```

## OpenZiti Dependency
@@ -92,8 +96,8 @@ helm dependency update
Example `values.yaml`:

```yaml
clusterName: cluster1
hubKubeconfigBase64: ""
managedClusters:
  - cluster1

openziti:
  enabled: true
@@ -104,8 +108,8 @@ openziti:
    password: "<OPENZITI-PASSWORD>"

  identity:
    name: "cluster1-ziti"
    secretName: "ziti-cluster1-identity"
    name: "hub-ziti"
    secretName: "ziti-hub-identity"

  hubApi:
    serviceName: "ocm-hub-api"
@@ -118,7 +122,7 @@ ziti-edge-tunnel:
    tag: "1.1.5"

  secret:
    existingSecretName: "ziti-cluster1-identity"
    existingSecretName: "ziti-hub-identity"
    keyName: persisted-identity

  tolerations:
@@ -128,16 +132,15 @@ ziti-edge-tunnel:
### Configuration Reference

| Value                                        | Description                                                                                                                                     |
| -------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `clusterName`                                | Name under which this Kubernetes cluster is registered in OCM.                           |
| `hubKubeconfigBase64`                        | Base64-encoded kubeconfig used to access the OCM hub during registration.                |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `managedClusters`                            | List of managed clusters that should exist on the OCM hub. The chart creates missing entries and removes entries that are no longer configured. |
| `openziti.enabled`                           | Enables the OpenZiti integration and `ziti-edge-tunnel` dependency.                                                                             |
| `openziti.controller.url`                    | OpenZiti Controller management API endpoint.                                                                                                    |
| `openziti.controller.username`               | Username used by the bootstrap and join Jobs to authenticate to the OpenZiti Controller. |
| `openziti.controller.username`               | Username used by the bootstrap and configuration Jobs to authenticate to the OpenZiti Controller.                                               |
| `openziti.controller.password`               | Password used to authenticate to the OpenZiti Controller.                                                                                       |
| `openziti.identity.name`                     | OpenZiti identity created for this managed cluster.                                      |
| `openziti.identity.name`                     | OpenZiti identity created for the hub cluster.                                                                                                  |
| `openziti.identity.secretName`               | Kubernetes Secret where the enrolled OpenZiti identity JSON is stored.                                                                          |
| `openziti.hubApi.serviceName`                | Name of the OpenZiti service exposing the OCM hub Kubernetes API.                        |
| `openziti.hubApi.serviceName`                | Name of the OpenZiti service used to expose the hub Kubernetes API.                                                                             |
| `ziti-edge-tunnel.image.*`                   | Container image configuration for the OpenZiti tunneler.                                                                                        |
| `ziti-edge-tunnel.secret.existingSecretName` | Secret mounted by the tunneler. This should match `openziti.identity.secretName`.                                                               |
| `ziti-edge-tunnel.secret.keyName`            | Key inside the Secret containing the OpenZiti identity JSON.                                                                                    |
@@ -154,56 +157,9 @@ ziti-edge-tunnel.secret.existingSecretName
              +----> consumed by ziti-edge-tunnel
```

## Hub Kubeconfig

The managed chart requires a kubeconfig that points to the OCM hub Kubernetes API.

The kubeconfig is passed as a base64-encoded value through:

```yaml
hubKubeconfigBase64: ""
```

Encode the hub kubeconfig with:

```bash
base64 -w0 hub-kubeconfig.yaml
```

During installation, the kubeconfig is stored in a Kubernetes Secret and mounted into the join Job as:

```text
/hub/kubeconfig
```

It is used to communicate with the OCM hub and retrieve the registration token.

The chart also creates a temporary kubeconfig for the local managed cluster:

```text
/tmp/managed-kubeconfig
```

The two kubeconfigs have different purposes:

```text
/hub/kubeconfig
      |
      +--> OCM hub
      |
      +--> clusteradm get token


/tmp/managed-kubeconfig
      |
      +--> local managed cluster
      |
      +--> clusteradm join
```

## OpenZiti Bootstrap

During the initial Helm installation, the chart automatically creates the OpenZiti identity required by the managed cluster.
During the initial Helm installation, the chart automatically creates the OpenZiti identity required by the hub.

The bootstrap process is:

@@ -211,7 +167,7 @@ The bootstrap process is:
Authenticate to OpenZiti Controller
        |
        v
Create cluster1-ziti identity
Create hub-ziti identity
        |
        v
Retrieve enrollment JWT
@@ -224,7 +180,7 @@ Generate identity.json
        |
        v
Create Kubernetes Secret
ziti-cluster1-identity
ziti-hub-identity
        |
        v
Start ziti-edge-tunnel
@@ -236,31 +192,92 @@ The generated identity JSON is stored in the Kubernetes Secret under the key:
persisted-identity
```

The `ziti-edge-tunnel` subchart mounts this Secret and starts the OpenZiti tunneler using the enrolled managed-cluster identity.
The `ziti-edge-tunnel` subchart mounts this Secret and starts the tunneler using the enrolled hub identity.

## OCM Hub Initialization

After the OpenZiti tunneler is ready, the chart initializes the OCM hub using:

```bash
clusteradm init --wait
```

This installs the OCM hub control plane.

## Direct Connectivity and OpenZiti Fallback
The chart then creates the configured `ManagedCluster` resources.

Before running the OCM registration, the chart checks whether the hub Kubernetes API is directly reachable.
For example:

The hub API endpoint is extracted from:
```yaml
apiVersion: cluster.open-cluster-management.io/v1
kind: ManagedCluster
metadata:
  name: cluster1
spec:
  hubAcceptsClient: true
  leaseDurationSeconds: 60
```

The hub-side acceptance CronJob automatically approves registration requests for the clusters configured in `managedClusters`.

Conceptually:

```text
/hub/kubeconfig
Managed cluster
      |
      v
Registration CSR
      |
      v
accept-clusters CronJob
      |
      v
clusteradm accept
      |
      v
CSR approved
      |
      v
ManagedCluster connected
```

If direct connectivity works:
## OCM Hub API through OpenZiti

The hub chart creates the OpenZiti objects required to expose the Kubernetes API through the OpenZiti overlay.

Conceptually:

```text
Managed Cluster
hub-ziti
    |
    | Bind
    v
ocm-hub-api
    |
    +--> intercept.v1
    |
      +-------- direct --------> Hub API
    +--> host.v1
            |
            v
       HUB_IP:6443
```

The `host.v1` configuration points to the actual Kubernetes API endpoint on the hub.

For example:

```text
192.168.5.185:6443
```

No OpenZiti Dial policy is created.
The `intercept.v1` configuration uses the same hub API address and port.

The managed chart can later create a cluster-specific Dial policy when direct communication with this endpoint is unavailable.

If direct connectivity is unavailable:
The resulting OpenZiti path is:

```text
Managed Cluster
cluster1-ziti
      |
      | Dial
@@ -273,55 +290,53 @@ hub-ziti
      |
      v
Hub Kubernetes API
HUB_IP:6443
```

The managed chart creates only the cluster-specific Dial policy.

For example:

```text
ocm-hub-api-cluster1-dial
```

The following OpenZiti objects are created and owned by the `ocm-hub` chart:
The hub chart owns the following OpenZiti objects:

```text
hub-ziti
ocm-hub-api
ocm-hub-api-intercept
ocm-hub-api-host
ocm-hub-api-bind
```

The managed chart only creates the Dial permission required for its own OpenZiti identity to consume the hub API service.
The managed charts only create their own cluster-specific Dial policies when required.

After OpenZiti connectivity becomes available, the OCM registration process continues using the same hub API endpoint contained in the kubeconfig.
## Managed Cluster Configuration

## OCM Join Process
Managed clusters are declared in `values.yaml`:

The join Job retrieves the OCM registration information from the hub:
```yaml
managedClusters:
  - cluster1
  - cluster2
```

```bash
clusteradm get token
The list represents the desired OCM managed-cluster state.

To add a cluster:

```yaml
managedClusters:
  - cluster1
  - cluster2
  - cluster3
```

It then executes:
Apply the change with:

```bash
clusteradm join \
  --hub-token <token> \
  --hub-apiserver <hub-api> \
  --wait \
  --cluster-name <cluster-name>
helm upgrade ocm-hub . -n ocm-hub
```

`clusteradm join` installs and configures the OCM Klusterlet on the managed cluster.

The Klusterlet includes the OCM agents responsible for communication with the hub, primarily:
The chart creates the missing `ManagedCluster` resources.

* `registration-agent`
* `work-agent`
To remove a cluster, remove it from the list and run the same Helm upgrade.

The registration agent creates the registration CSR on the hub. The hub-side acceptance CronJob subsequently approves the registration.
The chart reconciles the current OCM `ManagedCluster` resources with the configured list.

## Installation

@@ -331,91 +346,109 @@ Update Helm dependencies:
helm dependency update
```

Install the managed chart:
Install the hub chart:

```bash
helm install ocm-managed . \
  -n ocm-managed \
helm install ocm-hub . \
  -n ocm-hub \
  --create-namespace \
  --set clusterName=cluster1 \
  --set hubKubeconfigBase64="$(base64 -w0 hub-kubeconfig.yaml)" \
  --timeout 10m
```

## Verification

Check the Klusterlet:
Check the OCM hub:

```bash
kubectl get klusterlet
kubectl get clustermanager
```

Check the OCM agents:
Check managed clusters:

```bash
kubectl get pods -n open-cluster-management-agent
kubectl get managedclusters
```

Expected after registration:

```text
NAME       HUB ACCEPTED   MANAGED CLUSTER URLS   JOINED   AVAILABLE
cluster1   true                                  True     True
```

Check registration CSRs:

```bash
kubectl get csr
```

Check the automatic acceptance CronJob:

```bash
kubectl get cronjob -n ocm-hub
```

Check the OpenZiti tunneler:

```bash
kubectl get pods -n ocm-managed \
kubectl get pods -n ocm-hub \
  -l app.kubernetes.io/name=ziti-edge-tunnel
```

Check the tunneler logs:

```bash
kubectl logs -n ocm-managed \
kubectl logs -n ocm-hub \
  -l app.kubernetes.io/name=ziti-edge-tunnel
```

Check the tunneler image:

```bash
kubectl get pods -n ocm-managed \
kubectl get pods -n ocm-hub \
  -l app.kubernetes.io/name=ziti-edge-tunnel \
  -o jsonpath='{range .items[*]}{.metadata.name}{" -> "}{.spec.containers[*].image}{"\n"}{end}'
```

## OpenZiti Service Model

The current integration uses OpenZiti to provide connectivity to the OCM hub Kubernetes API when the direct network path is unavailable.
## Helm Upgrade Behaviour

The same model can later be reused for application-to-application connectivity across managed clusters.

For example:
The OpenZiti identity is created during the initial installation and reused during normal Helm upgrades.

```text
Cluster A                         Cluster B
helm install
     |
     +--> Create OpenZiti identity
     +--> Enroll identity
     +--> Create identity Secret
     +--> Start tunneler
     +--> Initialize OCM hub

frontend                         backend
   |                                ^
   |                                |
   +------ OpenZiti Service --------+
helm upgrade
     |
     +--> Reuse existing OpenZiti identity
     +--> Reuse existing identity Secret
     +--> Reconcile managedClusters
     +--> Apply configuration changes
```

The orchestrator can dynamically create the required OpenZiti service, `intercept.v1`, `host.v1`, Bind policy, and Dial policy after workload placement.

This allows connectivity without requiring prior knowledge of:

* the remote cluster CNI;
* Pod CIDRs;
* Service CIDRs;
* direct Layer 3 connectivity between clusters.
This avoids unnecessary re-enrollment of the OpenZiti identity during normal chart upgrades.

## Uninstall

```bash
helm uninstall ocm-managed -n ocm-managed
helm uninstall ocm-hub -n ocm-hub
```

The cleanup hook removes:

* the Klusterlet;
* OCM agent resources and namespaces;
* the cluster-specific OpenZiti Dial policy, if present;
* the managed-cluster OpenZiti identity;
* the generated identity Secret;
* OpenZiti bootstrap Role and RoleBinding;
* OpenZiti bootstrap ServiceAccount.
* configured `ManagedCluster` resources;
* related registration CSRs;
* OCM hub resources;
* OCM namespaces and stale resources;
* the `ocm-hub-api` Bind policy;
* the `ocm-hub-api` OpenZiti service;
* the associated `intercept.v1` configuration;
* the associated `host.v1` configuration;
* the `hub-ziti` identity;
* the generated OpenZiti identity Secret;
* OpenZiti bootstrap RBAC resources.