{"id":51358661,"url":"https://github.com/k8shell-io/identity","last_synced_at":"2026-07-02T21:34:01.984Z","repository":{"id":368709835,"uuid":"993402427","full_name":"k8shell-io/identity","owner":"k8shell-io","description":"Indetity service","archived":false,"fork":false,"pushed_at":"2026-07-01T21:47:32.000Z","size":62018,"stargazers_count":1,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-01T22:23:25.659Z","etag":null,"topics":["authentication","identity","jwt","oauth2"],"latest_commit_sha":null,"homepage":"https://docs.k8shell.io/architecture/identity","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/k8shell-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-30T18:19:23.000Z","updated_at":"2026-06-25T16:36:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/k8shell-io/identity","commit_stats":null,"previous_names":["k8shell-io/identity"],"tags_count":137,"template":false,"template_full_name":null,"purl":"pkg:github/k8shell-io/identity","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k8shell-io%2Fidentity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k8shell-io%2Fidentity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k8shell-io%2Fidentity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k8shell-io%2Fidentity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/k8shell-io","download_url":"https://codeload.github.com/k8shell-io/identity/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k8shell-io%2Fidentity/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35064249,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-02T02:00:06.368Z","response_time":173,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","identity","jwt","oauth2"],"created_at":"2026-07-02T21:33:58.435Z","updated_at":"2026-07-02T21:34:01.966Z","avatar_url":"https://github.com/k8shell-io.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# identity\n\n[![Build](https://github.com/k8shell-io/identity/actions/workflows/build.yaml/badge.svg)](https://github.com/k8shell-io/identity/actions/workflows/build.yaml)\n\nThe 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.\n\n## Concepts\n\n### Identity providers\n\nIdentity is built around pluggable providers. A provider is the source of truth for a user record.\n\n| Type | Description |\n|---|---|\n| **Local** (`file`) | Users loaded from YAML files on disk. No onboarding. Good for development and testing. |\n| **Remote** (`idp`)  | gRPC-connected external provider (e.g. GitHub, GitLab). Supports device-flow and web-flow onboarding. |\n\nUsers 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.\n\n### Organizations\n\nEvery 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).\n\n### JWT token lifecycle\n\nOn 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.\n\n### Personal Access Tokens (PATs)\n\nUsers 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.\n\n### User credentials\n\nThe service stores per-user credentials for external services. Resolution is controlled by `credential_source`:\n\n| `credential_source` | `service_name` | How the secret is resolved |\n|---|---|---|\n| `stored` | `registry`, `git` | Secret returned as-is from the database |\n| `kubernetes` | `kubernetes` | Fresh bound SA token issued via TokenRequest API on every call |\n| `\u003cidp-name\u003e` | `git` | Live `GetUserGitToken` RPC to the named provider |\n\nDynamic git credentials are provisioned automatically at the end of device-flow and web-flow onboarding.\n\n### Kubernetes service-account tokens\n\nWhen 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.\n\n### Authorization policies\n\nThe service integrates with an external authz service (gRPC) to enforce OPA/Rego policies at key lifecycle points:\n\n- **`user:onboard`** — evaluated before a new user is persisted. Can deny onboarding or attach obligations (sudo, roles, blueprints).\n- **`user:auth`** — evaluated on each authentication attempt.\n- **`token:create`** — evaluated before issuing a PAT. Can restrict scopes or maximum expiry.\n\nThe authz client is optional; all policy checks are no-ops when `authz` is not configured.\n\n### gRPC API\n\nThe service exposes two gRPC interfaces defined in the separate `github.com/k8shell-io/common` module:\n\n- `IdentityService` (`identity.proto`) — user lookup, authentication, onboarding, credential management, PAT lifecycle. Consumed by other k8shell services.\n- `IdentityProviderService` (`idp.proto`) — implemented by remote identity providers. Identity connects to them as a client. No other service accesses this interface directly.\n\n## Repository layout\n\n```\ninternal/\n  db/          # Postgres access (users, credentials, access tokens)\n  providers/\n    file/      # File-backed identity provider\n  server/      # gRPC server, JWT issuance, credential resolution, policy evaluation\ndb/migrations/ # SQL migrations (golang-migrate)\nbackend/       # Docker Compose for local Postgres\nconfig/        # Example configuration and user files\ndocker/        # Dockerfile (alpine + distroless stages)\n```\n\n## Prerequisites\n\n- Go 1.24+\n- Docker\n- A running Postgres instance (see `backend/compose.yaml`)\n\n## Local development\n\n**Start Postgres:**\n```bash\ndocker compose -f backend/compose.yaml up -d\n```\n\n**Run database migrations** (use [golang-migrate](https://github.com/golang-migrate/migrate)):\n```bash\nmigrate -path db/migrations -database \"postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable\" up\n```\n\n**Build and run:**\n```bash\nmake build\n./bin/identity --config config/config.yaml --logtext\n```\n\n**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.\n\n## Makefile targets\n\n| Target | Description |\n|---|---|\n| `make build` | Compile binary to `bin/identity` |\n| `make test` | Run unit tests with coverage |\n| `make test-static` | Run `golangci-lint` and `gosec` |\n| `make test-self` | Static analysis + build + smoke tests (used in CI) |\n| `make image` | Build Docker image (Alpine by default) |\n| `RUNTIME=distroless make image` | Build production-hardened distroless image |\n| `make vendor` | Vendor Go dependencies |\n\n## Docker images\n\nTwo runtime stages are available in `docker/identity/Dockerfile`:\n\n| Stage | Base | Use case |\n|---|---|---|\n| `alpine` | `alpine:3.21.3` | Development, debugging (has a shell) |\n| `release` | `distroless/static-debian12:nonroot` | Production (no shell, runs as non-root) |\n\nBoth stages use the same statically compiled binary (`CGO_ENABLED=0`, `-ldflags=\"-s -w\"`).\n\n## Running in Kubernetes\n\nDeployment 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.\n\n## License\n\nAGPL-3.0-or-later. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk8shell-io%2Fidentity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fk8shell-io%2Fidentity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk8shell-io%2Fidentity/lists"}