portal

May 16, 2026 · View on GitHub

Version: 0.1.0 Type: application AppVersion: 0.1.0

Portal — an admission webhook, informer-driven audit loop, and declarative NetworkPolicy analyser, with a built-in response-action engine. Successor to podwatcher-poc; AlertManager-compatible, PolicyReport-native, expr-lang rules.

Homepage: https://github.com/vilaca/portal

Maintainers

NameEmailUrl
Joao Vilacajoao.vilaca@relexsolutions.com

Source Code

Requirements

Kubernetes: >=1.27.0-0

Values

KeyTypeDefaultDescription
affinityobject{}Affinity rules applied to Portal pods. The chart adds a preferred pod anti-affinity by default — overridden when this value is non-empty.
alertmanager.urlstring""AlertManager v2 alerts endpoint. Empty disables the AlertManager sink.
audit.enabledboolfalse
audit.leaderElectionbooltrueEnable lease-based leader election. Informers run on every replica; only the leader dispatches actions / writes PolicyReports.
audit.resyncPeriodstring"10m"Informer resync period. Watch events are the main path; resync is a safety net only.
certManager.enabledboolfalseUse cert-manager to provision the webhook TLS Secret. When false the binary bootstraps a self-signed CA on startup and patches the ValidatingWebhookConfiguration.caBundle itself.
certManager.issuerKindstring""Issuer kind to use when certManager.enabled. When empty an in-chart self-signed Issuer is created.
certManager.issuerNamestring""Issuer name to use when certManager.enabled. When empty an in-chart self-signed Issuer is created.
extraEnvlist[]Extra environment variables for the Portal container.
extraVolumeMountslist[]Extra volume mounts on the Portal container.
extraVolumeslist[]Extra volumes mounted in the Portal pod.
global.failClosedbooltrueWhether the ValidatingWebhookConfiguration uses failurePolicy=Fail. When true, API server requests are rejected if Portal is unavailable — ≥2 replicas + PDB become mandatory. System namespaces are always excluded regardless of this flag (see templates/validatingwebhookconfiguration.yaml).
global.modestring"combined"Deployment topology. "combined" runs every enabled layer in one Deployment. "split" deploys one Deployment per layer (admission / audit / network) for independent scaling. v1 ships combined only; the split-mode templates are stubbed for forward compat.
image.pullPolicystring"IfNotPresent"Container image pull policy.
image.pullSecretslist[]Image pull secrets to attach to the ServiceAccount.
image.repositorystring"ghcr.io/vilaca/portal"Container image repository.
image.tagstring""Container image tag. Defaults to the chart appVersion when empty.
metrics.portint9090Container port the Prometheus /metrics + /healthz + /readyz listener serves on.
network.enabledboolfalse
nodeSelectorobject{}Node selector applied to Portal pods.
podDisruptionBudget.minAvailableint1Minimum available replicas during voluntary disruption. ≥1 is required when failClosed=true. Set to 0 to disable the PDB entirely.
podSecurityContext.fsGroupint65532Pod-level fsGroup. 65532 is the distroless nonroot group.
podSecurityContext.runAsNonRootbooltrueReject pods whose container security context allows root.
podSecurityContext.seccompProfile.typestring"RuntimeDefault"Seccomp profile applied at pod level.
policyReport.enabledbooltrueEmit wgpolicyk8s.io/v1alpha2 PolicyReport / ClusterPolicyReport CRs.
rbac.actions.annotateboolfalseGrant patch on workload kinds so the annotate action can mutate metadata.annotations via server-side apply.
rbac.actions.evictboolfalseGrant create on pods/eviction so the evict action can drain pods.
rbac.actions.labelboolfalseGrant patch on workload kinds so the label action can mutate metadata.labels via server-side apply.
rbac.actions.patchnpboolfalseGrant patch on networkpolicies.networking.k8s.io for the patch-NP action.
rbac.actions.revoketokenboolfalseGrant delete on secrets so the revoke-sa-token action can force ServiceAccount token rotation.
rbac.createbooltrueCreate the ClusterRole + ClusterRoleBinding.
replicaCountint2Number of Portal replicas. 2 is the minimum for fail-closed HA; the PodDisruptionBudget keeps ≥1 healthy during rollouts so workload-namespace admission requests continue to succeed.
resources.limits.cpustring"500m"CPU limit per Portal pod.
resources.limits.memorystring"256Mi"Memory limit per Portal pod.
resources.requests.cpustring"100m"CPU request per Portal pod.
resources.requests.memorystring"128Mi"Memory request per Portal pod.
rules.crbooltrue
rules.folderConfigMapstring""Name of an existing ConfigMap holding rule YAML files. Mounted at /etc/portal/rules and passed via --rules-folder. Empty disables folder loading.
securityContext.allowPrivilegeEscalationboolfalseDisallow privilege escalation.
securityContext.capabilities.droplist["ALL"]Drop all Linux capabilities; Portal needs none.
securityContext.readOnlyRootFilesystembooltrueMount the root filesystem read-only.
securityContext.runAsGroupint65532Run as the distroless nonroot group.
securityContext.runAsNonRootbooltrueEnforce non-root execution at container level.
securityContext.runAsUserint65532Run as the distroless nonroot user.
serviceAccount.annotationsobject{}Extra annotations on the ServiceAccount (useful for IRSA / Workload Identity).
serviceAccount.createbooltrueCreate a ServiceAccount for Portal. Set to false to reuse an existing one.
serviceAccount.namestring""Name of the ServiceAccount. Defaults to portal.fullname.
serviceMonitor.enabledboolfalseCreate a Prometheus Operator ServiceMonitor.
serviceMonitor.intervalstring"30s"Scrape interval.
serviceMonitor.labelsobject{}Extra labels added to the ServiceMonitor (typically the Prometheus release label for kube-prometheus-stack).
tolerationslist[]Tolerations applied to Portal pods.
watchedGvkslist[]Additional GVKs to start informers for, in "group/version/Kind" form. Empty group renders as "/v1/ConfigMap" etc. These extend the set computed from the audited rule corpus.
webhook.caBundlestring""Optional pre-baked caBundle (base64). When empty, Portal patches the ValidatingWebhookConfiguration at startup with its self-signed CA, or cert-manager populates it via the Certificate's caBundle injection.
webhook.enabledbooltrue
webhook.portint8443Container port the webhook TLS server listens on.
webhook.ruleslist[{"apiGroups":[""],"apiVersions":["v1"],"operations":["CREATE","UPDATE"],"resources":["pods"]},{"apiGroups":["apps"],"apiVersions":["v1"],"operations":["CREATE","UPDATE"],"resources":["deployments","statefulsets","daemonsets","replicasets"]},{"apiGroups":["batch"],"apiVersions":["v1"],"operations":["CREATE","UPDATE"],"resources":["jobs","cronjobs"]},{"apiGroups":["networking.k8s.io"],"apiVersions":["v1"],"operations":["CREATE","UPDATE"],"resources":["networkpolicies"]}]GVKs subject to admission. Each entry is {apiGroups, apiVersions, resources}. The system-namespace exclusion is layered on top of this via namespaceSelector.
webhook.timeoutSecondsint5Webhook timeoutSeconds in the ValidatingWebhookConfiguration.