Add Security

2026-08-12 09:47:32 +00:00
committed by Gitea
parent 0c28d572af
commit db68d6f1d5
+86
@@ -0,0 +1,86 @@
# Security modes
aptly itself has **no** authentication — upstream explicitly warns against putting
the REST API directly on the internet. This repo solves that with an nginx sidecar
(Compose: its own container; Helm: a second container in the same pod, `aptly` only
listens on `127.0.0.1`).
## The four presets
| `security.preset` | Read (apt clients) | Read auth | Write (`/api/`) | Write auth |
|---|---|---|---|---|
| `open` | on | **no** | on | **no** |
| `publicRead` (**default**) | on | no | on | yes |
| `authenticated` | on | yes | on | yes |
| `readOnly` | on | no | **off (404)** | — |
`open` is the "completely unsecured" option you asked for — **one line**, no
confirmation gate:
```yaml
security:
preset: open
```
Health probes (`/api/ready`, `/api/healthy`) are reachable without credentials in
**every** mode — otherwise Kubernetes/Compose could never recognize the instance as
healthy.
## Every cell individually reachable
`security.read.*` and `security.write.*` explicitly override the preset:
```yaml
security:
preset: authenticated
read:
requireAuth: false # = publicRead, just spelled out explicitly
```
## The Ingress split (Helm) — what it actually does
```yaml
ingress:
mode: split
api:
enabled: true
host: aptly-api.example.com
```
This creates two `Ingress` objects (different host, different
annotations/TLS/ingressClass possible) — **but both point at the same Service**.
nginx itself does not check which host a request arrived on; `/api/` is reachable
through **both** hosts, as long as `security.write.enabled` allows it. The split is
therefore a pure Ingress/DNS feature (e.g. a separate certificate or a WAF only on
the API host), not a hard network separation. For real isolation:
`security.write.inClusterOnly: true` (then renders no API Ingress at all — an honest
implementation, not an nginx trick) or a `networkPolicy`.
## The CIDR pitfall
```yaml
security:
write:
allowCIDRs: ["10.42.0.0/16"]
```
Behind an Ingress controller, `$remote_addr` in nginx is the **controller's pod IP**,
not the real client — `allowCIDRs` without `trustedProxies` then matches practically
everyone. Set `security.trustedProxies` to your Ingress controller's CIDR (enables
`X-Forwarded-For` evaluation), or use a `networkPolicy` for real L3 restriction. If
`trustedProxies` is missing while `allowCIDRs` is set, the chart renders a
`# WARNING` line directly into the nginx config.
## Unsigned
```yaml
aptly:
gpg:
enabled: false
```
Sets `gpg_disable_sign: true` in the aptly config **and** `Signing.Skip: true` in
every publish call the reconcile job makes — both are needed; aptly's publish API
takes its own signing parameter per call and ignores the global config flag
(empirically verified). The client then needs `[trusted=yes]` instead of
`signed-by=`.