Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,13 @@ Groups decide access. Each OIDC client names one group in `metadata.required_gro
| `site-admins` | The bulbashenko.com admin panel |
| `mail-users` | Mail clients and the Stalwart web UI |
| `vpn-users` | Joining the VPN mesh (Headscale) |
| `cloud-users` | Nextcloud (files, calendars, contacts) |

## Deploy on Kubernetes

`kustomization.yaml` at the root is a Kustomize base built from the same `ory/` files that `compose.yml` mounts: Deployments for Kratos, Hydra and Keto (each runs its migration as an init container), Oathkeeper and the UI, the `hydra-clients` Job, Traefik routes (`auth-public` on the `web` entrypoint, `auth-admin` for `users.int` behind the mesh and Oathkeeper), and NetworkPolicies that keep the admin APIs inside the namespace (see Security). Service names match the compose stack, so the configs' internal URLs work unchanged.

The deploying side provides the namespace, the image tag and a Secret `auth` with `KRATOS_DSN`, `HYDRA_DSN`, `KETO_DSN`, `KRATOS_SECRETS_{COOKIE,DEFAULT,CIPHER,PAGINATION}`, `HYDRA_SECRETS_{SYSTEM,COOKIE,PAGINATION}`, `SMTP_CONNECTION_URI`, `SMTP_SENDER` and `OIDC_{SITE,HEADSCALE,FLUXWEB,GRAFANA}_CLIENT_SECRET`, plus a ConfigMap `internal-ca` (key `ca.crt`) with the CA of the Postgres server certificate, mounted at `/etc/internal-ca` so the DSNs can use `sslmode=verify-full&sslrootcert=/etc/internal-ca/ca.crt`. bulbashenko.com deploys it from [bulbashenko-com/infra](https://github.com/bulbashenko-com/infra), pinned to one commit of this repo; `.github/workflows/image.yml` builds `ghcr.io/bulbashenko-com/auth-ui:<commit>` once `test` passes on main and then opens the deploy PR `deploy/auth` in infra.
The deploying side provides the namespace, the image tag and a Secret `auth` with `KRATOS_DSN`, `HYDRA_DSN`, `KETO_DSN`, `KRATOS_SECRETS_{COOKIE,DEFAULT,CIPHER,PAGINATION}`, `HYDRA_SECRETS_{SYSTEM,COOKIE,PAGINATION}`, `SMTP_CONNECTION_URI`, `SMTP_SENDER` and `OIDC_{SITE,HEADSCALE,FLUXWEB,GRAFANA,NEXTCLOUD}_CLIENT_SECRET`, plus a ConfigMap `internal-ca` (key `ca.crt`) with the CA of the Postgres server certificate, mounted at `/etc/internal-ca` so the DSNs can use `sslmode=verify-full&sslrootcert=/etc/internal-ca/ca.crt`. bulbashenko.com deploys it from [bulbashenko-com/infra](https://github.com/bulbashenko-com/infra), pinned to one commit of this repo; `.github/workflows/image.yml` builds `ghcr.io/bulbashenko-com/auth-ui:<commit>` once `test` passes on main and then opens the deploy PR `deploy/auth` in infra.

## Deploy on Coolify

Expand All @@ -72,7 +73,7 @@ The deploying side provides the namespace, the image tag and a Secret `auth` wit
| `KRATOS_CIPHER_SECRET` | exactly 32 characters: `openssl rand -hex 16` |
| `SMTP_CONNECTION_URI` | `smtps://noreply%40example.com:<url-encoded password>@host.docker.internal:465/?server_name=mail.example.com` |
| `SMTP_SENDER` | `noreply@example.com` |
| `OIDC_SITE_CLIENT_SECRET`, `OIDC_HEADSCALE_CLIENT_SECRET`, `OIDC_FLUXWEB_CLIENT_SECRET`, `OIDC_GRAFANA_CLIENT_SECRET` | `scripts/new-client-secret.sh`; the app gets the same value |
| `OIDC_SITE_CLIENT_SECRET`, `OIDC_HEADSCALE_CLIENT_SECRET`, `OIDC_FLUXWEB_CLIENT_SECRET`, `OIDC_GRAFANA_CLIENT_SECRET`, `OIDC_NEXTCLOUD_CLIENT_SECRET` | `scripts/new-client-secret.sh`; the app gets the same value |

