diff --git a/website/data/docs-navigation.js b/website/data/docs-navigation.js
index c681539067..c1b46d913a 100644
--- a/website/data/docs-navigation.js
+++ b/website/data/docs-navigation.js
@@ -154,6 +154,7 @@ export default [
],
},
'service-sync',
+ 'crds',
'dns',
{
category: 'upgrade',
diff --git a/website/pages/docs/k8s/crds.mdx b/website/pages/docs/k8s/crds.mdx
new file mode 100644
index 0000000000..5dd24d8be4
--- /dev/null
+++ b/website/pages/docs/k8s/crds.mdx
@@ -0,0 +1,482 @@
+---
+layout: docs
+page_title: Consul Custom Resource Definitions (Beta)
+sidebar_title: Custom Resource Definitions (Beta)
+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 (beta)
+
+## 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 < 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 (Beta)
+
+[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.