> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Resources

> Reference for the Formal Kubernetes Operator CRDs

## FormalResource

Registers an in-cluster service as a Formal resource.

```yaml theme={null}
apiVersion: joinformal.com/v1
kind: FormalResource
metadata:
  name: orders-database
spec:
  technology: postgres
  hostname: postgres.default.svc.cluster.local
  port: 5432
```

### Spec

| Field        | Type   | Required | Description                                                                    |
| ------------ | ------ | -------- | ------------------------------------------------------------------------------ |
| `technology` | string | Yes      | Protocol type (`postgres`, `mysql`, `mongodb`, `http`, etc.)                   |
| `hostname`   | string | Yes      | In-cluster hostname of the backend service                                     |
| `port`       | int    | Yes      | Port of the backend service                                                    |
| `spaceId`    | string | No       | ID of the [Space](/docs/guides/core-concepts/spaces) to assign the resource to |
| `tls`        | object | No       | TLS configuration for the backend connection                                   |

### TLS Configuration

```yaml theme={null}
spec:
  tls:
    mode: verify-full
    minVersion: "TLSv1.2"
    caSecretRef:
      name: my-ca-secret
      key: ca.crt
```

| Field                  | Type   | Required | Description                                        |
| ---------------------- | ------ | -------- | -------------------------------------------------- |
| `tls.mode`             | string | No       | `disable`, `verify-ca`, or `verify-full` (default) |
| `tls.minVersion`       | string | No       | Minimum TLS version (e.g., `TLSv1.2`)              |
| `tls.caSecretRef.name` | string | No       | Kubernetes Secret containing the CA certificate    |
| `tls.caSecretRef.key`  | string | No       | Key within the Secret                              |

***

## FormalListener

Creates a listener on an existing Formal connector with routing rules.

```yaml theme={null}
apiVersion: joinformal.com/v1
kind: FormalListener
metadata:
  name: postgres
spec:
  connectorId: connector_abc123
  name: postgres
  port: 5432
  rules:
    - type: technology
      technology: postgres
```

### Spec

| Field         | Type   | Required | Description                                 |
| ------------- | ------ | -------- | ------------------------------------------- |
| `connectorId` | string | Yes      | ID of the Formal connector                  |
| `name`        | string | Yes      | Display name of the listener                |
| `port`        | int    | Yes      | Port the listener binds to on the connector |
| `rules`       | list   | No       | Routing rules for the listener              |

### Rules

Each rule routes traffic to one or more resources:

| Field         | Type   | Required | Description                                                           |
| ------------- | ------ | -------- | --------------------------------------------------------------------- |
| `type`        | string | Yes      | `resource` or `technology`                                            |
| `resourceRef` | string | No       | Name of a FormalResource in the same namespace (for `resource` rules) |
| `technology`  | string | No       | Technology name (for `technology` rules)                              |

When using `resource` rules, the operator resolves the `resourceRef` to the Formal resource ID automatically.

