Identity Providers

An IdentityProvider represents an identity provider (IdP) that is used by the Cluster to authenticate and re-authenticate the Users in order for them to obtain and keep a valid Session and consequently be able to interact with the Cluster and access its Services (read more about Sessions here). As will be discussed in detail below, an IdentityProvider has one of the following types: github, oidc, saml and oidcIdentityToken.

A User can have one or more explicit identities, each for a different IdentityProvider. For example, a single User can use both GitHub or Okta with SAML 2.0 to authenticate themselves. You can read more about User identities here.

Web Identity Providers

Whenever you create an OAuth2/OIDC/SAML 2.0 application from within your identity provider's dashboard, you need to set the redirection URL to https://<DOMAIN>/callback in your application settings in order for the identity provider to know where to redirect the authentication flow back to Portal.

You should have a look at the reference here to see all provider-specific options.

In order for the Users to see a web IdP IdentityProvider in the login page and use it to log in to the Cluster, you have to explicitly add its name in the ClusterConfig's list of web IdentityProviders. You can read more here.

GitHub OAuth2

The GitHub IdentityProvider can be defined as in the following example:

1
kind: IdentityProvider
2
metadata:
3
name: github
4
displayName: GitHub
5
spec:
6
github:
7
clientID: abcdef...
8
clientSecret:
9
fromSecret: <SECRET_NAME>
NOTE

As you can see, the client secret is referenced by a Secret resource via the field fromSecret in very similar way to how secrets are referenced in Kubernetes for example. That means you have to first create a Secret via the command octeliumctl create secret and then reference it by its name in your IdentityProvider. You can read more about Secrets here.

To get the IdentityProvider client ID and secret, you will have to create an OAuth application as follows:

  1. Go to Developer Settings here.
  2. Add a new OAuth app.
  3. Set the Authorization callback URL field to https://<DOMAIN>/callback.

OpenID Connect

OpenID Connect is an identity layer built on top of the OAuth 2.0 protocol and is currently usually preferred over SAML in most cases. Octelium can use an OIDC client to authenticate the User from an OIDC IdentityProvider. Here is an example:

1
kind: IdentityProvider
2
metadata:
3
name: okta-oidc-01
4
displayName: Okta
5
spec:
6
oidc:
7
issuerURL: https://dev-<ID>.okta.com
8
clientID: <CLIENT_ID>
9
clientSecret:
10
fromSecret: <SECRET_NAME>
11
# Optional, by default the claim `email` is used as the identifier.
12
identifierClaim: custom-identifier
13
# Optional but RECOMMENDED, this checks whether the claim `email_verified` claim value is set to true.
14
checkEmailVerified: true
15
# Optional, this obtains the claims via the UserInfo endpoint instead of the ID token.
16
useUserInfoEndpoint: true
17
# Optional, by default the scopes `profile` and `email` are added in addition to the mandatory scope `openid`.
18
scopes: ["scope1", "scope2"]

SAML 2.0

You can define a SAML 2.0 IdentityProvider as in the following example:

1
kind: IdentityProvider
2
metadata:
3
name: okta-saml-01
4
displayName: Okta SAML
5
spec:
6
saml:
7
# Required
8
metadataURL: https://dev-12345678.okta.com/app/123456789abcde/sso/saml/metadata
9
# Optional, the entity ID by default is set to https://<DOMAIN>
10
# i.e. if the Cluster domain is example.com then the entity ID is https://example.com
11
entityID: urn:<DOMAIN>
12
# Optional. By default, the identifier attribute is assumed to be
13
# `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`.
14
identifierAttribute: custom-email-attr
15
# Optional, this forces a re-authentication even if the user has a SSO session at the IdP
16
forceAuthn: true

By default, the SAML 2.0 provider always checks for the user's identifier, typical the email, using the identifierAttribute which is set by default to http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress. However, you can always override that value by setting identifierAttribute.

User Email as an Identifier

By default, an authentication by a web IdP IdentityProvider (ie. GitHub OAuth2, OpenID Connect or SAML 2.0 IdentityProvider) at first tries to find the User via an explicitly set identity (read more here) with an identityProvider field that matches the IdP IdentityProvider's name and identifier that matches the identifier in the assertion returned by the provider.

If no explicit identity matches or if the list of identities is simply empty, then the email field of the User (read more here) is then inspected against the identifier in the assertion returned to the Cluster by the identity provider. In other words, the email field acts as a default identifier that can be used automatically for any IdP IdentityProvider to find a User. However, you can disable this default behavior in a certain IdentityProvider, for example, when you do not trust that the email has been verified by that identity provider, as follows:

1
kind: IdentityProvider
2
metadata:
3
name: github
4
displayName: GitHub
5
spec:
6
disableEmailAsIdentity: true
7
github:
8
clientID: <CLIENT_ID>
9
clientSecret:
10
fromSecret: <SECRET_NAME>

Public Display Name

You can set the public display name that shows up on the button of the corresponding IdentityProvider when Users visit the login page. If not set, the resource metadata's display name will be used as a fallback. Here is an example:

