Skip to content
limen-devPublic

About

Self-hosted, identity-aware access to SSH, databases, Kubernetes, message brokers and internal apps. Short-lived certificates instead of keys and passwords, and an audit trail you can verify yourself.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Limen

Identity-aware access to your infrastructure. Short-lived, audited, self-hosted.

CI License: Apache-2.0 Written in Rust Roadmap

Try it · How it works · What it connects to · What is not verified yet · Docs

Limen

Limen decides who can reach your servers, databases and clusters, and keeps a record of what they did there.

Engineers sign in through your company's identity provider. Limen checks a policy you keep in Git, then gives them a certificate that expires in an hour (or sooner: you choose per role). They connect with the tools they already use (ssh, psql, kubectl, redis-cli), and every session is recorded or audited into a signed trail you can verify yourself. CI jobs sign in the same way, with their own short-lived token, so your pipelines hold no long-lived secret either.

It is open source (Apache-2.0), written in Rust, and you run it on your own infrastructure. It is not production-ready yet: there is no release, and nothing has been tried against real cloud services. What is not verified yet has the details.

Why you might want it

Keys, passwords and tokens tend to outlive the reason they were handed out. Limen is built so that no person or pipeline holds one for long, and so that you can always answer two questions: who can get in right now, and what did they do?

Without it With Limen
Getting onto a server An SSH key that stays valid until someone removes it A certificate that expires in an hour, or sooner if you choose
Getting into a database A password that people copy and share limen db connect orders-prod. Only Limen's worker holds the database credential; no person sees it
Someone leaves the team Find and remove every key and password they had Disable them in your identity provider and they can't start new sessions. limen admin lock also ends their open ones within seconds
A CI job deploys A long-lived secret stored in the CI settings The job's own OIDC token becomes a short, scoped login
The network Targets reachable from a bastion or a VPN Limen's worker dials out from your network, so targets need no inbound port
"Who ran that DELETE?" Depends on what the database logs, and for how long Every statement, tied to the person or CI job that ran it, in a hash-chained trail

What using it looks like

$ limen login --proxy limen.example.com:443   # a browser opens on your identity provider
$ limen ls                                    # what am I allowed to reach?
NAME             KIND        ACCESS AS                LABELS
bastion-staging  ● ssh       ec2-user, ubuntu         env=staging tier=bastion
orders-staging   ● postgres  limen_read, limen_write  env=staging team=payments
web-staging-1    ● ssh       ec2-user, ubuntu         env=staging
  3 resources · `limen show <name>` tells you how to connect to one

$ limen ssh web-staging-1                     # a recorded SSH session
$ limen db connect orders-staging             # a local address for psql, no password needed
$ limen explain orders-prod                   # why can't I reach this one?
$ limen request orders-prod --for 30m --reason "INC-123: orders table is locked"

If a resource isn't in your list, limen explain tells you which rule stopped you, and limen request asks an approver for time-limited access.

Try it on your laptop

There is no release to download yet, so this builds Limen from source and runs the whole system on your machine, with a test identity provider and test users. You need Docker (on macOS, OrbStack or Docker Desktop) and the tools pinned in mise.toml (run mise install). The first build takes several minutes.

git clone https://github.com/limen-dev/limen && cd limen

# 1. Start everything. The script checks your tools, asks what to enable (an SSH host,
#    databases, Redis, Kubernetes, observability...), applies an example policy, and
#    prints a ready-to-run command for each resource.
deploy/compose/setup.sh

# 2. Install the CLI (re-run after pulling to upgrade)
scripts/install-cli.sh

# 3. Sign in. A browser opens; use admin@example.com with the password "password".
limen --proxy localhost:3443 login --ca-file deploy/compose/.state/internal-ca.pem

# 4. Connect
limen ls
limen ssh web-staging-1

# 5. Open the web console, sign in as the same user, and replay the session you just had
open https://localhost:3443/console/        # on Linux, paste the address into a browser

Note

Your browser will warn about the console's certificate. That is expected: it comes from a development CA the script just created. Click through the warning on localhost. Don't add that CA to your system's trust store. The other test users, and what each one is allowed to see, are listed in deploy/compose/README.md.

