ManagementCore API
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.

Listing IdentityProviders

You can list the Cluster's IdentityProviders as follows:

octeliumctl get identityprovider
# Or simply
octeliumctl get idp
# Show a certain IdentityProvider
octeliumctl get cred <NAME>

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.

Login Page Example

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: github-client-secret
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 and fill the following required fields as follows:
  • Set the Homepage URL field to https://<DOMAIN>
  • Authorization callback URL field to https://<DOMAIN>/callback

Now you obtain the OAuth client credentials and you set the client secret as an Octelium Secret as follows:

octeliumctl create secret github-client-secret

And now you can actually create your IdentityProvider as follows:

1
kind: IdentityProvider
2
metadata:
3
name: github
4
spec:
5
github:
6
clientID: abcdef....
7
clientSecret:
8
fromSecret: github-client-secret

And apply the creation with an octeliumctl apply command (read more here).

NOTE

Note that while Octelium requests the email and user OAuth scopes from GitHub, GitHub might not always reveal the user email if the user keeps their primary email as private in their GitHub user settings. Therefore, using email as an identifier for GitHub depends on whether the user keeps their primary email private regardless of the granted OAuth scopes. You can use, however, the GitHub usernames as an identifier of a certain IdentityProvider for such users in the User's list of identities (read more here). Here is an example:

1
kind: User
2
metadata:
3
name: linus
4
spec:
5
type: HUMAN
6
authentication:
7
identities:
8
# "github" is the name of the IdentityProvider
9
- identityProvider: github
10
# "linus" here is the GitHub account username
11
identifier: linus

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
# REQUIRED. Your issuer URL is where the OIDC configuration can be
8
# obtained automatically by adding the suffix "/.well-known/openid-configuration"
9
# to the value of "issuerURL"
10
issuerURL: https://dev-<ID>.okta.com
11
# REQUIRED
12
clientID: <CLIENT_ID>
13
# REQUIRED
14
clientSecret:
15
fromSecret: <SECRET_NAME>
16
# Optional, by default the claim `email` is used as the identifier.
17
identifierClaim: custom-identifier
18
# Optional but RECOMMENDED, this checks whether the claim `email_verified` claim value is set to true.
19
checkEmailVerified: true
20
# Optional, this obtains the claims via the UserInfo endpoint instead of the ID token.
21
useUserInfoEndpoint: true
22
# Optional, by default the scopes `profile` and `email` are added in addition to the mandatory scope `openid`.
23
scopes: ["scope1", "scope2"]
NOTE

As mentioned in the example above, the value of the issuerURL is when appended by /.well-known/openid-configuration shows you the OIDC discovery endpoint, or simply the OIDC provider configuration document. In some OIDC providers such as Auth0, such value needs to be appended with a final trailing slash since the issuer field in the endpoint document must match the issuerURL.

Gitlab Example

You can use Gitlab cloud as an OpenID Connect IdentityProvider as follows:

  1. Go to Applications in Settings here to add a new application.
  2. Set the Redirect URI field to https://<DOMAIN>/callback.
  3. Enable openid, email and profile in the scopes.
  4. Now you create an Octelium Secret from the obtained Gitlab app secret as follows:
octeliumctl create secret gitlab-oidc

And then set the value when asked.

  1. Now you can actually create the Gitlab IdentityProvider as follows:
1
kind: IdentityProvider
2
metadata:
3
name: gitlab
4
spec:
5
displayName: Login with Gitlab
6
oidc:
7
issuerURL: https://gitlab.com
8
# Your clientID is your Gitlab's Application ID
9
clientID: d46f...
10
clientSecret:
11
fromSecret: gitlab-oidc

And apply the creation with an octeliumctl apply command (read more here).

NOTE

For more information regarding using Gitlab as an OpenID Connect identity provider, you can read Gitlab's own docs here

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

You can also use the metadata content directly instead of using a metadata URL as follow:

1
kind: IdentityProvider
2
metadata:
3
name: okta-saml-01
4
displayName: Okta SAML
5
spec:
6
saml:
7
# Required
8
metadata: |
9
<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://accounts.google.com/o/saml2?idpid=ABCDEFG" validUntil="2030-01-01T13:48:23.000Z">
10
### The rest of the metadata XML content
11
identifierAttribute: email
12
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

Post-Authentication Rules

By default, a successful authentication/re-authentication by an IdentityProvider automatically creates/extends the validity of the Session. Post-authentication rules, however, provide you a way to control that behavior, enabling you to reject even a successful authentication via policy-as-code rules. This can be useful, for example, to prevent certain Users, or certain groups of Users, from logging in during certain times or under certain contexts, or logging in via certain IdentityProviders, or logging in without using strong, hardware-based MFAs such as security keys. Here is an example that only allows Users whose email domain is example.com who log in with an AAL of AAL3 to be able to use that particular IdentityProvider, otherwise do not accept the log-in:

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
postAuthenticationRules:
10
- condition:
11
match: ctx.user.spec.email.endsWith("@example.com") && ctx.authenticationInfo.aal == "AAL3"
12
effect: ALLOW
13
- condition:
14
matchAny: true
15
effect: DENY
© 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