{
  "schema_version": 2,
  "id": "operate/kubernetes/security/authentication/certificate-auth",
  "title": "Authenticate to the REST API with client certificates",
  "url": "https://redis.io/docs/latest/operate/kubernetes/security/authentication/certificate-auth/",
  "summary": "Authenticate the operator and users to the Redis Software REST API with client certificates, and optionally turn off password authentication.",
  "tags": [
    "docs",
    "operate",
    "kubernetes"
  ],
  "last_updated": "2026-10-29T06:28:31-05:00",
  "page_type": "content",
  "content_hash": "289ff03684fb5a2dbfbdd0c45c64e9c63429a0a9a0768af713a380e259d74ff1",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "The operator and your users can authenticate to the Redis Software REST API with client certificates instead of usernames and passwords. After they all use certificates, you can turn off basic (username and password) authentication.\n\nThree `RedisEnterpriseCluster` (REC) spec blocks control this:\n\n| Spec block | What it controls |\n| --- | --- |\n| `apiCertificateBasedAuth` | Whether the cluster accepts client certificates on the REST API, which CA it trusts, and which certificate subjects it authorizes. |\n| `operatorClientAuth` | Which credential the operator presents to the REST API: a username and password (`Basic`) or a client certificate (`Certificate`). |\n| `apiBasicAuth` | Whether the cluster accepts usernames and passwords on the REST API. |\n\nEnabling certificate-based authentication adds a way to authenticate. It doesn't remove basic authentication. Passwords keep working until you set `apiBasicAuth.enabled` to `false`. Each user and the operator authenticates with one method, so you can move them to certificates one at a time while the others keep using passwords.\n\nFor how certificate-based authentication works in Redis Software, see [Certificate-based authentication](https://redis.io/docs/latest/operate/rs/security/certificates/certificate-based-authentication) and [Disable basic authentication for the REST API](https://redis.io/docs/latest/operate/rs/security/access-control/disable-basic-authentication)."
    },
    {
      "id": "before-you-start",
      "title": "Before you start",
      "role": "content",
      "text": "- Requires Redis Software for Kubernetes operator `8.2.6-21` or later.\n- You need a certificate authority (CA) that signs your client certificates, and its CA certificate in PEM format.\n- You need a client certificate and private key for the operator, signed by that CA.\n- Disabling basic authentication requires Redis Software 8.2.0 or later.\n- Create all secrets in the same namespace as the REC."
    },
    {
      "id": "enable-certificate-based-authentication",
      "title": "Enable certificate-based authentication",
      "role": "content",
      "text": "1. Create a secret that holds the trusted CA certificate. The CA certificate must be under a key named `certificate`, `cert`, or `tls.crt`:\n\n    [code example]\n\n1. Create a secret that holds the operator's client certificate and private key. Use a [kubernetes.io/tls](https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets) secret, such as one cert-manager produces, or an opaque secret with the certificate under `tls.crt` or `cert` and the key under `tls.key` or `key`:\n\n    [code example]\n\n1. Get the certificate's subject in RFC 2253 format:\n\n    [code example]\n\n    You declare this subject in the next step, without the `subject=` prefix. It must match the certificate's subject exactly, or the operator rejects the spec.\n\n1. Add `apiCertificateBasedAuth` and `operatorClientAuth` to the `spec` section of your existing REC file:\n\n    [code example]\n\n    With `FullSubject`, only certificates whose full subject is listed in `authorizedSubjects` can authenticate. The operator adds its own subject for you.\n\n1. Apply the REC. This change triggers a rolling update of the cluster, because the operator updates the Redis Software pods to present the client certificate.\n\n    [code example]\n\n1. Confirm that the cluster accepts certificates and that the operator's certificate is valid:\n\n    [code example]\n\n    The first line is `true`, and `operatorClientCertStatus.state` is `Valid`."
    },
    {
      "id": "apicertificatebasedauth-fields",
      "title": "`apiCertificateBasedAuth` fields",
      "role": "content",
      "text": "| Field | Description |\n| --- | --- |\n| `enabled` | Whether the REST API accepts client certificates. Setting it to `true` requires `trustedCASecretName`. |\n| `trustedCASecretName` | Secret that holds the CA certificate used to validate client certificates. |\n| `clientCertSubjectValidationType` | How the cluster validates a client certificate's subject: `Disabled` (no subject validation), `SanCn` (the Subject Alternative Name or Common Name), or `FullSubject` (the full subject). |\n| `authorizedSubjects` | Certificate subjects allowed to authenticate. Each entry takes `CN` (required), `O`, `OU` (a list), `L`, `ST`, and `C`. The operator adds its own subject from `operatorClientAuth.certificateSubjectLine`, so you don't need to list it. |\n\nAfter you set `apiCertificateBasedAuth` for the first time, `status.managedAPIs.apiCertificateBasedAuth` is `true` and the operator keeps managing the setting. If you remove the block later, the operator turns certificate-based authentication off on the cluster."
    },
    {
      "id": "operatorclientauth-fields",
      "title": "`operatorClientAuth` fields",
      "role": "content",
      "text": "| Field | Description |\n| --- | --- |\n| `method` | `Basic` (the default) or `Certificate`. `Certificate` requires `clientCertificateSecretName`, `certificateSubjectLine`, and `apiCertificateBasedAuth.enabled: true`. |\n| `clientCertificateSecretName` | Secret that holds the operator's client certificate and private key. |\n| `certificateSubjectLine` | The certificate's subject in RFC 2253 format, with no spaces after commas, for example `CN=operator,O=example`. Only `CN`, `O`, `OU`, `L`, `ST`, and `C` attributes are allowed, and `CN` is required. |\n\nWith the `Certificate` method, the operator creates a `RedisEnterpriseUser`, a `RedisEnterpriseClusterRole` with the Admin management role, and a `RedisEnterpriseClusterRoleBinding`, all named `<rec-name>-operator-cert-auth`. This is the identity the operator authenticates as. The operator owns these resources and reverts changes to them. If a resource with that name already exists and the REC doesn't own it, the operator reports an error instead of taking it over."
    },
    {
      "id": "add-certificate-based-users",
      "title": "Add certificate-based users",
      "role": "content",
      "text": "To let a person or an app authenticate with a client certificate:\n\n1. Get a client certificate for the user, signed by the CA in `trustedCASecretName`. Get its subject in RFC 2253 format:\n\n    [code example]\n\n1. [Create a `RedisEnterpriseUser`](https://redis.io/docs/latest/operate/kubernetes/security/access-control/manage-users#create-a-user) with `authMethod: Certificate` and the subject, without the `subject=` prefix, in `certificateSubjectLine`. Certificate-based users have no password, so leave out `passwordSecrets`:\n\n    [code example]\n\n1. If `clientCertSubjectValidationType` is `SanCn` or `FullSubject`, add the user's subject to `apiCertificateBasedAuth.authorizedSubjects` in the REC.\n\n1. Grant the user permissions with a role binding. See [Manage role bindings](https://redis.io/docs/latest/operate/kubernetes/security/access-control/manage-bindings).\n\nFor all user fields, see the [RedisEnterpriseUser API reference](https://redis.io/docs/latest/operate/kubernetes/reference/api/redis_enterprise_user_api)."
    },
    {
      "id": "disable-basic-authentication",
      "title": "Disable basic authentication",
      "role": "content",
      "text": "Set `apiBasicAuth.enabled` to `false` after the operator authenticates with a certificate. The cluster then rejects usernames and passwords on every REST API request and accepts only client certificates and JSON Web Token (JWT) authentication.\n\nThis setting applies only to the REST API. It doesn't change how clients authenticate to databases.\n\n> [!WARNING]\n> Every script, tool, and user that calls the REST API with a username and password loses access when you turn off basic authentication. Move each one to certificate or JWT authentication first.\n\n1. While basic authentication is still on, confirm that each client's certificate works. Forward the REST API port to your machine:\n\n    [code example]\n\n    Then, in a second terminal, call the API with the client's certificate:\n\n    [code example]\n\n    A successful request returns the cluster object. For `--cacert`, use the CA that signed the cluster's API certificate. It can differ from the CA that signs client certificates.\n\n1. If the cluster participates in Active-Active databases, update the local RERC secrets. See [Active-Active databases](#active-active-databases).\n\n1. Add `apiBasicAuth` to the `spec` section of your REC file, and keep the `apiCertificateBasedAuth` and `operatorClientAuth` settings from [Enable certificate-based authentication](#enable-certificate-based-authentication):\n\n    [code example]\n\n1. Apply the REC:\n\n    [code example]\n\n1. Confirm that the cluster rejects passwords. With the port forward still running, call the API with a username and password:\n\n    [code example]\n\n    The request returns `401`. If it returns `200`, the operator hasn't turned off basic authentication yet. Wait for the rolling update to finish, then try again.\n\nThe operator rejects `apiBasicAuth.enabled: false` unless `operatorClientAuth.method` is `Certificate`.\n\nThe operator doesn't turn off basic authentication right away. It waits until every component it manages authenticates with the client certificate, including the rolled-out Redis Software pods and, if usage reporting is enabled, the call-home client. Until then, the cluster keeps accepting passwords.\n\nIf you leave `apiBasicAuth` unset, the operator doesn't manage the setting. Removing `apiBasicAuth.enabled` from the spec leaves basic authentication in its current state on the cluster. It doesn't turn passwords back on.\n\nNew nodes join the cluster with the operator's client certificate, so you can scale the cluster while basic authentication is off."
    },
    {
      "id": "active-active-databases",
      "title": "Active-Active databases",
      "role": "content",
      "text": "Participating clusters connect to this cluster's REST API with the credentials in the local `RedisEnterpriseRemoteCluster` (RERC) secret. Before you turn off basic authentication, the local RERC secret for every `RedisEnterpriseActiveActiveDatabase` (REAADB) must hold a client certificate and private key instead of a username and password.\n\nUpdate the local RERC secret to hold the certificate and key of a certificate-based user. Use the same key names as the operator's client certificate secret. Optionally, add the CA bundle that verifies this cluster's API certificate under a key named `trusted_ca`:\n\n[code example]\n\nA secret with both a username and password and certificate material is invalid. After you update the secret, return to step 3 in [Disable basic authentication](#disable-basic-authentication).\n\nThe operator rejects `apiBasicAuth.enabled: false` if an REAADB has no local RERC, or if a local RERC secret still holds a username and password. It waits to turn off basic authentication until the new credentials reach every Active-Active database. While basic authentication is off, the operator also rejects a new or updated RERC or REAADB whose local RERC secret holds a username and password.\n\nFor how certificate-based authentication works with Active-Active databases in Redis Software, see [Manage an Active-Active database](https://redis.io/docs/latest/operate/rs/security/certificates/certificate-based-authentication#manage-an-active-active-database)."
    },
    {
      "id": "re-enable-basic-authentication",
      "title": "Re-enable basic authentication",
      "role": "content",
      "text": "Set `apiBasicAuth.enabled` to `true`. The operator applies the change right away. Deleting `apiBasicAuth.enabled` from the spec doesn't turn passwords back on.\n\n[code example]\n\nTo move the operator back to passwords and turn off certificate-based authentication, follow this order:\n\n1. Set `apiBasicAuth.enabled` to `true`, and apply the REC.\n1. Set `operatorClientAuth.method` to `Basic`, and apply the REC.\n1. Set `apiCertificateBasedAuth.enabled` to `false`, and apply the REC.\n\nThe operator keeps certificate-based authentication on while basic authentication is off, because turning both off would leave no way to authenticate."
    },
    {
      "id": "monitor-and-rotate-the-client-certificate",
      "title": "Monitor and rotate the client certificate",
      "role": "content",
      "text": "`status.operatorClientCertStatus` reports the operator's client certificate:\n\n| Field | Description |\n| --- | --- |\n| `state` | `Valid`, `ExpiringSoon` (30 days or less until expiry), or `Expired`. |\n| `expirationDate` | When the certificate expires, in RFC 3339 format. |\n| `secretName` | The secret named in `operatorClientAuth.clientCertificateSecretName`. |\n\nFrom 30 days before expiry, the operator records a `ClientCertificateExpiringSoon` warning event on the REC. After expiry, it records `ClientCertificateExpired`. To list them:\n\n[code example]\n\nRotate the certificate before it expires. If it expires while basic authentication is off, the operator loses access to the cluster until you replace the certificate or [re-enable basic authentication from a cluster node](#troubleshoot).\n\nTo rotate the certificate, get a new certificate and key signed by the trusted CA. Then:\n\n- **Same subject:** replace the contents of the existing secret:\n\n    [code example]\n\n- **Different subject:** create a new secret, then update `clientCertificateSecretName` and `certificateSubjectLine` together in one change. The operator rejects the spec whenever the subject line doesn't match the certificate in the secret, so updating one without the other leaves the REC invalid."
    },
    {
      "id": "use-hashicorp-vault",
      "title": "Use HashiCorp Vault",
      "role": "content",
      "text": "When the REC uses [HashiCorp Vault](https://redis.io/docs/latest/operate/kubernetes/security/vault) for secrets (`clusterCredentialSecretType: vault`), set `clientCertificateSecretName` and `trustedCASecretName` to Vault KV paths instead of Kubernetes secret names. The operator delivers the client certificate to the components that need it through the Vault Agent Injector."
    },
    {
      "id": "troubleshoot",
      "title": "Troubleshoot",
      "role": "errors",
      "text": "**The operator can't authenticate (HTTP 401).** If basic authentication is off and `operatorClientAuth.method` is no longer `Certificate`, the REC events report that the cluster rejected the operator's credentials with HTTP 401. To recover, do one of the following:\n\n- Restore `operatorClientAuth.method: Certificate` with the previous client certificate secret.\n- Re-enable basic authentication from a cluster node:\n\n    [code example]\n\n**The REC's `status.specStatus` is `Invalid`.** The operator applies no changes until you fix the spec. Check the REC events for the reason. The operator rejects:\n\n- `apiCertificateBasedAuth.enabled: true` without `trustedCASecretName`.\n- `operatorClientAuth.method: Certificate` without `clientCertificateSecretName`, `certificateSubjectLine`, or `apiCertificateBasedAuth.enabled: true`.\n- A `certificateSubjectLine` that isn't a valid RFC 2253 subject, or that doesn't exactly match the subject of the certificate in `clientCertificateSecretName`.\n- A `trustedCASecretName` secret that doesn't exist or doesn't hold a CA certificate.\n- A `clientCertificateSecretName` secret that doesn't exist or doesn't hold a valid certificate and private key.\n- `apiBasicAuth.enabled` on Redis Software earlier than 8.2.0."
    },
    {
      "id": "related-topics",
      "title": "Related topics",
      "role": "related",
      "text": "- [Manage REC certificates](https://redis.io/docs/latest/operate/kubernetes/security/certificates/manage-rec-certificates)\n- [Manage users](https://redis.io/docs/latest/operate/kubernetes/security/access-control/manage-users)\n- [RedisEnterpriseCluster API reference](https://redis.io/docs/latest/operate/kubernetes/reference/api/redis_enterprise_cluster_api)\n- [Certificate-based authentication in Redis Software](https://redis.io/docs/latest/operate/rs/security/certificates/certificate-based-authentication)"
    }
  ],
  "examples": [
    {
      "id": "enable-certificate-based-authentication-ex0",
      "language": "sh",
      "code": "kubectl create secret generic <ca-secret-name> \\\n      --from-file=cert=</path/to/ca.pem>",
      "section_id": "enable-certificate-based-authentication"
    },
    {
      "id": "enable-certificate-based-authentication-ex1",
      "language": "sh",
      "code": "kubectl create secret tls <client-cert-secret-name> \\\n      --cert=</path/to/operator-client.pem> \\\n      --key=</path/to/operator-client-key.pem>",
      "section_id": "enable-certificate-based-authentication"
    },
    {
      "id": "enable-certificate-based-authentication-ex2",
      "language": "sh",
      "code": "openssl x509 -in </path/to/operator-client.pem> -noout -subject -nameopt RFC2253",
      "section_id": "enable-certificate-based-authentication"
    },
    {
      "id": "enable-certificate-based-authentication-ex3",
      "language": "yaml",
      "code": "spec:\n      apiCertificateBasedAuth:\n        enabled: true\n        trustedCASecretName: <ca-secret-name>\n        clientCertSubjectValidationType: FullSubject\n      operatorClientAuth:\n        method: Certificate\n        clientCertificateSecretName: <client-cert-secret-name>\n        certificateSubjectLine: CN=<operator-common-name>,O=<organization>",
      "section_id": "enable-certificate-based-authentication"
    },
    {
      "id": "enable-certificate-based-authentication-ex4",
      "language": "sh",
      "code": "kubectl apply -f <rec-file>.yaml",
      "section_id": "enable-certificate-based-authentication"
    },
    {
      "id": "enable-certificate-based-authentication-ex5",
      "language": "sh",
      "code": "kubectl get rec <rec-name> -o jsonpath='{.status.apiCertificateBasedAuthActive}{\"\\n\"}{.status.operatorClientCertStatus}{\"\\n\"}'",
      "section_id": "enable-certificate-based-authentication"
    },
    {
      "id": "add-certificate-based-users-ex0",
      "language": "sh",
      "code": "openssl x509 -in </path/to/user-client.pem> -noout -subject -nameopt RFC2253",
      "section_id": "add-certificate-based-users"
    },
    {
      "id": "add-certificate-based-users-ex1",
      "language": "yaml",
      "code": "spec:\n      authMethod: Certificate\n      certificateSubjectLine: CN=<user-common-name>,O=<organization>",
      "section_id": "add-certificate-based-users"
    },
    {
      "id": "disable-basic-authentication-ex0",
      "language": "sh",
      "code": "kubectl port-forward service/<rec-name> 9443:9443",
      "section_id": "disable-basic-authentication"
    },
    {
      "id": "disable-basic-authentication-ex1",
      "language": "sh",
      "code": "curl --cacert </path/to/api-ca.pem> --cert </path/to/client.pem> --key </path/to/client-key.pem> \\\n      https://localhost:9443/v1/cluster",
      "section_id": "disable-basic-authentication"
    },
    {
      "id": "disable-basic-authentication-ex2",
      "language": "yaml",
      "code": "spec:\n      apiBasicAuth:\n        enabled: false",
      "section_id": "disable-basic-authentication"
    },
    {
      "id": "disable-basic-authentication-ex3",
      "language": "sh",
      "code": "kubectl apply -f <rec-file>.yaml",
      "section_id": "disable-basic-authentication"
    },
    {
      "id": "disable-basic-authentication-ex4",
      "language": "sh",
      "code": "curl --cacert </path/to/api-ca.pem> -u <username>:<password> \\\n      -o /dev/null -w '%{http_code}\\n' https://localhost:9443/v1/cluster",
      "section_id": "disable-basic-authentication"
    },
    {
      "id": "active-active-databases-ex0",
      "language": "sh",
      "code": "kubectl create secret generic <rerc-secret-name> \\\n  --from-file=cert=</path/to/user-client.pem> \\\n  --from-file=key=</path/to/user-client-key.pem> \\\n  --from-file=trusted_ca=</path/to/ca.pem> \\\n  --dry-run=client -o yaml | kubectl replace --save-config -f -",
      "section_id": "active-active-databases"
    },
    {
      "id": "re-enable-basic-authentication-ex0",
      "language": "yaml",
      "code": "spec:\n  apiBasicAuth:\n    enabled: true",
      "section_id": "re-enable-basic-authentication"
    },
    {
      "id": "monitor-and-rotate-the-client-certificate-ex0",
      "language": "sh",
      "code": "kubectl get events --field-selector involvedObject.name=<rec-name>,type=Warning",
      "section_id": "monitor-and-rotate-the-client-certificate"
    },
    {
      "id": "monitor-and-rotate-the-client-certificate-ex1",
      "language": "sh",
      "code": "kubectl create secret tls <client-cert-secret-name> \\\n      --cert=</path/to/new-operator-client.pem> \\\n      --key=</path/to/new-operator-client-key.pem> \\\n      --dry-run=client -o yaml | kubectl apply -f -",
      "section_id": "monitor-and-rotate-the-client-certificate"
    },
    {
      "id": "troubleshoot-ex0",
      "language": "sh",
      "code": "rladmin tune cluster control_plane_basic_authentication enabled",
      "section_id": "troubleshoot"
    }
  ]
}