The quickstart walks through the same steps with more explanation.

How it works

How Limen works: people and bots sign in through your identity provider, connect through one public load balancer to proxies, and reach targets through workers that only dial out; every session is audited

Limen is three programs:

  • The control plane signs people and bots in through your identity provider, issues their short-lived certificates, keeps the policy, and writes the audit trail. The only database it needs is PostgreSQL.
  • The proxy is the one public entry point. It checks each connection against the policy and passes it to the right worker.
  • The worker runs inside your network, next to the things you want to reach. It dials out to the proxy, so nothing on your side needs an open inbound port. It speaks each target's protocol, records or audits the session, and signs in to the target with credentials only it holds.

All three are static binaries. If Limen can't write the audit trail, it refuses new sessions rather than let them run unrecorded.

The diagrams page follows one connection step by step, and shows where credentials and audit events go when parts of the system fail.

What it connects to

Each target works with ordinary self-hosted servers and with the managed services listed under it. ✅ means built and tested against a local copy of that software. ⚠️ names the managed-service parts that have not been tried for real yet.




SSH
Amazon EC2 and any SSH host
a certificate per session, recorded and replayable


✅ tested locally




PostgreSQL
RDS · Aurora · Redshift
every statement audited


✅ tested locally
⚠️ RDS IAM and Redshift





MySQL
RDS · Aurora
every statement audited


✅ tested locally
⚠️ RDS IAM





Redis and Valkey
ElastiCache
commands audited, values redacted


✅ tested locally
⚠️ ElastiCache IAM





Kubernetes
Amazon EKS and any cluster
impersonation, recorded exec


✅ tested on kind
⚠️ EKS





MongoDB
Atlas · DocumentDB
commands audited, values redacted


✅ tested locally
⚠️ Atlas, DocumentDB, AWS IAM





OpenSearch
Amazon OpenSearch Service
policy by index pattern


✅ tested locally
⚠️ the AWS service





Elasticsearch
self-hosted and Elastic Cloud
policy by index pattern


✅ tested locally
⚠️ Elastic Cloud





RabbitMQ
Amazon MQ
message bodies never audited


✅ tested locally
⚠️ Amazon MQ





Kafka
Amazon MSK
record values never audited


✅ tested locally
⚠️ MSK and its IAM sign-in





Internal web apps
single sign-on in front of any web UI
every request audited


✅ tested locally




Anything else over TCP
through a port on your machine
same policy, same audit


✅ tested locally

Who can sign in




Any OIDC provider
Okta, Entra ID, Keycloak, Auth0, Dex
your groups map to Limen roles


✅ tested with Dex
⚠️ Okta and the others





GitHub Actions
the job's OIDC token
becomes a bot login


✅ tested with a stand-in issuer
⚠️ real GitHub tokens





GitLab CI
the job's ID token
becomes a bot login


✅ tested with a stand-in issuer
⚠️ real GitLab tokens





Other automation
any OIDC token, including
Kubernetes service accounts


✅ tested with a stand-in issuer
⏳ AWS IAM: Phase 15


A bot is matched on exact claims of its token (for example the repository and the branch), gets a short-lived certificate (15 minutes by default, at most an hour), and is bound by the same policy. The CI run that made each request is written into every audit event.

Audit and monitoring




S3, signed and chained
batches signed and linked by hash
checked by limen-audit-verify


✅ tested with a local S3
⚠️ Amazon S3





Datadog
logs, plus monitors
as Terraform


✅ tested with a fake intake
⚠️ real Datadog





Grafana
optional dashboards
over S3 and Athena


✅ tested with Trino
⚠️ Athena





Metrics and traces
Prometheus /metrics, OpenTelemetry traces,
example alerts


✅ tested locally

Audit events are written to S3 in signed batches, and each batch records the hash of the one before it, like links in a chain. If a batch goes missing, is reordered, or is edited, one command finds it:

limen-audit-verify --bucket <your-audit-bucket> --ca-file internal-ca.pem

