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

# Binding Endpoints in the ngrok Kubernetes Operator

> Learn about ngrok's endpoint bindings and how to use them in the ngrok Kubernetes Operator.

ngrok supports the concept of endpoint bindings which allow you to control how your endpoints are accessed.
This page gives a brief overview of each type of binding as well as how they are used with the ngrok Kubernetes Operator.

With the Kubernetes Operator, bindings can be used on the `CloudEndpoint` and `AgentEndpoint` custom resources.

## Public binding

Endpoints with a public binding have a publicly addressable URL that receives traffic from the internet via the ngrok cloud service's global points of presence. for example,
These endpoints might use an ngrok subdomain or a custom domain.

Public endpoint URLs must:

* Use either a Domain or TCP Address
* Use the public binding

Example URLs:

* [https://example.ngrok.app](https://example.ngrok.app)
* [https://blog.example.com](https://blog.example.com)

Example `CloudEndpoint` (the same `spec.bindings` configuration works for `AgentEndpoint` as well)

```yaml theme={null}
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: CloudEndpoint
metadata:
  name: example-cloud-endpoint
spec:
  url: https://example-cloud-endpoint.ngrok.io
  bindings:
  - public
  description: Public Endpoint Created by the ngrok-operator
  trafficPolicy:
    policy:
      on_http_request:
      - actions:
        - type: forward-internal
          config:
            url: https://my-k8s-service.internal
```

The public binding and URL for the above `CloudEndpoint` make it accessible on the public internet at `https://example-cloud-endpoint.ngrok.io`

[Learn more about Public Endpoints](/gateway/public-endpoints/).

## Internal binding

Endpoints with an internal binding can only receive traffic forwarded to them from other Endpoints in your ngrok account via the forward-internal Traffic Policy action.

Example URLs:

* [https://example.internal](https://example.internal)
* tcp\://ssh.internal:22

Example `AgentEndpoint` (the same `spec.bindings` configuration works for `CloudEndpoint` as well)

```yaml theme={null}
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: AgentEndpoint
metadata:
  name: example-agent-endpoint
spec:
  bindings:
  - internal
  description: Internal Endpoint Created by the ngrok-operator
  url: https://my-k8s-service.internal
  upstream:
    url: http://my-service.default:80
```

The internal binding and URL on the above internal `AgentEndpoint` make it not accessible via the public internet.
It can be accessed by using the `forward-internal` action from a Traffic Policy on other endpoints.
This is not limited to the Kubernetes cluster that you installed the Operator in, and you could, for example, create a public endpoint using the ngrok dashboard/API/CLI that forwards to this endpoint.

[Learn more about Internal Endpoints](/gateway/internal-endpoints/).

## Kubernetes binding

<Warning title="The target namespace must exist before the bound endpoint is created">
  The ngrok Operator does not create the target namespace for you. Before
  creating a Kubernetes-bound endpoint, ensure the namespace referenced in the
  URL (the `<namespace>` in `<scheme>://<service-name>.<namespace>`) already
  exists in the cluster — otherwise the `BoundEndpoint` will fail to project
  with [`ERR_NGROK_20003`](/errors/err_ngrok_20003) and a
  `namespaces "<name>" not found` message in its status.

  You can create the namespace with `kubectl create ns <namespace>`.
</Warning>

Endpoints with a kubernetes binding are private endpoints that are only available inside of Kubernetes clusters where you installed the ngrok Kubernetes Operator.

Example URLs:

* [http://service.namespace](http://service.namespace)
* tcp\://db.controlplane:5432

Public endpoint URLs must:

* Use the kubernetes binding
* The `spec.url` must follow the format `<scheme>://<service-name>.<service-namespace>`

```yaml theme={null}
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: AgentEndpoint
metadata:
  name: example-agent-endpoint
  namespace: my-namespace
spec:
  bindings:
  - kubernetes
  description: Kubernetes Bound Endpoint Created by the ngrok-operator
  url: http://my-bound-service.my-namespace
  upstream:
    url: http://my-service.my-namespace:80
```

The kubernetes binding and URL for the above `AgentEndpoint` make it a Kubernetes bound endpoint.
Endpoints with a binding of `kubernetes` can be made available as projected services in any cluster running the ngrok Operator.
These endpoints are not accessible on the public internet, but can be used to enable services in your Kubernetes cluster to access the endpoint by making
requests to a projected `Service` that is created for the endpoint.

### How Kubernetes bound endpoints work

An endpoint with a Kubernetes binding will cause instances of the ngrok Kubernetes Operator to create a `BoundEndpoint` custom resource for the endpoint.
The `BoundEndpoint` will cause the endpoint to be projected into the cluster as a `Service` resource.

This enables many different use-cases such as enabling secure communication between different Kubernetes clusters using Kubernetes bound endpoints.

For example, the following endpoint:

```yaml theme={null}
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: AgentEndpoint
metadata:
  name: example-agent-endpoint
  namespace: my-namespace
spec:
  bindings:
  - kubernetes
  description: Kubernetes Bound Endpoint Created by the ngrok-operator
  url: http://my-bound-service.my-namespace
  upstream:
    url: http://my-service.my-namespace:80
```

Will cause the following `BoundEndpoint` to be created by the Operator.
You can also configure the same options on `CloudEndpoint` resources.

```yaml theme={null}
apiVersion: bindings.k8s.ngrok.com/v1alpha1
kind: BoundEndpoint
metadata:
  name: ngrok-22680758-eb09-576e-a7ac-dc3728458dfc
  namespace: ngrok-operator
spec:
  endpointURL: http://my-bound-service.my-namespace:80
  port: 10001
  scheme: http
  target:
    metadata: {}
    namespace: my-namespace
    port: 80
    protocol: TCP
    service: my-service
```

Which in-turn causes the Operator to project the following `Service` into your cluster

```yaml theme={null}
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/managed-by: ngrok-operator
    bindings.k8s.ngrok.com/endpoint-binding-name: ngrok-22680758-eb09-576e-a7ac-dc3728458dfc
    bindings.k8s.ngrok.com/endpoint-binding-namespace: ngrok-operator
  name: my-bound-service
  namespace: my-namespace
spec:
  externalName: ngrok-22680758-eb09-576e-a7ac-dc3728458dfc.ngrok-operator.svc.cluster.local
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 80
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
  type: ExternalName
```

When anything in the cluster makes a request to the `my-bound-service.my-namespace` `Service` it will hit the above `AgentEndpoint` and ultimately be routed to the `my-service.my-namespace` `Service`.

This can be used within a single cluster to use ngrok Traffic Policies on your endpoints for `Service` to `Service` networking to perform operations such as rate-limiting, header manipulation, etc.
Furthermore, the true power in Kubernetes bindings is allowing you to project a `Service` in one cluster to one or more other clusters running the ngrok Kubernetes Operator.
When doing this, you can configure networking between different Kubernetes clusters without needing to expose any publicly accessible URLs that would need to require authentication to prevent unwanted access.
This is not simply limited to Kubernetes clusters. You could for example, create a Kubernetes bound endpoint using the ngrok CLI/SDK to project workloads running on another system such as a Virtual Machine into your Kubernetes clusters.

### Kubernetes pod identity in Traffic Policy

When a connection arrives on a Kubernetes-bound endpoint, ngrok makes the originating pod's metadata available as Traffic Policy variables under `conn.k8s.pod.*`. This enables policies that make access control decisions based on the Kubernetes workload initiating the connection, such as restricting access to pods in a specific namespace or matching on pod annotations.

Pod identity variables are only available on endpoints with a `kubernetes` binding. They are not populated on public or internal endpoints.

For a full reference of the available variables, error handling, and usage examples, see [Restricting Access by Kubernetes Pod Identity](/k8s/guides/how-to/pod-identity).

### Enable bindings for the Operator

By default, the kubernetes bindings feature is not enabled for the ngrok Operator.
Without enabling the feature, you can still create endpoints like any of the above examples for `internal`/`public`/`kubernetes` endpoints, but the Operator will not create any `BoundEndpoint` resources for endpoints in your ngrok account with a Kubernetes binding.

To enable the feature and allow your Operator to create `BoundEndpoints` in response to endpoints with a kubernetes binding, use the helm value `bindings.enabled`.
For example, if you installed the ngrok Operator with the default name/namespace, the following command will enable bindings.

```bash theme={null}
helm upgrade ngrok-operator -n ngrok-operator ngrok/ngrok-operator --reuse-values --set bindings.enabled=true
```

See the [Operator Helm page](/k8s/installation/helm) for more information about the `bindings` value and all the other configuration options such as configuring custom annotations/labels on the projected services created by Kubernetes bound endpoints.

### Restrict Kubernetes bound endpoints

By default, the Operator will create a `BoundEndpoint` in response to all endpoints in your account with a Kubernetes binding type.
You can modify your Operator to only process a subset of them with the `bindings.endpointSelectors` Helm value.

`bindings.endpointSelectors` is a list of cel expressions used to filter which kubernetes-bound endpoints should be projected into this cluster.
It defaults to `["true"]` which causes it to process all endpoints with a Kubernetes type binding. This can be modified to anything you like to control which
endpoints the Operator should process. This strategy can enable you to easily only project endpoints into certain clusters running the ngrok Kubernetes Operator.

## Bindings with `Ingresses`

By default, creating an `Ingress` will create a `CloudEndpoint` that has a `public` binding, meaning that its URL is accessible via the public internet, and an `AgentEndpoint` with an `internal` binding, meaning that its URL is only accessible using the `forward-internal` Traffic Policy action.
You can control the binding on the `CloudEndpoint` that will be created by this `Ingress` using the `k8s.ngrok.com/bindings` annotation.

For more information about bindings, see [the bindings page](/k8s/guides/bindings)

The following `Ingress` will create a `CloudEndpoint` with an `internal` binding.
**Note that with the internal binding, the URL must end in .internal**

```yaml theme={null}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  namespace: default
  annotations:
    k8s.ngrok.com/bindings: "internal"
spec:
  ingressClassName: ngrok
  rules:
    - host: example-ingress.internal
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: example-service
                port:
                  number: 80
```

## Bindings with Gateway API

By default, the `CloudEndpoint` resources that are created by the Operator from Gateway API config have a `public` binding, meaning that its URL is accessible via the public internet, and any created `AgentEndpoint` resources will have an `internal` binding, meaning that its URL is only accessible using the `forward-internal` Traffic Policy action.
You can control the binding on the `CloudEndpoint` that will be created by using the `k8s.ngrok.com/bindings` annotation.

For more information about bindings, see [the bindings page](/k8s/guides/bindings)

The following configuration will create a `CloudEndpoint` with an `internal` binding. the annotation can be used on the `Gateway` but not `HTTPRoute`.
**Note that with the internal binding, the URL must end in .internal**

```yaml theme={null}
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: example-gateway
  namespace: default
  annotations:
    k8s.ngrok.com/bindings: "internal"
spec:
  gatewayClassName: ngrok
  listeners:
    - name: example-hostname
      hostname: "example-hostname.internal"
      port: 443
      protocol: HTTPS
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: example-route
  namespace: default
spec:
  hostnames:
  - example-hostname.internal
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: example-gateway
    namespace: default
  rules:
  - matches:
      - path:
          type: PathPrefix
          value: /
    backendRefs:
      - group: ""
        kind: Service
        name: example-service
        port: 80
        weight: 1
```