1
```yaml
2
kind: IdentityProvider
3
metadata:
4
name: okta-oidc
5
displayName: Okta OIDC
6
spec:
7
displayName: Login with Okta
8
oidc:
9
# The rest of your configuration

Workload Identity Providers

OIDC Assertion

Octelium currently also supports authentication for WORKLOAD Users using OpenID Connect (OIDC) assertions where workloads can authenticate themselves to the Cluster using OIDC ID tokens issued by the identity provider hosting the workload instead of typically having to use authentication token Credentials. The main disadvantage of using authentication tokens is that they need to be issued by the Cluster and have to be stored securely at the User's side. This can be cumbersome at scale and may lead to a breach if a Credential leaks. This "secret-less" assertion-based authentication method is increasingly getting more popular recently for workloads running on major cloud providers such as Azure, CI/CD providers such as GitHub Actions and CircleCI and it can also work for Kubernetes clusters. There are 3 modes to define the OIDC assertion IdentityProvider:

Public OIDC Issuer

This mode is preferable when the OIDC issuer publicly publishes its endpoint. Many cloud providers, CI/CD providers and managed Kubernetes clusters already offer their OIDC endpoint publicly.

1
kind: IdentityProvider
2
metadata:
3
name: github-actions-01
4
spec:
5
oidcIdentityToken:
6
# this is the URL that will be appended with the path "/.well-known/openid-configuration"
7
# to get the discovery-document URL of the issuer
8
issuerURL: https://token.actions.githubusercontent.com
9
audience: https://example.com

JWKS URL

In some cases, you might want to set the JWKS url directly if you are not dealing with a fully compliant OIDC provider. In such case, you also have to explicitly set the issuer in order to be verified against the issuer claim in the OIDC ID token assertion.

1
kind: IdentityProvider
2
metadata:
3
name: github-actions-01
4
spec:
5
oidcIdentityToken:
6
jwksURL: https://token.actions.githubusercontent.com/.well-known/jwks
7
issuer: https://token.actions.githubusercontent.com
8
audience: https://example.com

JWKS Content

This mode can be useful for cases where the OIDC issuer is not publishing its endpoint publicly (e.g. Kubernetes clusters that do not publish their endpoints publicly). In this case you can just manually set the JWKS content manually. In such case, you also have to explicitly set the issuer in order to be verified against the issuer claim in the OIDC ID token assertion.

1
kind: IdentityProvider
2
metadata:
3
name: k8s-01
4
spec:
5
oidcIdentityToken:
6
jwksContent: |
7
{
8
"keys": [
9
{
10
"use": "sig",
11
"kty": "RSA",
12
"kid": "I4twhfbX-awEXmXezQS_i_e7L-a6EWRp8-fYdAhga6A",
13
"alg": "RS256",
14
"n": "oloso_qOKvQ8Fu9rkUVUHqYJsyQ_2p_G_pAp5....",
15
"e": "AQAB"
16
}
17
]
18
}
19
issuer: https://kubernetes.default.svc.cluster.local
20
audience: https://kubernetes.default.svc.cluster.local

Authenticator Assurance Level

One of the important goals of the zero trust model is to control access based on the User's identity whose degree of confidence and assurance depends on the strength of authentication methods used by SSO identity providers. For example, an IdP might only require a password, another might require MFA second-factor authentication method such as TOTP, and a third forces the User to authenticate with a hardware-based phishing resistant authenticators such as FIDO-2 security keys (e.g. Yubikey) that is capable of enforcing user consent and verification methods during authentication such as biometric (e.g. fingerprint) or PIN in order for the authenticator to proceed with the authentication process. NIST defines a technical guide of 3 authenticator assurance levels (AAL) of increasing strength AAL1, AAL2 and AAL3 here where level-3 corresponds to the highest level of assurance. Octelium enables you to control such AAL level during authentication depending on the content of the assertion (e.g. ID token in the case of OpenID Connect IdentityProviders) returned by the IdP to the Cluster, and use the resulting AAL in your access control decisions (read more about access control and Policies here). For example, you might want to be sure that all or certain Users can access all Services or certain sensitive Services only if they authenticated via a phishing resistant hardware-based authenticator that satisfies AAL3 requirements. Here is an example:

1
kind: Policy
2
metadata:
3
name: production-policy
4
spec:
5
rules:
6
- name: production
7
effect: ALLOW
8
condition:
9
all:
10
of:
11
- match: ctx.namespace.metadata.name == "production"
12
- match: "ops" in ctx.user.spec.groups
13
- match: ctx.user.spec.type == "HUMAN"
14
- match: ctx.session.status.authentication.info.aal == "AAL3"

To actually set the AAL value based on the assertion content upon authentication, Octelium enables you to define your own policy-as-code AAL rules, represented by the aalRules list as shown below, where the value chosen corresponds to the first rule whose condition matches. This is similar to dynamic configuration rules (read more here). Octelium converts the assertion into a map in the case of oidc, oidcIdentityToken and github IdentityProviders where you can define your conditions in the assertionMap object. Here is an example:

1
kind: IdentityProvider
2
metadata:
3
name: oidc-01
4
displayName: My OIDC IdP
5
spec:
6
oidc:
7
issuerURL: https://oidc.example.com
8
# The rest of your configs
9
aalRules:
10
- aal: AAL3
11
condition:
12
match: ctx.assertionMap.hasMFA
NOTE

For the case of OpenID Connect, some IdPs use standard claims such as amr and acr to provide AAL information, others do use custom claims.

For the case of saml IdentityProviders, the assertion is available as a string value in the assertion field. Here is an example:

1
kind: IdentityProvider
2
metadata:
3
name: oidc-01
4
displayName: My OIDC IdP
5
spec:
6
saml:
7
# The rest of your configs
8
aalRules:
9
- aal: AAL2
10
condition:
11
match: ctx.assertion.contains("mfa")

Disabling an IdentityProvider

You can disable/deactivate a IdentityProvider and immediately disable the Users ability to see that IdentityProvider in the log in page or log in with it. Here is an example:

1
kind: IdentityProvider
2
metadata:
3
name: oidc
4
spec:
5
isDisabled: true
6
oidc:
7
# The rest of your configurations
© 2025 octelium.comOctelium Labs, LLCAll rights reserved
Octelium and Octelium logo are trademarks of Octelium Labs, LLC.
WireGuard is a registered trademark of Jason A. Donenfeld