Traces carry only ids and outcomes, never user names, SQL statements or tokens. To see one locally, start the dev stack with Jaeger: deploy/compose/setup.sh --yes --stacks ssh,tracing.

The console and the CLI

Web console

  • Resources: everything Limen can reach, who has access, and whether a worker is serving it
  • Sessions: live and past, with SSH sessions you can replay or watch live in the browser, and a button to end a session
  • Access: ask for access, and approve or deny requests, seeing what the person did on that resource in the past 30 days
  • Audit: search every event, and jump from a statement to the moment in the recording
  • Reviews: keep or remove each person's access, and download a signed evidence pack
  • Users, bots and workers: lock a user with a reason, issue join tokens, revoke a worker
  • Policy: the active policy, and a preview of what changes before you apply a new one
  • Everyone except admins and auditors sees only their own resources and sessions

Command line

  • limen login through your identity provider, in a browser or with --device; limen status shows who you are and the time left
  • limen ls shows what you can reach, as a table or as JSON; limen show <name> says how to connect to one
  • limen ssh, limen db connect, limen kube login and the rest, one per protocol, or limen connect <name> to pick for you
  • limen config ssh lets plain ssh work through Limen
  • limen explain says why you can or can't reach something
  • limen request asks for time-limited access; limen approve and deny answer one
  • limen policy test, who-can and diff question a policy before it ships
  • limen admin applies policy, locks users, ends sessions and manages workers

Where it runs

Status
Docker Compose, the full stack on one machine ✅ works; this is the local dev stack
Kubernetes, several copies of each program ✅ example manifests; ⚠️ not yet run on a real cluster
Terraform for the audit store (S3, Glue, Athena) and the Datadog monitors ✅ works
Amazon ECS and EC2, and a Helm chart ⏳ planned, Phase 15

What is not verified yet

Limen is tested thoroughly, but only against local stand-ins: Dex in place of a real identity provider, databases and brokers in containers, a local S3 and KMS, and a fake Datadog intake. Nothing has been verified against real AWS, Okta or Datadog yet. The ⚠️ marks above say exactly which paths that affects, and each one has an issue in the real-environment verification milestone.

Production hardening (a Helm chart, cloud deployment modules, a penetration test) comes after the next phase, and there is no tagged release yet. Until both are done, treat Limen as something to evaluate, not something to put in front of production systems.

Roadmap

Phases 0 to 13 are done: login and tunnels, SSH with recording, the audit pipeline, the console, bots, scale-out, the database, cache, Kubernetes, search and messaging protocols, internal web apps, and access workflows (requests and break-glass, audit search, discovery, policy tooling, access reviews, and watching a live session).

Next:

  • Phase 14, one management API (in progress): manage roles, resources, and bots from the CLI, the console, or Terraform, with one owner per document and scoped writers for automation (ADR-0042, milestone)
  • Phase 15, production readiness: a Helm chart, ECS and EC2 modules, and a penetration test (milestone)
  • Verification against real services (milestone)
  • The documentation site, already built in website/, is published when the repository goes public (milestone)

Every phase is a GitHub milestone with its checklist in an epic issue. What "done" means for each one is in docs/design.md §13.

Documentation

Start here

Connect

Control access

Audit and operate

How it is built

Why "Limen"

Limen is Latin for "threshold", the root of the English word liminal. A threshold is where you stop until you're allowed in. That is the job: you prove who you are, Limen lets you across for a short, recorded visit, and the door closes behind you.

It's also short enough to type all day (limen login, limen ssh). Say it "LIE-men" or "LEE-men"; both are common.

Security

Found a vulnerability? Please report it privately through GitHub, not in a public issue. SECURITY.md explains how, and what is in scope.

Contributing

CONTRIBUTING.md covers the repository layout, how to build and test, and the conventions. Coding agents should read AGENTS.md.

License

Apache-2.0. Icons are from Simple Icons (CC0) and Lucide (ISC). Product names and logos belong to their owners and appear here only to say what Limen works with.

About

Self-hosted, identity-aware access to SSH, databases, Kubernetes, message brokers and internal apps. Short-lived certificates instead of keys and passwords, and an audit trail you can verify yourself.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages