Octelium provides unified, seamless, zero trust, secretless access, for both HUMAN and WORKLOAD Users (read more about Users here), to any private/internal on-prem PostgreSQL-based database behind NAT as well as to any publicly protected SaaS PostgreSQL-based database (read more about POSTGRES Services here) without having to share and manage passwords (read more about secretless access here). Octelium provides the following:
- Secretless access for all Users to all PostgreSQL-based databases without sharing and distributing the database passwords to your Users.
- Identity-based, context-aware dynamic routing to different database hosts, users and passwords representing different contexts and privileges.
- Centralized identity-based, application-layer (L7) aware access control (read more about access control here).
- Enforce dynamic SSO, Hardware-based FIDO2 Passkey/WebAuthn authentication for your Users to access sensitive/production databases.
- OpenTelemetry-native, identity-based, L7 aware visibility and auditing that captures requests and responses including serialized JSON body content.
- Seamless horizontal scalability and availability since Octelium operates on top of Kubernetes (read more about how Octelium works here).
- GitOps-friendly declarative, programmable management (read more here).
A Simple Example
In this guide we are going to provide access to an internal PostgreSQL database (check out an example guide for a SaaS PostgreSQL-based database such as CockroachDB here). First, we need to create a Secret for the PostgreSQL database's password as follows:
octeliumctl create secret my-pg-password
Now we create the Service for our database as follows:
1kind: Service2metadata:3name: my-postgres4spec:5mode: POSTGRES6port: 54327config:8upstream:9url: postgres://my-db.local10postgres:11user: postgres12database: postgres13auth:14password:15fromSecret: my-pg-password
If the upstream is listening over TLS, then you can enable the SSL mode as shown in detail here.
The example above shows an upstream that is directly accessible by the Cluster. You can also remotely serve upstreams behind NAT from anywhere as shown in detail here.
You can now apply the creation of the Service as follows (read more here):
octeliumctl apply /PATH/TO/SERVICE.YAML
Now after connecting to the Cluster via the octelium connect command (read more about connecting to Clusters here), you can simply access the database whose hostname is at my-postgres.default or simply my-postgres (read more here) as follows:
psql -h my-postgres
You can also connect via the rootless mode and map the Service to your host's localhost (read more here) as follows:
# Connect as non-root/unprivileged OS useroctelium connect -p my-postgres:5432# Now access the Service at localhostpsql -h localhost
Dynamic Configuration
You can also provide dynamic secretless access where you can set different users, databases and passwords for different Users under different contexts. Read more about dynamic configuration here. Here is an example where Users are dynamically assigned to different PostgreSQL users with different privileges based on their identity.
For example, you could create a full_access user for full access as follows:
1-- Create the user2CREATE USER full_access WITH PASSWORD '<YOUR_PASSWORD>';34-- Grant all privileges on the database5GRANT ALL PRIVILEGES ON DATABASE my_db TO full_access;67-- Connect to the database and grant schema permissions8GRANT ALL PRIVILEGES ON SCHEMA public TO full_access;9GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO full_access;10GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO full_access;
And another read_only user for read-only as follows:
1-- Create the user2CREATE USER read_only WITH PASSWORD '<YOUR_OTHER_PASSWORD>';34-- Grant connect and usage permissions5GRANT CONNECT ON DATABASE my_db TO read_only;6GRANT USAGE ON SCHEMA public TO read_only;78-- Grant select (read) permissions on existing tables9GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only;
Now you define the Service so that more privileged Users belonging to either of engineering or admins Groups to automatically be assigned to the full_access user, and other Users (e.g. junior engineers, AI agents) are assigned to the read_only user as follows:
1apiVersion: core/v12kind: Service3metadata:4name: my-db5spec:6mode: POSTGRES7port: 54328dynamicConfig:9configs:10- name: read-only11upstream:12url: postgres://my-pg:543213postgres:14user: read_only15database: my_db16auth:17password:18fromSecret: read-only-password19sslMode: REQUIRE20- name: full-access21upstream:22url: postgres://my-pg:543223postgres:24user: full_access25database: my_db26auth:27password:28fromSecret: full-access-password29rules:30- condition:31match: ctx.user.spec.groups.hasAny(["engineering", "admins"])32configName: full-access33- condition:34matchAny: true35configName: read-only
Authentication
HUMAN Users can use their emails to authenticate to the Cluster via web browsers using IdentityProviders. There currently 3 methods:
- GitHub OAuth IdentityProvider as shown in detail here
- OpenID Connect IdentityProviders (e.g. Okta, Auth0, etc...) as shown here.
- SAML 2.0 IdentityProviders (e.g. Okta, Entra ID, etc...) as shown here.
Furthermore, HUMAN Users can register their FIDO2 Authenticators (e.g. Yubikeys) in order to natively login later via Passkey (read more here).
You can read more about Authenticators and WebAuthn/TOTP MFA as shown here.
For WORKLOAD Users, they can authenticate themselves via the octelium login or octeliumctl login commands using various ways:
- OAuth2 client credentials (read more here)
- "Secretless" OpenID Connect identity assertions which can be used by
octeliumCLIs and containers running in cloud providers, GitHub Action runners, Kubernetes clusters, etc... (read more here). - Access tokens directly issued and used as bearer authentication tokens (read more here).
Visibility
Octelium also provides OpenTelemetry-ready, application-layer L7 aware visibility and access logging in real time (read more about visibility here). Here is an example:
1{2"apiVersion": "core/v1",3"entry": {4"common": {5// Omitted for the sake of brevity of the example6},7"info": {8"postgres": {9"query": {10"query": "CREATE DATABASE db01;"11},12"type": "QUERY"13}14}15},16"kind": "AccessLog",17"metadata": {18// Omitted for the sake of brevity of the example19}20}