## Kubernetes Integration

The Kubernetes integration allows you to run Headplane and Headscale together
in a cluster. It allows you to unlock full functionality such as automatic
reloading of ACLs, DNS management, and Headscale configuration management.

Currently there are a few limitations to the Kubernetes integration:
- Headplane and Headscale need to run in the same Pod and share the same
  process space for the integration to work correctly due to a limitation in
  the Kubernetes API.

- The only supported methods of deploying the integration are through a
  `Deployment` or `Pod` (more coming soon). You can still get around this with
  the `HEADSCALE_INTEGRATION_UNSTRICT` variable, but it's not recommended.

- The integration will assume that the Headscale container will always restart
  because the integration relies on a system call that will exit the container.

### Deployment

In order to ensure Headplane can read Kubernetes resources, you'll need to
grant additional RBAC permissions to the default `ServiceAccount` in the
namespace. This can be done with the following:
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: headplane-agent
  namespace: default # Adjust namespace as needed
rules:
- apiGroups: ['']
  resources: ['pods']
  verbs: ['get', 'list']
- apiGroups: ['apps']
  resources: ['deployments']
  verbs: ['get', 'list']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: headplane-agent
  namespace: default # Adjust namespace as needed
roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: Role
    name: headplane-agent
subjects:
- kind: ServiceAccount
  name: default # If you use a different service account, change this
  namespace: default # Adjust namespace as needed
```

Keep in mind you'll need to make `PersistentVolumeClaim`s for the data and that
they need to be either `ReadWriteOnce` or `ReadWriteMany` depending on your
topology. Additionally, you can abstract environment variables and configuration
away into a `ConfigMap` or `Secret` for easier management.

The important parts of this deployment are the `HEADSCALE_INTEGRATION` and
`DEPLOYMENT_NAME` environment variables. The `HEADSCALE_INTEGRATION` variable
should be set to `kubernetes` and the `POST_NAME` variable should be set
to the name of the pod (done using the Downward API below).

> If you are having issues with validating `shareProcessNamespace`, you can
set `HEADSCALE_INTEGRATION_UNSTRICT` to `true` to disable the strict checks.

A basic deployment of the integration would look like this. Keep in mind that
you are responsible for setting up a reverse-proxy via an `Ingress` or `Service`
otherwise Headplane will not work:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: headplane
  namespace: default # Adjust namespace as needed
  labels:
    app: headplane
spec:
  replicas: 1
  selector:
    matchLabels:
      app: headplane
  template:
    metadata:
      labels:
        app: headplane
    spec:
      shareProcessNamespace: true
      serviceAccountName: default
      containers:
      - name: headplane
        image: ghcr.io/tale/headplane:latest
        env:
        - name: COOKIE_SECRET
          value: 'abcdefghijklmnopqrstuvwxyz'
        - name: HEADSCALE_INTEGRATION
          value: 'kubernetes'
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        volumeMounts:
        - name: headscale-config
          mountPath: /etc/headscale

      - name: headscale
        image: headscale/headscale:0.23.0-beta2
        command: ['serve']
        env:
        - name: TZ
          value: 'America/New_York'
        volumeMounts:
        - name: headscale-data
          mountPath: /var/lib/headscale
        - name: headscale-config
          mountPath: /etc/headscale

      volumes:
        - name: headscale-data
          persistentVolumeClaim:
            claimName: headscale-data
        - name: headscale-config
          persistentVolumeClaim:
            claimName: headscale-config
```

> For a breakdown of each configuration variable, please refer to the
[Configuration](/docs/Configuration.md) guide. 
> It explains what each variable does, how to configure them, and what the
default values are.
