---
title: "Configure an external identity provider"
description: "Connect an external identity provider to Calico Enterprise so users authenticate against an existing IdP when signing in to the web console and Kibana."
product: "Calico Enterprise"
version: "3.23 (latest)"
section: "Operations"
canonical_url: "https://docs.tigera.io/calico-enterprise/latest/operations/cnx/configure-identity-provider"
---

# Configure an external identity provider

## Big picture

Configure an external identity provider (IdP), create a user, and log in to the Calico Enterprise web console.

(If you are just starting out, the quickest way to allow user access is to configure the default, [token authentication](https://docs.tigera.io/calico-enterprise/latest/operations/cnx/authentication-quickstart.md).)

## Concepts

The Calico Enterprise authentication method is configured through the [Authentication API resource](https://docs.tigera.io/calico-enterprise/latest/reference/installation/api.md#authentication) named, `tigera-secure`.

When configuring your cluster, you may be asked for the following inputs:

- **Client Id**: Id for exchanging data that are shared between the IdP and an application.
- **Client Secret**: Secret associated with the `client id` used by server applications for exchanging tokens.
- **Issuer URL**: URL where the IdP can be reached, based on the conventions of OAuth and OIDC.
- **Claims**: Every time your IdP issues a token for a valid user, these claims add metadata about the user. Calico Enterprise uses this to determine the username.

## Before you begin

**Supported identity providers**

- **OIDC authentication**: User identity is managed outside of the cluster by an OIDC authorization server.
- **Google OIDC authentication**: User identity is managed by Google OIDC. Choose this option if you want to use GSuite groups.
- **OpenShift authentication**: User identity is provided by the OpenShift OAuth server.
- **LDAP authentication**: User identify is provided using the LDAP server.

**Required**

- [Install Calico Enterprise](https://docs.tigera.io/calico-enterprise/latest/getting-started.md)
- [Configure access to the web console](https://docs.tigera.io/calico-enterprise/latest/operations/cnx/access-the-manager.md)

## How to

### Configure an external identity provider for user authentication

<!-- tabs -->

**Tab: OIDC**

1. Apply the Authentication CR to your cluster to let the operator configure your login. The following example uses the email claim. The email field from the JWT (created by your IdP), is used as the username for binding privileges.

   ```yaml
   apiVersion: operator.tigera.io/v1
   kind: Authentication
   metadata:
     name: tigera-secure
   spec:
      # This indicates where the web console can be accessed from the browser. Include the port only if the web console is not running on port 443.
     managerDomain: https://<domain-of-manager-ui>
     oidc:
       issuerURL: <your-idp-issuer>
       usernameClaim: email
   ```

2. Apply the secret to your cluster with your OIDC credentials. To get the values, consult the documentation of your provider.

   ```yaml
   apiVersion: v1
   kind: Secret
   metadata:
     name: tigera-oidc-credentials
     namespace: tigera-operator
   data:
     clientID: <your-base64-clientid>
     clientSecret: <your-base64-clientid-secret>
   ```

   If you are using an external secret provider, you can mount your OIDC credentials as a volume through CSI Secret Store Driver to avoid storing the credentials in the Kubernetes cluster.

   Create a `SecretProviderClass` resource named `tigera-oidc-credentials` in the `tigera-operator` namespace that mounts your OIDC credential fields as exactly two files: `clientID` and `clientSecret`.

   In its spec, map your source secret/keys so the mounted filenames are precisely `clientID` and `clientSecret`. Use your provider’s standard configuration options to supply these values.

   For example, if you are integrating with AWS Secrets Manager, your `SecretProviderClass` might look like this:

   ```yaml
   apiVersion: secrets-store.csi.x-k8s.io/v1
   kind: SecretProviderClass
   metadata:
     name: tigera-oidc-credentials
     namespace: tigera-operator
   spec:
     provider: aws
     parameters:
       objects: |
         - objectName: <name-of-oidc-credentials-in-aws-secretsmanager>
           objectType: "secretsmanager"
           jmesPath:
             - path: <field-name-in-your-oidc-credentials-in-aws-secretsmanager-mapping-to-clientID>
               objectAlias: "clientID"
             - path: <field-name-in-your-oidc-credentials-in-aws-secretsmanager-mapping-to-clientSecret>
               objectAlias: "clientSecret"
   ```

**Tab: Google OIDC**

1. Apply the Authentication CR to your cluster to let the operator configure your login. The following example uses the email claim. The email field from the JWT (created by your IdP), is used as the username for binding privileges.

   ```yaml
   apiVersion: operator.tigera.io/v1
   kind: Authentication
   metadata:
     name: tigera-secure
   spec:
     managerDomain: https://<domain-of-manager-ui>
     oidc:
       issuerURL: <your-idp-issuer>
       usernameClaim: email
   ```

2. Optional: Google OIDC does not support the groups claim. However, Calico Enterprise leverages [Dex IdP](https://dexidp.io/docs/connectors/google/) to add groups if you configure a service account. This account needs Domain-Wide Delegation and permission to access the `https://www.googleapis.com/auth/admin.directory.group.readonly` API scope. To get group fetching set up:

   - Follow the [instructions](https://developers.google.com/admin-sdk/directory/v1/guides/delegation) to set up a service account with Domain-Wide Delegation

     - During service account creation, a JSON key file will be created that contains authentication information for the service account.
     - When delegating the API scopes to the service account, delegate the `https://www.googleapis.com/auth/admin.directory.group.readonly` scope and **only this scope**.

   - Enable the [Admin SDK](https://console.developers.google.com/apis/library/admin.googleapis.com/)

   - Use the `serviceAccountSecret` and `adminEmail` configuration options in the next step.

     - The contents of the JSON key file should be used as the `serviceAccountSecret`
     - For `adminEmail` choose a G Suite super user. The service account will impersonate this user when making calls to the admin API.

3. Apply the secret to your cluster with your OIDC credentials.

   ```yaml
   apiVersion: v1
   kind: Secret
   metadata:
     name: tigera-oidc-credentials
     namespace: tigera-operator
   data:
     clientID: <your-base64-clientid>
     clientSecret: <your-base64-clientid-secret>
       # If you created a service account in the previous step, include the following two fields.
     serviceAccountSecret: <your-base64-json-contents>
     adminEmail: <your-base64-gsuite-user>
   ```

   If you are using an external secret provider, you can mount your OIDC credentials as a volume through CSI Secret Store Driver to avoid storing the credentials in the Kubernetes cluster.

   Create a `SecretProviderClass` resource named `tigera-oidc-credentials` in the `tigera-operator` namespace that mounts your OIDC credential fields as files `clientID` and `clientSecret`, if you created a Google service account in the previous step then also mount additional fields as files `serviceAccountSecret` and `adminEmail`.

   In its spec, map your source secret/keys so the mounted files are named exactly `clientID` and `clientSecret` (required), and optionally `serviceAccountSecret` and `adminEmail`. Use your provider’s standard configuration to supply these values.

   For example, if you are integrating with AWS Secrets Manager, your `SecretProviderClass` resource might look like this:

   ```yaml
   apiVersion: secrets-store.csi.x-k8s.io/v1
   kind: SecretProviderClass
   metadata:
     name: tigera-oidc-credentials
     namespace: tigera-operator
   spec:
     provider: gcp
     parameters:
       secrets: |
         - resourceName: "projects/<your-project-id>/secrets/tigera-oidc-client-id/versions/<secret-version>"
           fileName: "clientID"
         - resourceName: "projects/<your-project-id>/secrets/tigera-oidc-client-secret/versions/<secret-version>"
           fileName: "clientSecret"
         # If you created a service account in the previous step, include the following two files.
         - resourceName: "projects/<your-project-id>/secrets/tigera-oidc-service-account-secret/versions/<secret-version>"
           fileName: "serviceAccountSecret"
         - resourceName: "projects/<your-project-id>/secrets/tigera-oidc-admin-email/versions/<secret-version>"
           fileName: "adminEmail"
   ```

**Tab: OpenShift**

1. Install the [OpenShift CLI (oc)](https://docs.openshift.com/container-platform/latest/cli_reference/openshift_cli/getting-started-cli.html).

2. Create values for some required variables. `MANAGER_URL` is the URL where the Calico Enterprise web console will be accessed, `CLUSTER_DOMAIN` is the domain (excl. port) where your OpenShift cluster is accessed (run `oc status` to get it) and `CLIENT_SECRET` is a value of your choosing.

   ```bash
    # This indicates where the web console can be accessed from the browser. Include the port only if the web console is not running on port 443.
   MANAGER_URL=<manager-host>:<port>
   CLUSTER_DOMAIN=<domain-of-your-ocp-cluster>
   CLIENT_SECRET=<clientSecret>
   ```

3. Add an OAuthClient to your OpenShift cluster.

   ```bash
   oc apply -f - <<EOF
   kind: OAuthClient
   apiVersion: oauth.openshift.io/v1
   metadata:
      # The name is used as the clientID by Dex.
     name: tigera-dex
    # The secret is used as the clientSecret by Dex
   secret: $CLIENT_SECRET
    # List of valid addresses for the callback.
   redirectURIs:
    - "$MANAGER_URL/dex/callback"
   grantMethod: prompt
   EOF
   ```

4. Apply the Authentication CR to your cluster to let the operator configure your login.

   ```bash
   oc apply -f - <<EOF
   apiVersion: operator.tigera.io/v1
   kind: Authentication
   metadata:
     name: tigera-secure
   spec:
      # This indicates where the web console can be accessed from the browser. Include the port only if the web console is not running on port 443.
     managerDomain: $MANAGER_URL
     openshift:
       issuerURL: https://api.$CLUSTER_DOMAIN:6443
   EOF
   ```

5. Get the certificates that are used to connect with OpenShift and store them in a file called `dex.pem`.

   ```bash
   echo | openssl s_client -servername oauth-openshift.apps.$CLUSTER_DOMAIN -connect oauth-openshift.apps.$CLUSTER_DOMAIN:443 |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > dex.pem
   echo | openssl s_client -servername api.$CLUSTER_DOMAIN -connect api.$CLUSTER_DOMAIN:6443 |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' >> dex.pem
   ```

   Alternatively, you can use the root CA of your cluster and store it in `dex.pem`.

6. Apply a secret to your cluster with your OpenShift credentials.

   ```bash
   oc create secret generic tigera-openshift-credentials -n tigera-operator --from-file=rootCA=dex.pem --from-literal=clientID=tigera-dex --from-literal=clientSecret=$CLIENT_SECRET
   ```

**Tab: LDAP**

For detailed steps, see the Support KB article [How to Configure LDAP Authentication with Active Directory](https://tigeraio.my.site.com/help/s/article/How-to-configure-LDAP-Authentication-with-Active-Directory).

1. Apply the Authentication CR to your cluster to let the operator configure your login.

   ```yaml
   apiVersion: operator.tigera.io/v1
   kind: Authentication
   metadata:
     name: tigera-secure
   spec:
      # This indicates where the web console can be accessed from the browser. Include the port only if the web console is not running on port 443.
     managerDomain: https://<manager-host>:<port>
     ldap:
       # The host and port of the LDAP server. Example: ad.example.com:636.
       host: <ldap-host>:<ldap-port>
       # (optional) StartTLS whether to enable the startTLS feature for establishing TLS on an existing LDAP session.
       # If true, the ldap protocol is used and then issues a StartTLS command, otherwise, connections will use
       # the ldaps: protocol.
       startTLS: true

       # User entry search configuration.
       userSearch:
          # To start the user search from. Example: "cn=users,dc=example,dc=com".
         baseDN: <base-dn>

        # Optional filter to apply when searching the directory. Example: "(objectClass=posixAccount)"
         filter: <filter>

          # A mapping of attributes to the username. This value can be used for applying RBAC to a user.
          Default: uid
         nameAttribute: <name-attribute>

        # (Optional) Group search configuration. This value can be used to apply RBAC to a user group.
       groupSearch:

         # BaseDN to start the search from. Example: "cn=groups,dc=example,dc=com".
         baseDN: <base-dn>

        # Optional filter to apply when searching the directory. Example: "(objectClass=posixGroup)"
         filter: <filter>

         # A mapping of attributes to the group name. This value can be used for applying RBAC to a user group. Example: "cn".
         nameAttribute: <name-attribute>

         # Following list contains field pairs that are used to match a user to a group. It adds an additional
         # requirement to the filter that an attribute in the group must match the user's attribute value.
         userMatchers:
           - userAttribute: <user-attribute>
             groupAttribute: <group-attribute>
   ```

2. Apply the secret to your cluster with your LDAP credentials. To obtain the values, consult the documentation of your provider.

   ```yaml
   apiVersion: v1
   kind: Secret
   metadata:
     name: tigera-ldap-credentials
     namespace: tigera-operator
   data:
     bindDN: <your-base64-bind-dn>
     bindPW: <your-base64-bind-password>
     rootCA: <your-base64-ca-cert-pem>
   ```

   If you are using an external secret provider, you can mount your LDAP credentials as a volume through CSI Secret Store Driver to avoid storing the credentials in the Kubernetes cluster.

   Create a `SecretProviderClass` resource named `tigera-ldap-credentials` in the `tigera-operator` namespace that mounts your LDAP credential fields as files `bindDN`, `bindPW` and `rootCA`.

   In its spec, map your source secret/keys so the mounted files are named exactly `bindDN`, `bindPW` and `rootCA`. Use your provider’s standard configuration to supply these values.

   For example, if you are integrating with AWS Secrets Manager, your `SecretProviderClass` resource might look like this:

   ```yaml
   apiVersion: secrets-store.csi.x-k8s.io/v1
   kind: SecretProviderClass
   metadata:
     name: tigera-ldap-credentials
     namespace: tigera-operator
   spec:
     provider: aws
     parameters:
       objects: |
         - objectName: <name-of-ldap-credentials-in-aws-secretsmanager>
           objectType: "secretsmanager"
           jmesPath:
             - path: <field-name-in-your-ldap-credentials-in-aws-secretsmanager-mapping-to-bindDN>
               objectAlias: "bindDN"
             - path: <field-name-in-your-ldap-credentials-in-aws-secretsmanager-mapping-to-bindPW>
               objectAlias: "bindPW"
             - path: <field-name-in-your-ldap-credentials-in-aws-secretsmanager-mapping-to-rootCA>
               objectAlias: "rootCA"
   ```

### Troubleshooting LDAP

**Problem**: Error: (502 bad gateway nginx) when logging in to the web console

**Solution**: nginx ingress cannot handle the length of the token when a groupSearch matches too many groups. To resolve this, apply a filter as shown in the following example.

```yaml
apiVersion: operator.tigera.io/v1
kind: Authentication
  name: tigera-secure
spec:
  ldap:
    groupSearch:
      baseDN: OU=GroupID,OU=Groups,DC=mycompany,DC=com
      filter: (&(objectClass=group)(|(cn=example-dn1)(cn=example-dn2)))
      nameAttribute: cn
      userMatchers:
      - groupAttribute: member
        userAttribute: distinguishedName
host: ldap.mycompany.com:636
startTLS: false
userSearch:
  baseDN: OU=Accounts,DC=mycompany.com,DC=com
  nameAttribute: userPrimaryName
managerDomain: https://calico-manager.mycompany.com
```

<!-- /tabs -->

### Grant user login privileges

> **SECONDARY:** For OpenShift users, replace `kubectl` with `oc` in the following commands, or apply cluster roles from the OpenShift console: **User Management**, **users**.

For admin users, apply this cluster role.

```bash
kubectl create clusterrolebinding <user>-tigera-network-admin --user=<user> --clusterrole=tigera-network-admin
```

For basic users with view-only permissions, apply this role.

```bash
kubectl create clusterrolebinding <user>-tigera-ui-user --user=<user> --clusterrole=tigera-ui-user
```

Or use the groups flag to assign cluster role to a group of users.

```bash
kubectl create clusterrolebinding all-developers-tigera-ui-user --group=<group> --clusterrole=tigera-ui-user
```

### (Optional) Allow Calico Enterprise URIs in your IdP

Most IdPs require redirect URIs to be allowed to redirect users at the end of the OAuth flow to the Calico Enterprise web console or to Kibana. Consult your IdP documentation for authorizing your domain for the respective origins and destinations.

**Authorized redirect URIs**

- `https://<host><port>/dex/callback`

## Troubleshooting

- ManagerDomain `localhost` and `127.0.0.1` are not the same. If you configure `localhost:9443` as your managerDomain, while navigating to `https://127.0.0.1:9443`, the OIDC security checks will deny you access.
- Omit the port from `managerURL` if it is listening on the standard port (`:443`) for HTTPS.
- When your `usernameClaim` is not `email` and `usernamePrefix` is omitted, we have implemented a default prefix identical to how Kubernetes has for their kube-apiserver, see the [oidc-username-claim documentation](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver). For example, if the `managerDomain` in your `Authentication` spec is `https://example.com`, and the username claim maps to `jane`, the (cluster) role binding should be bound to: `https://example.com/dex#jane`
- When you encounter problems while configuring your IdP, we encourage you to use the network tab of the browser dev tools to inspect requests with error codes and to decode authorization headers of the HTTP requests.
- If you would like to bring a self-signed certificate for your IdP and are using OIDC, you can do so by adding the field `rootCA` to secret `tigera-oidc-credentials`. The value for this field should contain the certificate in PEM format.
- If logging into Kibana fails with a `cookie not present` error, update the browser settings to allow third-party cookies, as the Calico Enterprise web console uses Kibana's cookies during login.
- If you need to configure LDAP with a DN that has spaces, use double quotes to escape them. For example: `cn="example common name",ou="example org unit",DC=example,DC=org`.

## Additional resources

- [Configure user roles and permissions](https://docs.tigera.io/calico-enterprise/latest/operations/cnx/roles-and-permissions.md)
- [Configure RBAC for tiered policies](https://docs.tigera.io/calico-enterprise/latest/network-policy/policy-tiers/rbac-tiered-policies.md)
- [Configure RBAC for Elasticsearch](https://docs.tigera.io/calico-enterprise/latest/observability/elastic/rbac-elasticsearch.md)
