Files
certctl/deploy/helm/certctl/values.yaml
T
shankar0123 69a2b5c55a config: default hardening + operator docs (Phase 2 closure — SEC-H1, SEC-H3, SEC-M4, DEPL-H1, DEPL-M2 + doc-only carve-outs)
Eleven findings from the architecture diligence audit's Phase 2 bundle
closed in one PR. All touch the same backend config + Helm chart +
operator docs surface, so reviewing in one diff is the natural fit.

config.go: three new fail-closed Validate() branches behind sentinels
=====================================================================

Three new error sentinels exported from internal/config/config.go for
tests to pin via errors.Is + message-text:
  - ErrAgentBootstrapTokenRequired (SEC-H1)
  - ErrACMEInsecureWithoutAck      (SEC-M4)
  - ErrDemoModeAckExpired          (SEC-H3)

SEC-H1 (staged): introduces CERTCTL_AGENT_BOOTSTRAP_TOKEN_DENY_EMPTY
as an opt-in feature flag. When true AND the bootstrap token is empty,
Validate() returns ErrAgentBootstrapTokenRequired and the server
refuses to start. Default in THIS release: false (warn-mode
pass-through preserved). WORKSPACE-ROADMAP.md schedules the default
flip to true for v2.2.0 — operators get one upgrade window.

SEC-M4: upgrades the existing boot-time WARN log for
CERTCTL_ACME_INSECURE=true into a hard refuse-to-start gate behind
CERTCTL_ACME_INSECURE_ACK=true. The ACK env var must be paired with
the existing INSECURE flag; either alone fails closed. The boot-time
WARN log at cmd/server/main.go:611 continues to fire for the ACK'd
case so every restart logs the reminder.

SEC-H3: tightens the sticky DemoModeAck bit so it expires after 24h.
When DemoModeAck=true, Validate() now requires CERTCTL_DEMO_MODE_ACK_TS
to be set as a unix-epoch timestamp within the last 24h (24h-tolerance
on the past side, 1-minute clock-skew on the future side). Catches the
"forgotten demo deployment promoted to production" failure mode —
next container restart past 24h refuses unless re-ack'd.

Tests in internal/config/config_test.go cover every new branch:
positive (passes when properly set), negative (each fail-closed path
fires with the matching sentinel + message-text). 11 new tests added.

Helm chart + HA runbook (DEPL-H1)
=================================

Created docs/operator/runbooks/ha.md documenting the three values
flips required for production HA: server.replicas, podDisruptionBudget,
service.sessionAffinity. Cross-link comments added to
deploy/helm/certctl/values.yaml next to the server.replicas (line 19)
and podDisruptionBudget (line 566) defaults. DEFAULTS DO NOT CHANGE
— that's the point per the prompt's 'do not flip networkPolicy default'
guidance: a default-enabled PDB blocks fresh helm install on
single-node clusters.

CI guard (DEPL-M2)
==================

scripts/ci-guards/no-change-me-in-prod-compose.sh grep-fails any
'change-me-' literal in compose files OTHER than docker-compose.demo.yml.
Catches the placeholder-credential-leak regression one layer earlier
than the runtime Validate() fail-closed guards from Bundle 2 (2026-05-12).
Excludes comment lines so docs explaining the pattern don't trip the
guard. Verified to fire on a synthetic leak; clean on the current tree.

Consolidated 'Security carve-outs' doc section
==============================================

docs/operator/security.md grows by one new section documenting the
seven existing carve-outs in one canonical place:
  - SEC-M3: 3 InsecureSkipVerify=true sites (Agent dev, verify probe, tlsprobe)
  - SEC-M5: F5 connector InsecureSkipVerify per-config field
  - SEC-M4: ACME insecure + new ACK gate
  - SEC-L1: CSP 'unsafe-inline' on style-src (Tailwind carve-out)
  - SEC-L2: break-glass Argon2id rest-defense reminder
  - SEC-L3: 1 MB body-size cap + CERTCTL_MAX_BODY_SIZE override
  - DEPL-M2: change-me-* placeholder credentials in demo overlay
  - DEPL-M3: K8s NetworkPolicy operator-opt-in default

Each entry cites the file:line, the rationale for the carve-out, and
the operator action.

CHANGELOG + ENVIRONMENTS coverage
==================================