<Note>
  The connector itself is not managed by the operator. Create the connector via
  [Terraform](/docs/guides/configuration/terraform) or the [web
  console](https://app.formal.ai/connectors), then reference its ID in
  FormalListener resources.
</Note>

***

## FormalNativeUser

Creates a native user on a Formal resource, with credentials sourced from a Kubernetes Secret.

```yaml theme={null}
apiVersion: joinformal.com/v1
kind: FormalNativeUser
metadata:
  name: orders-database-default
spec:
  resourceRef: orders-database
  type: basic
  useAsDefault: true
  secretRef:
    name: postgres-credentials
    keys:
      username: username
      password: password
```

### Spec

| Field           | Type   | Required | Description                                              |
| --------------- | ------ | -------- | -------------------------------------------------------- |
| `resourceRef`   | string | Yes      | Name of a FormalResource in the same namespace           |
| `type`          | string | Yes      | See [supported types](#supported-types) below            |
| `useAsDefault`  | bool   | No       | Whether this is the default native user for the resource |
| `identityLinks` | list   | No       | See [identity links](#identity-links) below              |

<Note>
  The operator watches referenced Secrets. When a Secret is updated, the
  operator automatically propagates the new credentials to Formal.
</Note>

### Supported Types

#### `basic`

Username and password credentials, sourced from a Kubernetes Secret.

| Field                     | Type   | Required | Description                               |
| ------------------------- | ------ | -------- | ----------------------------------------- |
| `secretRef.name`          | string | Yes      | Name of the Kubernetes Secret             |
| `secretRef.keys.username` | string | Yes      | Key in the Secret containing the username |
| `secretRef.keys.password` | string | Yes      | Key in the Secret containing the password |

#### `iam`

Cloud IAM authentication.

| Field               | Type   | Required | Description                                                                             |
| ------------------- | ------ | -------- | --------------------------------------------------------------------------------------- |
| `iam.cloudProvider` | string | Yes      | Cloud provider (`aws` or `gcp`)                                                         |
| `iam.username`      | string | Yes      | IAM username for authentication                                                         |
| `iam.role`          | string | No       | IAM role ARN or identifier (if omitted, uses the environment's ambient IAM credentials) |

#### `kubernetes`

Kubernetes authentication via kubeconfig.

| Field                      | Type   | Required | Description                                     |
| -------------------------- | ------ | -------- | ----------------------------------------------- |
| `kubernetes.kubeconfigEnv` | string | Yes      | Environment variable name containing kubeconfig |

#### `ssh_key`

SSH key authentication, with the private key sourced from a Kubernetes Secret.

| Field                   | Type   | Required | Description                       |
| ----------------------- | ------ | -------- | --------------------------------- |
| `sshKey.username`       | string | Yes      | SSH username                      |
| `sshKey.secretRef.name` | string | Yes      | Secret containing the private key |
| `sshKey.secretRef.key`  | string | Yes      | Key within the Secret             |

#### `snowflake_key`

Snowflake key-pair authentication, with the private key sourced from a Kubernetes Secret.

| Field                         | Type   | Required | Description                       |
| ----------------------------- | ------ | -------- | --------------------------------- |
| `snowflakeKey.username`       | string | Yes      | Snowflake username                |
| `snowflakeKey.secretRef.name` | string | Yes      | Secret containing the private key |
| `snowflakeKey.secretRef.key`  | string | Yes      | Key within the Secret             |

#### `http_basic`

HTTP Basic authentication, with credentials sourced from a Kubernetes Secret.

| Field                               | Type   | Required | Description                               |
| ----------------------------------- | ------ | -------- | ----------------------------------------- |
| `httpBasic.header`                  | string | Yes      | HTTP header name (e.g., `Authorization`)  |
| `httpBasic.secretRef.name`          | string | Yes      | Name of the Kubernetes Secret             |
| `httpBasic.secretRef.keys.username` | string | Yes      | Key in the Secret containing the username |
| `httpBasic.secretRef.keys.password` | string | Yes      | Key in the Secret containing the password |

#### `http_bearer`

HTTP Bearer token authentication, with the token sourced from a Kubernetes Secret.

| Field                       | Type   | Required | Description                              |
| --------------------------- | ------ | -------- | ---------------------------------------- |
| `httpBearer.header`         | string | Yes      | HTTP header name (e.g., `Authorization`) |
| `httpBearer.secretRef.name` | string | Yes      | Secret containing the token              |
| `httpBearer.secretRef.key`  | string | Yes      | Key within the Secret                    |

#### `http_api_key`

HTTP API key authentication, with the value sourced from a Kubernetes Secret.

| Field                       | Type   | Required | Description                         |
| --------------------------- | ------ | -------- | ----------------------------------- |
| `httpApiKey.location`       | string | Yes      | `header` or `query_parameter`       |
| `httpApiKey.key`            | string | Yes      | Header or query parameter name      |
| `httpApiKey.secretRef.name` | string | Yes      | Secret containing the API key value |
| `httpApiKey.secretRef.key`  | string | Yes      | Key within the Secret               |

### Identity Links

`identityLinks` binds Formal identities to the native user. Each entry is resolved by name against the Formal control plane:

| Field                   | Type   | Required | Description                                               |
| ----------------------- | ------ | -------- | --------------------------------------------------------- |
| `type`                  | string | Yes      | `user`, `group`, or `resource_hostname`                   |
| `name`                  | string | Yes      | Name of the identity to link (see resolution rules below) |
| `terminationProtection` | bool   | No       | If `true`, the link cannot be deleted                     |

Resolution rules per `type`:

* `group`: matched against `Group.name`
* `user`: matched against `User.db_username`
* `resource_hostname`: matched against `ResourceHostname.name` within the parent resource

Links not present in `identityLinks` on reconcile are removed, so the spec is the source of truth.

```yaml theme={null}
spec:
  resourceRef: orders-database
  type: basic
  secretRef:
    name: postgres-credentials
    keys:
      username: username
      password: password
  identityLinks:
    - type: group
      name: db-readers
    - type: group
      name: orders-admins
      terminationProtection: true
```