Optional: `AUTH_LOG_LEVEL` (`info`), `AUTH_RATE_LIMIT_PER_CLIENT` (10 per minute), `AUTH_RATE_LIMIT_TOTAL` (120 per minute).
For another domain, change the domains in `ory/*/*.yml`, `ory/hydra/clients/` and the defaults of `AUTH_HOST`, `AUTH_PUBLIC_URL` and `AUTH_ADMIN_HOST`.
Expand Down
1 change: 1 addition & 0 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ services:
OIDC_HEADSCALE_CLIENT_SECRET: ${OIDC_HEADSCALE_CLIENT_SECRET:?}
OIDC_FLUXWEB_CLIENT_SECRET: ${OIDC_FLUXWEB_CLIENT_SECRET:?}
OIDC_GRAFANA_CLIENT_SECRET: ${OIDC_GRAFANA_CLIENT_SECRET:?}
OIDC_NEXTCLOUD_CLIENT_SECRET: ${OIDC_NEXTCLOUD_CLIENT_SECRET:?}
volumes:
- ./ory/hydra/clients:/app/clients:ro
# Plain-text secrets of the confidential clients; Hydra stores only their hashes.
Expand Down
1 change: 1 addition & 0 deletions deploy/k8s/ui.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ spec:
- { name: OIDC_HEADSCALE_CLIENT_SECRET, valueFrom: { secretKeyRef: { name: auth, key: OIDC_HEADSCALE_CLIENT_SECRET } } }
- { name: OIDC_FLUXWEB_CLIENT_SECRET, valueFrom: { secretKeyRef: { name: auth, key: OIDC_FLUXWEB_CLIENT_SECRET } } }
- { name: OIDC_GRAFANA_CLIENT_SECRET, valueFrom: { secretKeyRef: { name: auth, key: OIDC_GRAFANA_CLIENT_SECRET } } }
- { name: OIDC_NEXTCLOUD_CLIENT_SECRET, valueFrom: { secretKeyRef: { name: auth, key: OIDC_NEXTCLOUD_CLIENT_SECRET } } }
resources:
requests: { cpu: 10m, memory: 48Mi }
securityContext:
Expand Down
1 change: 1 addition & 0 deletions e2e/test.env
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ OIDC_SITE_CLIENT_SECRET=test-site-secret
OIDC_HEADSCALE_CLIENT_SECRET=test-headscale-secret
OIDC_FLUXWEB_CLIENT_SECRET=test-fluxweb-secret
OIDC_GRAFANA_CLIENT_SECRET=test-grafana-secret
OIDC_NEXTCLOUD_CLIENT_SECRET=test-nextcloud-secret
# The suite signs in many times a minute from one machine; the rate-limit test checks the per-client limit.
AUTH_RATE_LIMIT_PER_CLIENT=60
AUTH_RATE_LIMIT_TOTAL=1000
1 change: 1 addition & 0 deletions kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ configMapGenerator:
- ory/hydra/clients/flux-web.json
- ory/hydra/clients/grafana.json
- ory/hydra/clients/headscale.json
- ory/hydra/clients/nextcloud.json
- ory/hydra/clients/stalwart-webui.json
- ory/hydra/clients/thunderbird.json
- name: keto-config
Expand Down
13 changes: 13 additions & 0 deletions ory/hydra/clients/nextcloud.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"client_id": "nextcloud",
"client_name": "Nextcloud (files, calendars, contacts)",
"client_secret": "${OIDC_NEXTCLOUD_CLIENT_SECRET}",
"token_endpoint_auth_method": "client_secret_post",
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"scope": "openid offline_access profile email groups",
"redirect_uris": ["https://cloud.bulbashenko.com/apps/user_oidc/code"],
"post_logout_redirect_uris": ["https://cloud.bulbashenko.com/"],
"skip_consent": true,
"metadata": { "required_group": "cloud-users" }
}
2 changes: 1 addition & 1 deletion ui/src/lib/groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import "server-only"
import { permissions, relationshipsRead, relationshipsWrite } from "./ory"

/** The groups that exist. Membership lives only in Keto: Group:<name>#members@User:<identity id>. */
export const GROUPS = ["infra-admins", "site-admins", "mail-users", "vpn-users"] as const
export const GROUPS = ["infra-admins", "site-admins", "mail-users", "vpn-users", "cloud-users"] as const
export type Group = (typeof GROUPS)[number]

export const isGroup = (value: string): value is Group => (GROUPS as readonly string[]).includes(value)
Expand Down