CHANGELOG.md grows by one new '### Breaking changes (scheduled for
v2.2.0)' section under Unreleased, documenting SEC-H1 / SEC-M4 / SEC-H3
with explicit upgrade-window guidance for each.

deploy/ENVIRONMENTS.md adds five rows: AGENT_BOOTSTRAP_TOKEN +
AGENT_BOOTSTRAP_TOKEN_DENY_EMPTY + DEMO_MODE_ACK + DEMO_MODE_ACK_TS +
ACME_INSECURE_ACK. G-3 env-docs-drift CI guard stays clean.

WORKSPACE-ROADMAP.md (cowork-side) schedules the SEC-H1 default-flip
for v2.2.0.

Sandbox limitation
==================

The certctl repo's working tree is 6.1 GB which fills the sandbox
volume; the go1.25.10 toolchain download (go.mod requires it,
sandbox has 1.25.9) keeps failing on disk-full. Local 'go build' /
'go test' were NOT run in this commit's verification path.
make verify MUST be run on the operator's workstation before push
per CLAUDE.md operating rules.

CI guards (no-change-me, G-3 env-docs-drift, doc-rot-detector, +
all existing) verified clean by running each individually.

Closes: cowork/certctl-architecture-diligence-audit.html#fix-SEC-H1,
        cowork/certctl-architecture-diligence-audit.html#fix-SEC-H3,
        cowork/certctl-architecture-diligence-audit.html#fix-SEC-M4,
        cowork/certctl-architecture-diligence-audit.html#fix-DEPL-H1,
        cowork/certctl-architecture-diligence-audit.html#fix-DEPL-M2,
        cowork/certctl-architecture-diligence-audit.html#fix-DEPL-M3,
        cowork/certctl-architecture-diligence-audit.html#fix-SEC-M3,
        cowork/certctl-architecture-diligence-audit.html#fix-SEC-M5,
        cowork/certctl-architecture-diligence-audit.html#fix-SEC-L1,
        cowork/certctl-architecture-diligence-audit.html#fix-SEC-L2,
        cowork/certctl-architecture-diligence-audit.html#fix-SEC-L3
2026-05-13 19:50:00 +00:00

673 lines
22 KiB
YAML

