https://github.com/k8shell-io/identity
Indetity service
https://github.com/k8shell-io/identity
authentication identity jwt oauth2
Last synced: about 15 hours ago
JSON representation
Indetity service
- Host: GitHub
- URL: https://github.com/k8shell-io/identity
- Owner: k8shell-io
- License: agpl-3.0
- Created: 2025-05-30T18:19:23.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2026-07-01T21:47:32.000Z (1 day ago)
- Last Synced: 2026-07-01T22:23:25.659Z (1 day ago)
- Topics: authentication, identity, jwt, oauth2
- Language: Go
- Homepage: https://docs.k8shell.io/architecture/identity
- Size: 59.1 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# identity
[](https://github.com/k8shell-io/identity/actions/workflows/build.yaml)
The k8Shell Identity service. Manages user identities, authenticates users via SSH public key or password, issues JWTs, manages per-user external credentials, and provides on-demand Kubernetes service-account tokens via the TokenRequest API.
## Concepts
### Identity providers
Identity is built around pluggable providers. A provider is the source of truth for a user record.
| Type | Description |
|---|---|
| **Local** (`file`) | Users loaded from YAML files on disk. No onboarding. Good for development and testing. |
| **Remote** (`idp`) | gRPC-connected external provider (e.g. GitHub, GitLab). Supports device-flow and web-flow onboarding. |
Users are cached in Postgres and refreshed from the provider when the cached record expires. Remote providers unavailable at startup are retried every 30 seconds in the background.
### Organizations
Every user belongs to exactly one organization (tenant). Organizations referenced by incoming users can be created automatically via the `organizations.autoCreate` config list (use `["*"]` to allow all).
### JWT token lifecycle
On login the service issues a signed JWT for the authenticated user. Tokens are issued on demand — there is no background refresh loop and no token state is stored in the database.
### Personal Access Tokens (PATs)
Users can hold long-lived Personal Access Tokens with scope restrictions. PATs use the `k8sh_` prefix and are stored as `sha256(raw)` only — the raw value is returned once at creation. API gateways call `ResolveAccessToken` on every `k8sh_` request; the service verifies the token, updates `last_used_at`, and exchanges it for a short-lived JWT. PAT scopes and maximum expiry can be constrained by the `token:create` authz policy. PATs can also be provisioned automatically during web-flow onboarding.
### User credentials
The service stores per-user credentials for external services. Resolution is controlled by `credential_source`:
| `credential_source` | `service_name` | How the secret is resolved |
|---|---|---|
| `stored` | `registry`, `git` | Secret returned as-is from the database |
| `kubernetes` | `kubernetes` | Fresh bound SA token issued via TokenRequest API on every call |
| `` | `git` | Live `GetUserGitToken` RPC to the named provider |
Dynamic git credentials are provisioned automatically at the end of device-flow and web-flow onboarding.
### Kubernetes service-account tokens
When a credential with `credential_source: kubernetes` is resolved, the service issues a fresh, short-lived bound service-account token on demand via the Kubernetes TokenRequest API. No token is stored — every request results in a new token issued directly from the cluster. The TTL is controlled by `kubernetes.saToken.ttl` in the service configuration.
### Authorization policies
The service integrates with an external authz service (gRPC) to enforce OPA/Rego policies at key lifecycle points:
- **`user:onboard`** — evaluated before a new user is persisted. Can deny onboarding or attach obligations (sudo, roles, blueprints).
- **`user:auth`** — evaluated on each authentication attempt.
- **`token:create`** — evaluated before issuing a PAT. Can restrict scopes or maximum expiry.
The authz client is optional; all policy checks are no-ops when `authz` is not configured.
### gRPC API
The service exposes two gRPC interfaces defined in the separate `github.com/k8shell-io/common` module:
- `IdentityService` (`identity.proto`) — user lookup, authentication, onboarding, credential management, PAT lifecycle. Consumed by other k8shell services.
- `IdentityProviderService` (`idp.proto`) — implemented by remote identity providers. Identity connects to them as a client. No other service accesses this interface directly.
## Repository layout
```
internal/
db/ # Postgres access (users, credentials, access tokens)
providers/
file/ # File-backed identity provider
server/ # gRPC server, JWT issuance, credential resolution, policy evaluation
db/migrations/ # SQL migrations (golang-migrate)
backend/ # Docker Compose for local Postgres
config/ # Example configuration and user files
docker/ # Dockerfile (alpine + distroless stages)
```
## Prerequisites
- Go 1.24+
- Docker
- A running Postgres instance (see `backend/compose.yaml`)
## Local development
**Start Postgres:**
```bash
docker compose -f backend/compose.yaml up -d
```
**Run database migrations** (use [golang-migrate](https://github.com/golang-migrate/migrate)):
```bash
migrate -path db/migrations -database "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable" up
```
**Build and run:**
```bash
make build
./bin/identity --config config/config.yaml --logtext
```
**Configuration** is a YAML file. Secrets and connection parameters can be injected via environment variables or `!file` references. See `config/config.yaml` for the full reference.
## Makefile targets
| Target | Description |
|---|---|
| `make build` | Compile binary to `bin/identity` |
| `make test` | Run unit tests with coverage |
| `make test-static` | Run `golangci-lint` and `gosec` |
| `make test-self` | Static analysis + build + smoke tests (used in CI) |
| `make image` | Build Docker image (Alpine by default) |
| `RUNTIME=distroless make image` | Build production-hardened distroless image |
| `make vendor` | Vendor Go dependencies |
## Docker images
Two runtime stages are available in `docker/identity/Dockerfile`:
| Stage | Base | Use case |
|---|---|---|
| `alpine` | `alpine:3.21.3` | Development, debugging (has a shell) |
| `release` | `distroless/static-debian12:nonroot` | Production (no shell, runs as non-root) |
Both stages use the same statically compiled binary (`CGO_ENABLED=0`, `-ldflags="-s -w"`).
## Running in Kubernetes
Deployment configuration and Helm charts for identity and the other k8shell services are maintained in the [k8shell-io/charts](https://github.com/k8shell-io/charts) repository.
## License
AGPL-3.0-or-later. See [LICENSE](LICENSE).