---
layout: docs
page_title: Consul Custom Resource Definitions (Beta)
sidebar_title: Custom Resource Definitions <sup>(Beta)</sup>
description: >-
  Consul now supports managing configuration entries via Kubernetes Custom Resources.
  These custom resource can be used to manage the configuration for workloads
  deployed within the cluster.
---

# Custom Resource Definitions <sup>(beta)</sup>

## Overview

-> **This feature is currently in Beta.** It requires consul-helm >= 0.25.0 and
consul >= 1.8.4.

We support managing Consul [configuration entries](/docs/agent/config-entries)
via Kubernetes Custom Resources. Configuration entries are used to provide
cluster-wide defaults for the service mesh.

We currently support the follow configuration entry kinds:

- [`proxy-defaults`](/docs/agent/config-entries/proxy-defaults)
- [`service-defaults`](/docs/agent/config-entries/service-defaults)
- [`service-splitter`](/docs/agent/config-entries/service-splitter)
- [`service-router`](/docs/agent/config-entries/service-router)
- [`service-resolver`](/docs/agent/config-entries/service-resolver)
- [`service-intentions`](/docs/agent/config-entries/service-intentions) (requires Consul >= 1.9.0)

The following kinds are **not** currently supported:

- [`ingress-gateway`](/docs/agent/config-entries/ingress-gateway)
- [`terminating-gateway`](/docs/agent/config-entries/terminating-gateway)

## Installation

Ensure you have version `0.25.0` of the helm chart:

```shell-session
$ helm search repo hashicorp/consul
NAME            	CHART VERSION	APP VERSION	DESCRIPTION
hashicorp/consul	0.25.0       	1.8.4      	Official HashiCorp Consul Chart
```

If you don't have `0.25.0`, you will need to update your helm repository cache:

```shell-session
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "hashicorp" chart repository
Update Complete. ⎈Happy Helming!⎈
```

Next, you must configure consul-helm via your `values.yaml` to install the custom resource definitions
and enable the controller that acts on them:

```yaml
global:
  name: consul
  image: 'consul:1.9.0-beta1' # consul >= 1.8.4 must be used
  imageK8S: 'hashicorp/consul-k8s:0.19.0'

controller:
  enabled: true

connectInject:
  enabled: true
```

Note that:

1. `controller.enabled: true` installs the CRDs and enables the controller.
1. `global.image` must be a Consul version `>= 1.8.4`, e.g. `consul:1.8.4` or `consul:1.9.0-beta1`.
1. `global.imageK8S` must be `>= 0.19.0`
1. Configuration entries are used to configure Consul service mesh so it's also
   expected that `connectInject` will be enabled.

See [Install with Helm Chart](/docs/k8s/installation/install) for further installation
instructions.

## Usage

Once installed, we can use `kubectl` to create and manage Consul's configuration entries.

### Create

We can create configuration entries via `kubectl apply`.

```shell-session
$ cat <<EOF | kubectl apply -f -
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceDefaults
metadata:
  name: foo
spec:
  protocol: "http"
EOF

servicedefaults.consul.hashicorp.com/foo created
```

See [Specifications](#specifications) for detailed schema documentation.

### Get

We can use `kubectl get [kind] [name]` to get the status of the configuration entry:

```shell-session
$ kubectl get servicedefaults foo
NAME  SYNCED
foo   True
```

The `SYNCED` status shows whether the configuration entry was successfully created
in Consul.

### Describe

We can use `kubectl describe [kind] [name]` to investigate the status of the
configuration entry. If `SYNCED` is false, the status will contain the reason
why.

```shell-session
$ kubectl describe servicedefaults foo
Status:
  Conditions:
    Last Transition Time:  2020-10-09T21:15:50Z
    Status:                True
    Type:                  Synced
```

### Edit

We can use `kubectl edit [kind] [name]` to edit the configuration entry:

```shell
$ kubectl edit servicedefaults foo
# change protocol: http => protocol: tcp
servicedefaults.consul.hashicorp.com/foo edited
```

We can then use `kubectl get` to ensure the change was synced to Consul:

```shell-session
$ kubectl get servicedefaults foo
NAME  SYNCED
foo   True
```

### Delete

We can use `kubectl delete [kind] [name]` to delete the configuration entry:

```shell-session
$ kubectl delete servicedefaults foo
servicedefaults.consul.hashicorp.com "foo" deleted
```

We can then use `kubectl get` to ensure the configuration entry was deleted:

```shell-session
$ kubectl get servicedefaults foo
Error from server (NotFound): servicedefaults.consul.hashicorp.com "foo" not found
```

#### Delete Hanging

If running `kubectl delete` hangs without exiting, there may be
a requirement inside Consul that prevents that configuration entry from being
deleted. For example, if you set the protocol of your service to `http` via `ServiceDefaults` and then
create a `ServiceSplitter`, you won't be able to delete the `ServiceDefaults`.

This is because by deleting the `ServiceDefaults` config, you are setting the
protocol back to the default which is `tcp`. Since `ServiceSplitter` requires
that the service has an `http` protocol, Consul will not allow the `ServiceDefaults`
to be deleted since that would put Consul into a broken state.

In order to delete the `ServiceDefaults` config you would need to first delete
the `ServiceSplitter`.

## Specifications

### ProxyDefaults

[proxy-defaults](/docs/agent/config-entries/proxy-defaults)
configures global defaults across all proxies.

```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ProxyDefaults
metadata:
  name: global
spec:
  config:
    envoy_tracing_json: '{"http":{"name":"envoy.zipkin","config":{"collector_cluster":"zipkin","collector_endpoint":"/api/v1/spans","shared_span_context":false}}}'
  expose:
    checks: true
    paths:
      - listenerPort: 80
        localPathPort: 42
        path: /test/path
        protocol: tcp
      - listenerPort: 8080
        localPathPort: 4201
        path: /root/test/path
        protocol: https
  meshGateway:
    mode: local
```

Notes:

1. There can only be one `ProxyDefaults` resource and its name **must** be `global`.
1. Keys under `spec.config` will need to use `snake_case`, not `camelCase`, because
   this config is passed directly to Envoy which uses `snake_case`, e.g.
   ```yaml
   spec:
     config:
       envoy_statsd_url: 'udp://127.0.0.1:8125'
   ```
1. See [proxy-defaults](/docs/agent/config-entries/proxy-defaults) for full
   documentation on this config entry.

### ServiceDefaults

[service-defaults](/docs/agent/config-entries/service-defaults)
configures a specific service.

```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceDefaults
metadata:
  name: your-service-name
spec:
  protocol: https
  meshGateway:
    mode: local
  expose:
    checks: true
    paths:
      - listenerPort: 80
        path: /path
        localPathPort: 9000
        protocol: tcp
      - listenerPort: 8080
        path: /another-path
        localPathPort: 9091
        protocol: http2
  externalSNI: external-sni
```

Notes:

1. The name of the service that this `ServiceDefaults` configures is set by
   `metadata.name`.
1. See [service-defaults](/docs/agent/config-entries/service-defaults) for full
   documentation on this config entry.

### ServiceIntentions <sup>(Beta)</sup>

[service-intentions](/docs/agent/config-entries/service-intentions)
configures traffic authorization for a destination service.

```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
  name: my-intention
spec:
  destination:
    name: your-service-name
  sources:
    - name: svc1
      namespace: test
      action: allow
      permissions: []
      description: allow access from svc1
    - name: '*'
      namespace: not-test
      action: deny
      permissions: []
      description: disallow access from namespace not-test
    - name: svc-2
      namespace: bar
      action: ''
      permissions:
        - action: allow
          http:
            pathExact: /foo
            pathPrefix: /bar
            pathRegex: /baz
            header:
              - name: header
                present: true
                exact: exact
                prefix: prefix
                suffix: suffix
                regex: regex
                invert: true
            methods:
              - GET
              - PUT
      description: an L7 config
```

Notes:

1. This resource is only supported in Consul 1.9.0.
1. Unlike the other configuration entries, the value of `metadata.name` does not
   define which service the intention applies to. It can be set to any value
   however we recommend setting it to the name of the destination service the
   intention is configuring.

   Instead, the name of the service this intention
   is configuring is set in `spec.destination.name`.

1. Wildcard intentions can be created by setting `spec.destination.name` to `*` and/or
   `spec.sources[].name` to `*`. For example to create a `deny` intention that applies
   to all services:

   ```yaml
   apiVersion: consul.hashicorp.com/v1alpha1
   kind: ServiceIntentions
   metadata:
    name: deny-all
   spec:
    destination:
      name: *
    sources:
      - name: *
        action: deny
   ```

1. See [service-intentions](/docs/agent/config-entries/service-intentions) for full
   documentation on this config entry.

### ServiceResolver

[service-resolver](/docs/agent/config-entries/service-resolver)
configures which service instances should satisfy Connect upstream discovery requests for a given service name.

```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceResolver
metadata:
  name: your-service-name
spec:
  defaultSubset: default_subset
  subsets:
    subset1:
      filter: filter1
      onlyPassing: true
    subset2:
      filter: filter2
  redirect:
    service: redirect
    serviceSubset: redirect_subset
    namespace: redirect_namespace
    datacenter: redirect_datacenter
  failover:
    failover1:
      service: failover1
      serviceSubset: failover_subset1
      namespaces: failover_namespace1
      datacenters:
        - failover1_dc1
        - failover1_dc2
    failover2:
      service: failover2
      serviceSubset: failover_subset2
      namespaces: failover_namespace2
      datacenters:
        - failover2_dc1
        - failover2_dc2
  connectTimeout: 1000000000
  loadBalancer:
    policy: policy
    ringHashConfig:
      minimumRingSize: 1
      maximumRingSize: 2
    leastRequestConfig:
      choiceCount: 1
    hashPolicies:
      - field: field
        fieldValue: value
        cookieConfig:
          session: true
          ttl: 1
          path: path
        sourceIP: true
        terminal: true
```

Notes:

1. The name of the service that this `ServiceResolver` configures is set by
   `metadata.name`.
1. See [service-resolver](/docs/agent/config-entries/service-resolver) for full
   documentation on this config entry.

### ServiceRouter

[service-router](/docs/agent/config-entries/service-router)
configures traffic routing and manipulation at networking layer 7 (e.g. HTTP).

```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceRouter
metadata:
  name: your-service-name
spec:
  routes:
    - match:
        http:
          pathExact: pathExact
          pathPrefix: pathPrefix
          pathRegex: pathRegex
          header:
            - name: name
              present: true
              exact: exact
              prefix: prefix
              suffix: suffix
              regex: regex
              invert: true
          queryParam:
            - name: name
              present: true
              exact: exact
              regex: regex
          methods:
            - method1
            - method2
      destination:
        service: service
        serviceSubset: serviceSubset
        namespace: namespace
        prefixRewrite: prefixRewrite
        requestTimeout: 1000000000
        numRetries: 1
        retryOnConnectFailure: true
        retryOnStatusCodes:
          - 500
          - 400
```

Notes:

1. The name of the service that this `ServiceRouter` configures is set by
   `metadata.name`.
1. See [service-router](/docs/agent/config-entries/service-router) for full
   documentation on this config entry.

### ServiceSplitter

[service-splitter](/docs/agent/config-entries/service-splitter)
configures splitting incoming requests across different subsets of a single service.

```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceSplitter
metadata:
  name: your-service-name
spec:
  splits:
    - weight: 50.1
      service: foo
      serviceSubset: bar
      namespace: baz
    - weight: 49.9
      service: foo
      serviceSubset: bar
      namespace: baz
```

Notes:

1. The name of the service that this `ServiceSplitter` configures is set by
   `metadata.name`.
1. See [service-splitter](/docs/agent/config-entries/service-splitter) for full
   documentation on this config entry.
