# TLS Certificate

> Octelium documentation. Canonical page: <https://octelium.com/docs/octelium/latest/install/cluster/tls-certificate>.

> **Note:**
>
> If you are currently installing the single-node *Cluster* as shown in the quick installation guide (read more [here](https://octelium.com/docs/octelium/latest/overview/quick-install.md)), it is easier and more recommended to stick to the post-installation guide there as shown [here](https://octelium.com/docs/octelium/latest/overview/quick-install.md#post-installation).

The *Cluster* requires a main TLS certificate, issued by a public certificate authority such as Let's Encrypt, to serve the *Cluster*'s public *Services* (read more about public BeyondCorp *Services* [here](https://octelium.com/docs/octelium/latest/management/core/service/clientless.md)) and anonymous *Services* (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/anonymous-access.md)) over the internet. Such *Services* include the *Cluster*'s own *Services* such as the [*API Server*](https://octelium.com/docs/octelium/latest/reference/components.md#api-server) and the [*AuthServer*](https://octelium.com/docs/octelium/latest/reference/components.md#auth-server). Therefore, you should issue and set the *Cluster* TLS certificate as soon as you install the *Cluster* to begin using `octelium` and `octeliumctl` commands, and log in via the web portal of the *AuthServer*.

> **Note:**
>
> The *Cluster* installs an initial self-signed TLS certificate during the *Cluster* installation. You can use the `octelium` and `octeliumctl` commands before setting your real *Cluster* certificate, issued by a real CA such as Let's Encrypt, by setting `OCTELIUM_INSECURE_TLS` or `OCTELIUM_DEV` environment variables to `true` before using the `octelium` or `octeliumctl` commands.

Regardless of the certificate authority you use or the method you use to issue the TLS certificate, you will need to provide the issued certificate to the *Cluster* through a Kubernetes TLS secret with the name `cert-cluster` in the Kubernetes namespace `octelium` as shown in detail [here](#manually-setting-the-certificate).

## Cluster Domain Certificate

The *Cluster* certificate needs to include the following domains in the SAN list:

1. The *Cluster* domain `<DOMAIN>`.
2. The wildcard domain `*.<DOMAIN>`.
3. The wildcard domains `*.local.<DOMAIN>` and `*.default.local.<DOMAIN>`.

## Issuing the Certificate

There is no one canonical way to issue your *Cluster* certificate by a certificate authority. You can use [Let's Encrypt](https://letsencrypt.org/) via [Certbot](https://certbot.eff.org/instructions), for example, to issue a certificate for your *Cluster* domain for free.

### Certbot

Here is an example of issuing the certificate using the `certbot` CLI tool via a DNS challenge:

```bash
sudo certbot certonly --email <YOUR_EMAIL> --agree-tos --cert-name <DOMAIN> -d "<DOMAIN>,*.<DOMAIN>,*.local.<DOMAIN>" --manual --preferred-challenges dns
# Your certificate is stored by default in /etc/letsencrypt/live/<DOMAIN>/
```

### cert-manager

In a production environment, it is recommended to automate the process of issuing and rotating the *Cluster* certificate. You can also use a Kubernetes-based open source solution such as [cert-manager](https://cert-manager.io/). The following example shows the `ClusterIssuer` and `Certificate` cert-manager resources needed for a certificate that uses Let's Encrypt and Cloudflare.

The `ClusterIssuer` should look as follows:

```yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-cloudflare
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: contact-acme@<DOMAIN>
    privateKeySecretRef:
      name: letsencrypt-cloudflare-account
    solvers:
    - dns01:
        cloudflare:
          email: cloudflare-account@<DOMAIN>
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-key
      selector: {}
```

The `Certificate` should look like this:

```yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: octelium-cluster
  # !mark
  namespace: octelium
spec:
  # !mark
  secretName: cert-cluster
  issuerRef:
    name: letsencrypt-cloudflare
    kind: ClusterIssuer
  commonName: <DOMAIN>
  dnsNames:
    - <DOMAIN>
    - '*.<DOMAIN>'
    - '*.local.<DOMAIN>'
```

## Manually Setting the Certificate

Once you issue the certificate, you can manually provide it to the *Cluster* by creating a Kubernetes secret with the name `cert-cluster` in the namespace `octelium`. You can use the `kubectl create secret tls` command as follows:

```bash
kubectl create secret tls cert-cluster -n octelium --key </PATH/TO/PRIVATE_KEY.PEM> --cert </PATH/TO/CERT_CHAIN.PEM>
```

Alternatively, you can use the `octops cert` command to provide the same functionality as the `kubectl create/update secret tls` command above as follows:

```bash
octops cert <DOMAIN> --key </PATH/TO/PRIVATE_KEY.PEM> --cert </PATH/TO/CERT_CHAIN.PEM> --kubeconfig </PATH/TO/KUBECONFIG>
```

The *Cluster* watches for that specific Kubernetes secret and once it is created or updated, it is synchronized into an Octelium *Secret* resource.

## Namespace Certificates

As shown above, the *Cluster* TLS certificate only serves for direct subdomains of the *Cluster* domain. This makes it only useful for *Services* belonging to the `default` *Namespace* (read more about *Namespaces* [here](https://octelium.com/docs/octelium/latest/management/core/namespace.md)). If you want to enable public/BeyondCorp access (i.e. via `isPublic`) or/and just TLS over the client-based access (i.e. `isTLS` field), you will have to issue a TLS certificate that uses the wildcard domains `*.<NAMESPACE>.local.<DOMAIN>` and `*.<NAMESPACE>.<DOMAIN>`. You can set/rotate a *Namespace* certificate via the `octops cert` command via `--namespace` field. For example, if the *Namespace* is `production`, then the `octops cert` command is used as follows:

```bash
octops cert <DOMAIN> --key </PATH/TO/PRIVATE_KEY.PEM> --cert </PATH/TO/CERT_CHAIN.PEM> --kubeconfig </PATH/TO/KUBECONFIG> --namespace production
```

You can also directly use Kubernetes commands (e.g. `kubectl create secret`) or via the SDKs. The name of the Kubernetes secret needs to be `cert-ns-<NAMESPACE>`. For example, if the *Namespace* is `production`, then the `kubectl create secret` command is used as follows:

```bash
kubectl create secret tls cert-ns-production -n octelium --key </PATH/TO/PRIVATE_KEY.PEM> --cert </PATH/TO/CERT_CHAIN.PEM>
```