# Default values for certctl Helm chart
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# Namespace override (optional)
namespace: ""
# Global configuration
commonLabels: {}
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
# ==============================================================================
# Certctl Server Configuration
# ==============================================================================
server:
# Number of replicas (for HA deployments).
# Phase 2 DEPL-H1: production HA is operator-opt-in across this field
# + podDisruptionBudget.enabled + server.service.sessionAffinity.
# See docs/operator/runbooks/ha.md for the smallest-possible HA overlay.
replicas: 1
# Image configuration
image:
repository: ghcr.io/certctl-io/certctl
tag: "" # defaults to Chart.appVersion
pullPolicy: IfNotPresent
# Server port
port: 8443
# Resource requests and limits
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
# Pod security context
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
# Liveness and readiness probes (HTTPS-only as of v2.2).
#
# The two paths exposed for probes are `/health` and `/ready` —
# registered in internal/api/router/router.go:76-85 and bypassing the
# auth middleware via the no-auth list at cmd/server/main.go:920.
# Both serve the same JSON shape today (`{"status":"healthy"}` /
# `{"status":"ready"}`) but exist as separate routes so liveness and
# readiness can diverge in the future without renaming.
livenessProbe:
httpGet:
path: /health
port: https
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# U-2 (P1, cat-u-healthcheck_protocol_mismatch — adjacent fix): pre-U-2
# the readiness probe pointed at `/readyz`, the conventional kube-flavor
# name. The certctl server doesn't register `/readyz` (only `/health`
# and `/ready`) — see cmd/server/main.go:920 and
# internal/api/router/router.go:81. K8s readiness probes therefore
# received a 404 (or, with auth enabled, a 401 from the api-key middleware
# because `/readyz` was NOT in the no-auth bypass set), pods stayed
# `NotReady` indefinitely, and Helm rollouts stalled. Post-U-2 the path
# matches a registered route.
readinessProbe:
httpGet:
path: /ready
port: https
scheme: HTTPS
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
# TLS configuration — REQUIRED. HTTPS is the only supported mode (v2.2+).
# Operator must configure EXACTLY ONE of:
# (a) server.tls.existingSecret: <name> # pre-existing kubernetes.io/tls Secret
# (b) server.tls.certManager.enabled: true # provision a cert-manager Certificate CR
# Refusing to set either makes `helm template` fail with a diagnostic pointing at docs/tls.md.
tls:
# Name of a pre-existing Secret (type kubernetes.io/tls) holding tls.crt + tls.key (+ optional ca.crt).
# Leave empty to fall through to the cert-manager path.
existingSecret: ""
# Mount path for the TLS Secret inside the server + agent containers.
mountPath: /etc/certctl/tls
# cert-manager auto-provisioning. Opt-in (off by default per milestone §3.4).
certManager:
enabled: false
# Secret name the cert-manager Certificate CR writes into. Agents and the server
# both read from this Secret. If empty, defaults to "<fullname>-tls".
secretName: ""
# Cert-manager issuer reference.
issuerRef:
name: "" # e.g. "letsencrypt-prod" or "internal-ca"
kind: ClusterIssuer # ClusterIssuer or Issuer
group: cert-manager.io
# Subject fields on the issued cert.
commonName: "certctl-server"
dnsNames:
- certctl-server
- localhost
# Certificate lifetime + renewal window.
duration: 2160h # 90 days
renewBefore: 360h # 15 days
# Service type (ClusterIP, LoadBalancer, NodePort)
service:
type: ClusterIP
port: 8443
annotations: {}
# Authentication configuration.
# Valid types: "api-key" (production) or "none" (demo only — disables
# authentication on the API and logs a loud Warn at server startup).
# For JWT/OIDC, run an authenticating gateway in front of certctl
# (oauth2-proxy / Envoy ext_authz / Traefik ForwardAuth / Pomerium)
# and set type=none here so the gateway terminates federated identity.
# See docs/architecture.md "Authenticating-gateway pattern".
#
# G-1 (P1): pre-G-1 the chart accepted server.auth.type=jwt and the
# certctl-server container silently routed every request through the
# api-key bearer middleware — silent auth downgrade. Post-G-1 the
# chart's `certctl.validateAuthType` template helper rejects any value
# outside {api-key, none} at template time. See
# docs/upgrade-to-v2-jwt-removal.md if you previously set type=jwt.
auth:
type: api-key
apiKey: "" # REQUIRED when type=api-key (set via --set or values override).
# Logging configuration
logging:
level: info # debug, info, warn, error
format: json # json or text
# SMTP configuration for email notifications (optional)
smtp:
enabled: false
host: ""
port: 587
username: ""
password: ""
fromAddress: ""
useTLS: true
# Certificate digest digest (periodic email summary)
digest:
enabled: false
interval: "24h"
recipients: []
# Example:
# - admin@example.com
# - ops@example.com
# Enrollment over Secure Transport (EST) configuration
est:
enabled: false
issuerID: "iss-local"
profileID: ""
# Rate limiting configuration
rateLimiting:
rps: 100 # Requests per second
burst: 200 # Burst capacity
# Network scanning configuration
networkScan:
enabled: false
interval: "6h"
# Certificate key generation mode
keygen:
mode: agent # Options: agent (production), server (demo with warning)
# CORS configuration
cors:
origins: "" # Comma-separated list, empty means deny all cross-origin requests
# Issuer connectors configuration
issuer:
local:
enabled: true
# For sub-CA mode, provide these paths:
# caCertPath: /path/to/ca.crt
# caKeyPath: /path/to/ca.key
acme:
enabled: false
directoryURL: ""
email: ""
challengeType: "http-01" # Options: http-01, dns-01, dns-persist-01
# DNS configuration (for dns-01 or dns-persist-01)
# dnsPresentScript: /path/to/dns-present.sh
# dnsCleanupScript: /path/to/dns-cleanup.sh
# dnsPropagationWait: "30s"
# dnsPersistIssuerDomain: "validation.example.com"
# EAB configuration (for ZeroSSL, Google Trust Services, etc.)
# eabKid: ""
# eabHmac: ""
stepca:
enabled: false
# rootCAPath: /path/to/root_ca.crt
# intermediateCAPath: /path/to/intermediate_ca.crt
# provisionerName: ""
# provisionerPassword: ""
openssl:
enabled: false
# signScript: /path/to/sign.sh
# revokeScript: /path/to/revoke.sh
# crlScript: /path/to/crl.sh
# timeoutSeconds: 30
# Notifier connectors configuration
notifiers:
slack:
enabled: false
# webhookUrl: ""
# channel: ""
# username: ""
# iconEmoji: ""
teams:
enabled: false
# webhookUrl: ""
pagerduty:
enabled: false
# routingKey: ""
# severity: warning
opsgenie:
enabled: false
# apiKey: ""
# priority: P3
# Additional environment variables
# Will be passed as-is to the server container
env: {}
# Example:
# CERTCTL_SCHEDULER_RENEWAL_CHECK_INTERVAL: "1h"
# CERTCTL_DATABASE_MAX_CONNS: "25"
# Additional volume mounts for custom configurations
# volumeMounts: []
# - name: ca-cert
# mountPath: /etc/ssl/certs/ca.crt
# subPath: ca.crt
# Additional volumes
# volumes: []
# - name: ca-cert
# secret:
# secretName: ca-cert
# ==============================================================================
# External Database Configuration (Bundle 3 closure / D2 + OPS-L2)
# ==============================================================================
# When postgresql.enabled=false, the chart skips the bundled StatefulSet +
# Secret + Service and instead consumes the URL below verbatim as the
# server's CERTCTL_DATABASE_URL. The URL embeds username, password,
# host, port, database, and sslmode — operators are responsible for
# rotating credentials in this string out-of-band (Kubernetes Secret +
# helm upgrade is the supported pattern).
#
# Recommended sslmode for managed Postgres (RDS, Cloud SQL, Azure DB):
# verify-full — PCI-DSS Req 4 v4.0 §2.2.5 compliant; requires CA bundle.
# Mount the CA via server.volumes / server.volumeMounts and
# set sslrootcert=/path/in/pod/ca.crt in the URL.
#
# Example values overrides:
# postgresql.enabled: false
# externalDatabase.url: "postgres://certctl:HUNTER2@db.example.com:5432/certctl?sslmode=verify-full"
#
# Migration from the legacy `server.env.CERTCTL_DATABASE_URL` workaround:
# both still work (env block overrides the helper-emitted Secret value at
# pod-spec level), but the new path renders cleaner manifests with no
# stranded postgres-* templates.
externalDatabase:
# Connection string used when postgresql.enabled=false.
# Required in that mode — see certctl.requiredSecrets helper.
url: ""
# ==============================================================================
# PostgreSQL Configuration
# ==============================================================================
postgresql:
# Enable/disable PostgreSQL (set to false if using external database)
enabled: true
# Image configuration
image:
repository: postgres
tag: "16-alpine"
pullPolicy: IfNotPresent
# Authentication
auth:
database: certctl
username: certctl
# REQUIRED — set via `--set postgresql.auth.password=<value>` or values override.
#
# WARNING (U-1): rotating this value after first deploy does NOT change the
# database password. The `postgres:16-alpine` image runs `initdb` only when
# /var/lib/postgresql/data is empty, so POSTGRES_PASSWORD is written into
# pg_authid exactly once — on the first boot of the StatefulSet's PVC.
# Subsequent rollouts pick up the new env value in the postgres container
# but the certctl-server container's CERTCTL_DATABASE_URL also picks up
# the new value, while pg_authid still expects the old one — leading to
# `pq: password authentication failed for user "certctl"` (SQLSTATE 28P01).
#
# The certctl-server emits guidance via internal/repository/postgres/db.go::
# wrapPingError when it sees SQLSTATE 28P01 at startup. To resolve in a
# Helm deployment:
# - Non-destructive (preferred for environments with data):
# kubectl exec -it <release>-postgres-0 -- \
# psql -U certctl -c "ALTER ROLE certctl PASSWORD '<new>';"
# then update the secret/values to match and let the certctl-server
# pod restart against the matching credential.
# - Destructive (DESTROYS DATA — only acceptable on dev/demo PVCs):
# helm uninstall <release> && \
# kubectl delete pvc -l app.kubernetes.io/name=certctl,app.kubernetes.io/component=postgres && \
# helm install <release> ... # PVC re-creates empty, initdb seeds new password
password: ""
# ─────────────────────────────────────────────────────────────────────
# Bundle B / Audit M-018 (PCI-DSS Req 4 / CWE-319): TLS to Postgres
# ─────────────────────────────────────────────────────────────────────
# postgresql.tls.mode is wired into the database-url sslmode parameter
# (see templates/_helpers.tpl::certctl.databaseURL).
#
# Acceptable values (lib/pq):
# disable — no TLS (default, preserves in-cluster pod-to-pod
# traffic on the K8s pod network).
# require — TLS required, no certificate verification.
# verify-ca — TLS required + verify CA chain.
# verify-full — TLS required + verify CA chain + verify hostname.
#
# PCI-DSS Req 4 v4.0 §2.2.5 requires verify-ca or verify-full when the
# database carries sensitive data crossing untrusted networks (RDS,
# Cloud SQL, cross-VPC, etc). The bundled Helm Postgres runs in the
# same pod network as certctl-server; sslmode=disable is acceptable
# there only when the cluster CNI provides L2/L3 encryption (Cilium
# WireGuard, Calico Wireguard, Tailscale operator, etc).
#
# When mode != disable AND tls.caSecretRef is set, the CA bundle is
# mounted at /etc/postgresql-ca/ca.crt and the server's PGSSLROOTCERT
# env points there. caSecretRef must reference an existing Secret with
# a "ca.crt" key.
tls:
mode: disable
# caSecretRef: "" # Secret with ca.crt key (required for verify-ca/verify-full)
# Storage configuration
storage:
size: 10Gi
storageClass: "" # Uses default StorageClass if empty
# deleteOnTermination: false # Keep data on Helm uninstall
# Resource requests and limits
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
# Pod security context
securityContext:
runAsNonRoot: true
runAsUser: 999
runAsGroup: 999
fsGroup: 999
# Liveness and readiness probes
livenessProbe:
exec:
command:
- /bin/sh
- -c
- pg_isready -U certctl -d certctl
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- /bin/sh
- -c
- pg_isready -U certctl -d certctl
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
# Service configuration
service:
type: ClusterIP
port: 5432
# PostgreSQL-specific settings
postgresqlConfig: {}
# Example:
# max_connections: "200"
# shared_buffers: "256MB"
# ==============================================================================
# Certctl Agent Configuration
# ==============================================================================
agent:
# Enable/disable agent deployment
enabled: true
# Deployment strategy: DaemonSet (recommended) or Deployment
kind: DaemonSet # Options: DaemonSet, Deployment
# Image configuration
image:
repository: ghcr.io/certctl-io/certctl-agent
tag: "" # defaults to Chart.appVersion
pullPolicy: IfNotPresent
# Number of replicas (for Deployment kind; ignored for DaemonSet)
replicas: 1
# Resource requests and limits
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
# Pod security context
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
# Agent name (can be overridden per pod via StatefulSet ordinals)
name: "" # If empty, uses release name
# Key storage directory
keyDir: /var/lib/certctl/keys
# Certificate discovery directories (comma-separated)
discoveryDirs: ""
# Example: "/etc/ssl/certs,/etc/pki/tls"
# Node selector for agent pods (for DaemonSet)
nodeSelector: {}
# Example:
# node-role.kubernetes.io/worker: "true"
# Tolerations for agent pods
tolerations: []
# Example:
# - key: node-role
# operator: Equal
# value: worker
# effect: NoSchedule
# Affinity rules
affinity: {}
# Additional environment variables
env: {}
# ==============================================================================
# Ingress Configuration
# ==============================================================================
ingress:
enabled: false
className: ""
annotations: {}
# kubernetes.io/ingress.class: nginx
# Optional cert-manager integration for the public-facing Ingress cert.
# This is completely independent of server.tls.* — the Ingress terminates
# an *additional* TLS hop between the internet and the in-cluster Service.
# Leave disabled unless an Ingress is exposing certctl to the outside world.
certManager:
enabled: false
issuerRef:
name: "" # e.g. "letsencrypt-prod"
kind: ClusterIssuer # ClusterIssuer or Issuer
hosts:
- host: certctl.local
paths:
- path: /
pathType: Prefix
tls: []
# - secretName: certctl-tls
# hosts:
# - certctl.local
# ==============================================================================
# Service Account Configuration
# ==============================================================================
serviceAccount:
create: true
annotations: {}
name: "" # defaults to release name if empty
# ==============================================================================
# RBAC Configuration
# ==============================================================================
rbac:
create: true
# ==============================================================================
# Kubernetes Secrets Target Connector (PREVIEW — Bundle 3 closure / C3)
# ==============================================================================
# Bundle 3 audit closure (C3): the connector framework at
# internal/connector/target/k8ssecret/ ships the Config + interface +
# 14 unit tests, but the production K8s client at
# k8ssecret.go::realK8sClient is documented as "a stub placeholder for
# the real k8s.io/client-go implementation". The repo does not import
# k8s.io/client-go (verified via `grep -n "client-go" go.mod`), so the
# connector cannot deploy to a real cluster today.
#
# Setting kubernetesSecrets.enabled=true wires up the RBAC verbs the
# real client will need (get/create/update/patch/delete on Secrets)
# without making the connector functional — operators trying to use it
# get the stub's error and a pointer to this note.
#
# Status: PREVIEW. Production client lands when the cluster-management
# bundle ships (tracked in WORKSPACE-ROADMAP.md). Until then,
# in-cluster deploys use the file-based connectors (NGINX, Apache,
# HAProxy, etc.) via a Pod-mounted Secret + DaemonSet agent.
kubernetesSecrets:
enabled: false
# ==============================================================================
# Pod Disruption Budget (for HA deployments).
# Phase 2 DEPL-H1: defaults to enabled=false because a PDB template
# rendered at `replicas: 1` blocks every rolling restart on a
# single-node cluster. Production HA flips this to true alongside
# server.replicas ≥ 2. See docs/operator/runbooks/ha.md.
# ==============================================================================
podDisruptionBudget:
enabled: false
minAvailable: 1
# maxUnavailable: 1
# ==============================================================================
# Monitoring Configuration
# ==============================================================================
# Bundle 3 closure (D5): the ServiceMonitor template at
# templates/servicemonitor.yaml renders when both monitoring.enabled=true
# AND monitoring.serviceMonitor.enabled=true. The endpoint scrapes
# /api/v1/metrics/prometheus, which is rbac-gated on `metrics.read` —
# operators MUST provide a bearer token via
# monitoring.serviceMonitor.bearerTokenSecret pointing at a Secret with
# an API key holding that permission. Without the token, scrapes 401.
monitoring:
enabled: false
# Prometheus ServiceMonitor
serviceMonitor:
enabled: false
interval: 30s
scrapeTimeout: 10s
# Additional labels applied to the ServiceMonitor metadata.
# labels: {}
# Bearer-token Secret reference (required when the certctl server's
# /api/v1/metrics/prometheus endpoint is gated by api-key auth).
# Example:
# bearerTokenSecret:
# name: certctl-prometheus-key
# key: api-key
# bearerTokenSecret: {}
# TLS config for the scrape endpoint. The certctl server presents
# the same TLS cert the rest of the chart uses; insecureSkipVerify
# defaults to true so demos work out of the box. Production deploys
# should pin the CA via caFile or ca.secret.
# tlsConfig:
# caFile: /etc/prometheus/secrets/certctl-ca/ca.crt
# serverName: certctl-server
# tlsConfig: {}
# Optional relabeling for the scrape job.
# relabelings: []
# ==============================================================================
# Network Policy (Bundle 3 closure / D11)
# ==============================================================================
# Default off so existing deploys don't suddenly lose network reach.
# When enabled, restricts the server pod to:
# - Ingress: from in-namespace agent pods only.
# - Egress: kube-dns + bundled Postgres (if enabled).
# Operators add CA / OIDC / SMTP egress via extraEgress.
networkPolicy:
enabled: false
# Additional Ingress rules merged into the policy. Each entry is a
# raw networking.k8s.io/v1 NetworkPolicyIngressRule.
extraIngress: []
# Additional Egress rules merged into the policy. Common operator
# need: 443/TCP to an OIDC issuer, 443/TCP to a public CA endpoint,
# 25/TCP to an SMTP relay.
# Example:
# extraEgress:
# - to:
# - ipBlock:
# cidr: 0.0.0.0/0
# except:
# - 10.0.0.0/8
# ports:
# - protocol: TCP
# port: 443
extraEgress: []
# ==============================================================================
# Advanced Configuration
# ==============================================================================
# Node affinity for server pods
nodeAffinity: {}
# Pod affinity for server pods
podAffinity: {}
# Pod anti-affinity for server pods (for HA)
podAntiAffinity: {}
# Example:
# podAntiAffinity:
# preferredDuringSchedulingIgnoredDuringExecution:
# - weight: 100
# podAffinityTerm:
# labelSelector:
# matchExpressions:
# - key: app.kubernetes.io/name
# operator: In
# values:
# - certctl
# topologyKey: kubernetes.io/hostname
# Custom labels for all resources
customLabels: {}
# Custom annotations for all resources
customAnnotations: {}