Public Access
- Updated Chart.yaml to version 0.2.0 and added annotations for changes. - Modified release-chart.yaml to trigger releases via Gitea and handle pre-releases. - Introduced ServiceAccount configuration in values.yaml and related templates. - Adjusted internal container ports to prevent conflicts between nginx and aptly. - Updated README.md and NOTES.txt to reflect new configurations and usage instructions.
344 lines
12 KiB
YAML
344 lines
12 KiB
YAML
nameOverride: ""
|
|
fullnameOverride: ""
|
|
|
|
# -- Container image for the aptly server itself (also used for the
|
|
# initContainer and the reconcile Job — all three run the same image).
|
|
image:
|
|
repository: git.morlana.online/f.weber/aptly
|
|
tag: "" # "" -> .Chart.AppVersion, i.e. the last released image. Never "latest".
|
|
pullPolicy: IfNotPresent
|
|
pullSecrets: []
|
|
|
|
# -- The read/auth sidecar. A plain upstream image — this chart owns none of
|
|
# its code, only its rendered config (see `security` below).
|
|
nginx:
|
|
image:
|
|
repository: nginxinc/nginx-unprivileged
|
|
tag: "1-alpine"
|
|
pullPolicy: IfNotPresent
|
|
resources: {}
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
capabilities: { drop: [ALL] }
|
|
|
|
# =============================================================================
|
|
# aptly configuration. Two layers, always merged in this order:
|
|
# 1. the curated keys below (omitted from the rendered config when unset,
|
|
# so a default install matches aptly's own upstream defaults exactly)
|
|
# 2. aptly.configOverrides — raw aptly YAML, deep-merged last, always wins.
|
|
# Every current and future aptly config key is reachable here without a
|
|
# chart change. See rootfs/usr/local/bin/aptly-init and
|
|
# https://github.com/aptly-dev/aptly/blob/master/utils/config.go for the
|
|
# full field list (snake_case yaml tags).
|
|
# =============================================================================
|
|
aptly:
|
|
architectures: []
|
|
logLevel: info
|
|
logFormat: json
|
|
download:
|
|
concurrency: 4
|
|
limit: 0
|
|
retries: 0
|
|
sourcePackages: false
|
|
publishing:
|
|
skipContents: false
|
|
skipBz2: false
|
|
|
|
metrics:
|
|
enabled: false
|
|
swagger:
|
|
enabled: false
|
|
|
|
gpg:
|
|
# false -> gpg_disable_sign: true AND Signing.Skip: true on every publish
|
|
# call the reconcile Job makes (both are required — aptly's publish API
|
|
# does not consult gpg_disable_sign on its own, see docs/security.md).
|
|
enabled: true
|
|
verify: true
|
|
# gpg (default): the real gnupg binary, in the image already — handles
|
|
# armored keys, subkeys and passphrases the way upstream aptly expects.
|
|
# internal: pure-Go openpgp, no gnupg binary needed, smaller attack
|
|
# surface — verify your key type works with it before switching.
|
|
provider: gpg
|
|
signingKey:
|
|
# Secret with key "privateKey" (armored .asc) or "secretKeyring"
|
|
# (binary secring.gpg), optionally "passphrase". Never put a real key
|
|
# inline in values.yaml — this is the production path.
|
|
existingSecret: ""
|
|
# Discouraged escape hatch for quick tests only.
|
|
privateKey: ""
|
|
passphrase: ""
|
|
publishPublicKey:
|
|
enabled: true
|
|
path: /signing-key.asc
|
|
|
|
# Trusted keys imported into GNUPGHOME on every start, for mirror
|
|
# signature verification. The keyring is therefore a pure function of
|
|
# values.yaml — restart the pod to pick up an edit here.
|
|
# Inline ASCII-armored public keys only (Helm has no network access at
|
|
# render time to support a `url:`/`keyserver:` form the way a plain script
|
|
# could — fetch the key yourself once and paste it here).
|
|
gpgKeys: []
|
|
# - name: debian-archive
|
|
# armored: |
|
|
# -----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
# ...
|
|
|
|
# Declarative desired state, reconciled by the post-install/post-upgrade
|
|
# Job against the REST API (never the CLI — see reconcile.mode below and
|
|
# rootfs/usr/local/bin/aptly-reconcile for the exact field reference and
|
|
# the documented limitation on editing mirrors[].components after creation).
|
|
localRepos: []
|
|
# - name: stable
|
|
# comment: "Production package repository"
|
|
# defaultDistribution: stable
|
|
# defaultComponent: main
|
|
|
|
mirrors: []
|
|
# - name: debian-security
|
|
# archiveURL: http://security.debian.org/debian-security
|
|
# distribution: trixie-security
|
|
# components: [main]
|
|
# architectures: [amd64, arm64]
|
|
|
|
publish: []
|
|
# - name: stable-root
|
|
# prefix: "" # "" = repo root
|
|
# distribution: stable
|
|
# sourceKind: local # local | snapshot
|
|
# sources: [{ name: stable, component: main }]
|
|
# architectures: [amd64, arm64]
|
|
# acquireByHash: true
|
|
|
|
# Raw passthrough, deep-merged over the generated config last. See header.
|
|
configOverrides: {}
|
|
|
|
# Existing Secrets to envFrom into the aptly container, so configOverrides
|
|
# can reference ${VAR} placeholders (e.g. S3 credentials) that resolve from
|
|
# Secrets you already manage, without ever putting them in values.yaml.
|
|
existingSecretEnv: []
|
|
|
|
# =============================================================================
|
|
# Security matrix — one preset switch, escape hatches for every axis. See
|
|
# docs/security.md for the full decision table.
|
|
# =============================================================================
|
|
security:
|
|
# open: read+write, no auth, no exceptions — the explicit "unabgesichert"
|
|
# mode. publicRead (default): read is open, write needs Basic Auth.
|
|
# authenticated: both need Basic Auth. readOnly: write returns 404.
|
|
preset: publicRead
|
|
auth:
|
|
# name: plaintext password. Hashed into htpasswd by the initContainer at
|
|
# pod start (never a bcrypt/apr1 hash here — see rootfs/.../aptly-init
|
|
# for why: a template-side hash would change, hence restart-loop, on
|
|
# every single helm upgrade).
|
|
users: {}
|
|
# Secret key "htpasswd" (pre-hashed) — the recommended production path,
|
|
# e.g. via ExternalSecrets/SealedSecrets. Wins over `users` when set.
|
|
existingSecret: ""
|
|
internalUser:
|
|
# Always appended to htpasswd: the reconcile Job talks to nginx (not
|
|
# directly to aptly, which is loopback-only), so it needs credentials
|
|
# in every preset, including existingSecret + authenticated.
|
|
enabled: true
|
|
username: aptly-internal
|
|
# CIDRs matched against $remote_addr. Behind an Ingress controller that is
|
|
# the CONTROLLER's pod IP, not the real client — set trustedProxies to the
|
|
# controller's CIDR (via X-Forwarded-For) or use networkPolicy instead. The
|
|
# chart renders a warning comment into nginx.conf when allowCIDRs is set
|
|
# without trustedProxies.
|
|
trustedProxies: []
|
|
read:
|
|
enabled: true
|
|
requireAuth: null # null = take the preset's value; true/false overrides it
|
|
allowCIDRs: []
|
|
write:
|
|
enabled: true
|
|
requireAuth: null
|
|
allowCIDRs: []
|
|
# true: do not render the API Ingress at all (regardless of ingress.api.*)
|
|
# and rely on networkPolicy for isolation — an honest implementation, not
|
|
# an nginx trick.
|
|
inClusterOnly: false
|
|
|
|
# proxy.enabled=false hands aptly's unauthenticated write API directly to
|
|
# whatever can reach the Service — the chart refuses to render an Ingress in
|
|
# that combination unless security.preset is explicitly "open" (see
|
|
# templates/NOTES.txt / the `fail` guard in templates/_helpers.tpl).
|
|
proxy:
|
|
enabled: true
|
|
# nginx additionally serves the same tree under /repos/<name>/, matching
|
|
# aptly's own serve_in_api_mode URL shape, so toggling this flag never
|
|
# breaks an already-deployed sources.list.
|
|
compatPaths: true
|
|
maxUploadSize: "0" # nginx client_max_body_size; "0" = unlimited
|
|
readTimeout: "3600s"
|
|
publishEndpointName: public
|
|
|
|
# Container ports inside the pod. aptly and nginx are two containers sharing
|
|
# one pod network namespace — they MUST NOT use the same port (nginx would
|
|
# fail to start with "address already in use"). These are internal-only;
|
|
# external access is still controlled by service.port / metrics.service.port,
|
|
# which stay decoupled from these via named ports (targetPort: http/metrics).
|
|
ports:
|
|
aptly: 8080 # aptly's own listener (loopback-only, or 0.0.0.0 when proxy.enabled=false)
|
|
nginx: 8081 # nginx's main (repo + API) listener
|
|
metrics: 9090 # nginx's /api/metrics passthrough listener, when metrics.service.enabled
|
|
|
|
persistence:
|
|
enabled: true
|
|
existingClaim: "" # set this in production — see docs/operations.md
|
|
storageClass: ""
|
|
accessMode: ReadWriteOnce
|
|
size: 20Gi
|
|
annotations: {}
|
|
|
|
serviceAccount:
|
|
# Own ServiceAccount per release, so RBAC (if you grant any) is scoped to
|
|
# this instance rather than the namespace's shared "default" identity.
|
|
create: true
|
|
# "" -> aptly.fullname (this release's name) when create=true. When
|
|
# create=false, set this to bind to a ServiceAccount you already manage;
|
|
# leave "" to fall back to the namespace's "default" ServiceAccount.
|
|
name: ""
|
|
annotations: {}
|
|
automountServiceAccountToken: true
|
|
|
|
workload:
|
|
updateStrategy:
|
|
type: RollingUpdate # safe here: a StatefulSet with replicas=1 always
|
|
# terminates the old pod before creating the new one
|
|
podManagementPolicy: OrderedReady
|
|
revisionHistoryLimit: 3
|
|
terminationGracePeriodSeconds: 60
|
|
annotations: {}
|
|
podAnnotations: {}
|
|
podLabels: {}
|
|
|
|
podSecurityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 10001
|
|
runAsGroup: 10001
|
|
fsGroup: 10001
|
|
fsGroupChangePolicy: OnRootMismatch
|
|
seccompProfile: { type: RuntimeDefault }
|
|
|
|
containerSecurityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
capabilities: { drop: [ALL] }
|
|
|
|
resources: {}
|
|
|
|
probes:
|
|
startup: { periodSeconds: 5, failureThreshold: 60 }
|
|
readiness: { periodSeconds: 10, timeoutSeconds: 3, failureThreshold: 3 }
|
|
liveness: { periodSeconds: 30, timeoutSeconds: 5, failureThreshold: 6 }
|
|
|
|
service:
|
|
type: ClusterIP
|
|
port: 8080
|
|
annotations: {}
|
|
|
|
ingress:
|
|
enabled: false
|
|
mode: single # single | split — see docs/security.md
|
|
className: ""
|
|
annotations:
|
|
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
|
repo:
|
|
host: ""
|
|
path: /
|
|
pathType: Prefix
|
|
tls: []
|
|
# - hosts: [apt.example.com]
|
|
# secretName: apt-tls
|
|
api:
|
|
enabled: false
|
|
host: ""
|
|
className: ""
|
|
annotations: {}
|
|
tls: []
|
|
|
|
# Gateway API HTTPRoute support — fully independent of `ingress.*` above, and
|
|
# safe to enable at the same time as it (e.g. mid-migration between the two:
|
|
# both can point at the same Service simultaneously, see docs/security.md).
|
|
# This chart never creates a Gateway itself, only HTTPRoutes attaching to one
|
|
# your cluster admin already manages — TLS is that Gateway listener's job, not
|
|
# something set here.
|
|
gateway:
|
|
enabled: false
|
|
# Core Gateway API resources are apiVersion gateway.networking.k8s.io/v1 (GA
|
|
# since v1.0) — override only if your cluster's CRDs are still pre-GA.
|
|
apiVersion: gateway.networking.k8s.io/v1
|
|
mode: single # single | split — same meaning as ingress.mode, see docs/security.md
|
|
# Referenced Gateway(s). Required when gateway.enabled is true.
|
|
parentRefs: []
|
|
# - name: my-gateway
|
|
# namespace: gateway-infra # optional, defaults to this release's namespace
|
|
# sectionName: https # optional, binds to one named listener
|
|
repo:
|
|
hostnames: [] # e.g. [apt.example.com] — omit to match the Gateway listener's own hostname(s)
|
|
path: /
|
|
pathType: PathPrefix # PathPrefix | Exact | RegularExpression — Gateway API's own enum, distinct from ingress.repo.pathType's
|
|
api:
|
|
enabled: false
|
|
hostnames: []
|
|
parentRefs: [] # override for the API route only — falls back to gateway.parentRefs when empty
|
|
|
|
metrics:
|
|
service:
|
|
enabled: false
|
|
port: 9090
|
|
annotations: {}
|
|
serviceMonitor:
|
|
enabled: false
|
|
interval: 30s
|
|
labels: {}
|
|
relabelings: []
|
|
|
|
reconcile:
|
|
enabled: true
|
|
# hook (default): post-install,post-upgrade Helm hook Job.
|
|
# job: a plain Job named with a hash of the desired state, for GitOps
|
|
# controllers (ArgoCD/Flux) that dislike Helm hooks.
|
|
# manual: render the state ConfigMap only.
|
|
mode: hook
|
|
failOnError: false
|
|
timeoutSeconds: 600
|
|
image: {} # override repository/tag/pullPolicy; defaults to the main `image`
|
|
resources: {}
|
|
|
|
podDisruptionBudget:
|
|
enabled: false
|
|
maxUnavailable: 1
|
|
|
|
networkPolicy:
|
|
enabled: false
|
|
allowedNamespaces: []
|
|
extraIngress: []
|
|
egress:
|
|
# A default-deny egress policy silently breaks every mirror — this stays
|
|
# true until you have a specific reason to lock it down.
|
|
allowAll: true
|
|
extra: []
|
|
|
|
extraEnv: []
|
|
extraEnvFrom: []
|
|
extraVolumes: []
|
|
extraVolumeMounts: []
|
|
extraInitContainers: []
|
|
extraContainers: []
|
|
nodeSelector: {}
|
|
tolerations: []
|
|
affinity: {}
|
|
topologySpreadConstraints: []
|
|
priorityClassName: ""
|
|
|
|
global:
|
|
imageRegistry: ""
|
|
imagePullSecrets: []
|
|
defaultStorageClass: ""
|