Files
aptly-containerized/charts/aptly/values.yaml
T
f.weber 1675ea9a4e
CI / lint (push) Failing after 2s
CI / smoke-test (push) Failing after 9s
Release chart / release (release) Successful in 12s
Enhance Helm chart with ServiceAccount support and configurable ports
- 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.
2026-08-13 12:12:30 +02:00

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: ""